Archive defaults: HYPEUSDC · 15m decisions · 15m execution. Uses the current chart symbol and timeframe.
Regenerated from the installed original archive. TradingView verification on 46,892 identical original candles, including seed history, matched trade decisions and quantities, with equity within 0.0000001. The Archive rules table and native fill markers use loaded chart candles with the archive calculation and account rules. Use the archived execution timeframe and the same candle history from the same origin to compare results. Changed charts or inputs are fresh exploratory runs. Optional Strategy Tester orders approximate sizing and percentage slippage; broker settings are separate from the Archive account inputs.
strategy("VESTROS C05793: original archive rules", overlay = true, initial_capital = 10000, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, commission_value = 0.08, slippage = 0, pyramiding = 100, margin_long = 0, margin_short = 0, process_orders_on_close = false, calc_on_every_tick = false, calc_on_order_fills = false, max_bars_back = 5000)f_gt(float a, float b) => math.sign(a - b) == 1f_lt(float a, float b) => math.sign(a - b) == -1f_eq(float a, float b) => math.sign(a - b) == 0f_ge(float a, float b) => not na(a) and not na(b) and math.sign(a - b) >= 0f_le(float a, float b) => not na(a) and not na(b) and math.sign(a - b) <= 0f_number(bool value) => value ? 1.0 : 0.0type Samples array<float> valuesf_samples() => Samples.new(array.new<float>())method add(Samples self, float value, int capacity = 82) => self.values.push(value) if self.values.size() > capacity self.values.shift()method lag(Samples self, int offset = 0) => self.values.size() > offset ? self.values.get(self.values.size() - 1 - offset) : namethod stats(Samples self, int length, int offset = 0) => float average = na float deviation = na if self.values.size() >= length + offset float total = 0 for i = length - 1 to 0 total += self.lag(i + offset) average := total / length float squares = 0 for i = length - 1 to 0 float delta = self.lag(i + offset) - average squares += delta * delta deviation := math.sqrt(squares / length) [average, deviation]method zscore(Samples self, int length) => [average, deviation] = self.stats(length) (self.lag() - average) / deviationmethod volatility(Samples self, int length, int offset = 1) => [average, deviation] = self.stats(length, offset) deviationmethod rangePosition(Samples self, int length) => float minimum = self.lag(1) float maximum = self.lag(1) for i = 2 to length minimum := math.min(minimum, self.lag(i)) maximum := math.max(maximum, self.lag(i)) 2 * (self.lag() - minimum) / (maximum - minimum) - 1method rank(Samples self, int length) => float current = self.lag() bool complete = not na(current) int less = 0 int equal = 0 for i = 1 to length float prior = self.lag(i) complete := complete and not na(prior) less += f_lt(prior, current) ? 1 : 0 equal += f_eq(prior, current) ? 1 : 0 complete ? 2.0 * (less + equal / 2.0) / length - 1 : namethod persistence(Samples self, int length, float threshold) => bool complete = true bool passed = true for i = 0 to length - 1 float value = self.lag(i) complete := complete and not na(value) passed := passed and (threshold >= 0 ? f_gt(value, threshold) : f_lt(value, threshold)) complete ? f_number(passed) : naf_relative(Samples left, Samples right, int length) => (left.lag() - left.lag(length)) / math.abs(left.lag(length)) - (right.lag() - right.lag(length)) / math.abs(right.lag(length))f_cross(Samples left, Samples right, bool above) => bool complete = not na(left.lag()) and not na(right.lag()) and not na(left.lag(1)) and not na(right.lag(1)) complete ? f_number(above ? f_gt(left.lag(), right.lag()) and f_le(left.lag(1), right.lag(1)) : f_lt(left.lag(), right.lag()) and f_ge(left.lag(1), right.lag(1))) : naf_compare(float left, float right, string comparison) => not na(left) and not na(right) ? f_number(comparison == "gt" ? f_gt(left, right) : comparison == "lt" ? f_lt(left, right) : comparison == "ge" ? f_ge(left, right) : f_le(left, right)) : naf_votes(array<float> values, int required) => int passed = 0 int unknown = 0 for value in values passed += value == 1 ? 1 : 0 unknown += na(value) ? 1 : 0 passed >= required ? 1.0 : passed + unknown < required ? 0.0 : namethod riskScale(Samples self) => Samples returns = f_samples() bool positive = true for i = 80 to 1 float previous = self.lag(i) float current = self.lag(i - 1) positive := positive and f_gt(previous, 0) and f_gt(current, 0) returns.add(current / previous - 1) [slowMean, slow] = returns.stats(60, 20) [fastMean, fast] = returns.stats(20) positive and f_gt(slow, 0) and f_gt(fast, 0) ? math.min(1, math.max(0.25, slow / fast)) : naf_histories(int count) => array<Samples> result = array.new<Samples>() for i = 1 to count result.push(f_samples()) resulttype RsiState int length int leftBars int rightBars float lastClose = na float gain = na float loss = na float gainSum = 0 float lossSum = 0 int seedCount = 0 Samples oscillators Samples highs Samples lows float oscillator = na float latestLowOscillator = na float latestLowPrice = na float latestHighOscillator = na float latestHighPrice = na float previousLowPivotOscillator = na float previousLowPivotPrice = na float previousHighPivotOscillator = na float previousHighPivotPrice = na bool precedingLowFound = false int lowPivotBarsSincePrevious = naf_rsi(int length, int leftBars, int rightBars) => RsiState.new(length, leftBars, rightBars, oscillators = f_samples(), highs = f_samples(), lows = f_samples())method calculate(RsiState self, float highPrice, float lowPrice, float closePrice) => if not na(self.lastClose) float change = closePrice - self.lastClose float gain = math.max(change, 0) float loss = math.max(-change, 0) if na(self.gain) self.gainSum += gain self.lossSum += loss self.seedCount += 1 if self.seedCount == self.length self.gain := self.gainSum / self.length self.loss := self.lossSum / self.length else float alpha = 1.0 / self.length self.gain := alpha * gain + (1 - alpha) * self.gain self.loss := alpha * loss + (1 - alpha) * self.loss self.oscillator := na(self.gain) or na(self.loss) ? na : f_eq(self.loss, 0) ? (f_eq(self.gain, 0) ? na : 100) : f_eq(self.gain, 0) ? 0 : 100 - 100 / (1 + self.gain / self.loss) self.lastClose := closePrice int width = self.leftBars + self.rightBars + 1 self.oscillators.add(self.oscillator, width) self.highs.add(highPrice, width) self.lows.add(lowPrice, width) bool lowFound = false bool highFound = false if self.oscillators.values.size() == width float candidate = self.oscillators.lag(self.rightBars) lowFound := not na(candidate) highFound := not na(candidate) for i = 0 to width - 1 float neighbour = self.oscillators.lag(i) if i != self.rightBars and not na(neighbour) lowFound := lowFound and (i < self.rightBars ? f_lt(candidate, neighbour) : f_le(candidate, neighbour)) highFound := highFound and (i < self.rightBars ? f_gt(candidate, neighbour) : f_ge(candidate, neighbour)) if lowFound self.previousLowPivotOscillator := self.latestLowOscillator self.previousLowPivotPrice := self.latestLowPrice self.latestLowOscillator := candidate self.latestLowPrice := self.lows.lag(self.rightBars) if highFound self.previousHighPivotOscillator := self.latestHighOscillator self.previousHighPivotPrice := self.latestHighPrice self.latestHighOscillator := candidate self.latestHighPrice := self.highs.lag(self.rightBars) self.lowPivotBarsSincePrevious := self.precedingLowFound ? 0 : na(self.lowPivotBarsSincePrevious) ? na : self.lowPivotBarsSincePrevious + 1 self.precedingLowFound := lowFoundtype Holding int steps = 0 float average = 0 bool pending = false int targetDirection = 0 float allocation = 1 float executedDelta = 0 float executedPrice = na float markedPrice = na float referencePrice = na float plannedPrice = 0type Account float initial float wallet float equity float peak float drawdown = 0 float fees = 0 float slippage = 0 int fills = 0 int closed = 0 array<Holding> holdings string mode = "combination"f_account(float capital, int routes = 1, string mode = "combination") => array<Holding> holdings = array.new<Holding>() for i = 1 to routes holdings.push(Holding.new(allocation = 1.0 / routes)) Account.new(capital, capital, capital, capital, holdings = holdings, mode = mode)method valueAt(Account self, float price, float quantityStep) => float value = self.wallet for holding in self.holdings value += holding.steps * quantityStep * (price - holding.average) valuemethod observe(Account self, float quantityStep) => self.equity := self.wallet for holding in self.holdings if holding.steps != 0 self.equity += holding.steps * quantityStep * (holding.markedPrice - holding.average) self.peak := math.max(self.peak, self.equity) self.drawdown := math.max(self.drawdown, (self.peak - self.equity) / self.peak)method mark(Account self, float price, float quantityStep) => for holding in self.holdings holding.markedPrice := price self.observe(quantityStep)method execute(Account self, float openPrice, float quantityStep, float feeRate, float slipRate) => float sizingEquity = self.valueAt(openPrice, quantityStep) for holding in self.holdings holding.executedDelta := 0 holding.executedPrice := na if holding.pending float sizingPrice = openPrice float sizingNotional = math.max(sizingEquity, 0) * holding.allocation if self.mode == "managed" float reserved = 0 for other in self.holdings reserved += math.abs(other.steps) * quantityStep * other.plannedPrice sizingPrice := holding.referencePrice sizingNotional := math.min(math.max(self.equity, 0) * holding.allocation, math.max(self.equity - reserved, 0)) int target = holding.targetDirection == 0 ? 0 : holding.targetDirection * int(math.floor(sizingNotional / (sizingPrice * quantityStep))) int before = holding.steps int deltaSteps = target - before if deltaSteps != 0 float delta = deltaSteps * quantityStep float fill = openPrice * (deltaSteps > 0 ? 1 + slipRate : 1 - slipRate) float fee = math.abs(delta) * fill * feeRate self.wallet -= fee self.fees += fee self.slippage += math.abs(delta) * math.abs(fill - openPrice) self.fills += 1 holding.executedDelta := delta holding.executedPrice := fill if before == 0 or math.sign(before) == math.sign(deltaSteps) holding.average := (math.abs(before) * quantityStep * holding.average + math.abs(delta) * fill) / (math.abs(target) * quantityStep) else int closing = math.min(math.abs(before), math.abs(deltaSteps)) self.wallet += closing * quantityStep * math.sign(before) * (fill - holding.average) if target == 0 or math.sign(target) != math.sign(before) self.closed += 1 holding.average := target == 0 ? 0 : fill holding.steps := target holding.markedPrice := fill if before == 0 or math.sign(before) != math.sign(target) holding.plannedPrice := target == 0 ? 0 : holding.referencePrice if self.mode == "combination" self.mark(fill, quantityStep) else if self.mode == "managed" self.observe(quantityStep) holding.pending := false if self.mode == "open" self.mark(openPrice, quantityStep)type Member bool active = false int enteredAt = na int heldBars = 0 bool changed = false float entryPrice = na float highestClose = na float lowestClose = na bool pendingReference = falsemethod fillReference(Member self, float openPrice, float slipRate, int direction) => if self.pendingReference self.entryPrice := openPrice * (direction == 1 ? 1 + slipRate : 1 - slipRate) self.pendingReference := falsemethod decide(Member self, bool entry, bool exit, int closeAt) => bool before = self.active if self.active self.heldBars += 1 if exit self.active := false self.enteredAt := na self.heldBars := 0 self.highestClose := na self.lowestClose := na self.entryPrice := na else if entry self.active := true self.enteredAt := closeAt self.heldBars := 0 self.pendingReference := true self.changed := self.active != beforetype Incumbent int member = 0 int inactive = 0 bool desired = false bool changed = falsemethod combine(Incumbent self, Member a, Member b) => bool event = a.changed or b.changed bool before = self.desired self.changed := false if event or (self.desired and self.member != 0 and not a.active and not b.active) if a.active or b.active bool keep = (self.member == 1 and a.active) or (self.member == 2 and b.active) if not keep self.member := a.active and b.active ? (a.enteredAt <= b.enteredAt ? 1 : 2) : a.active ? 1 : 2 self.inactive := 0 self.desired := true else if self.desired and self.member != 0 self.inactive += 1 if self.inactive >= 2 self.member := 0 self.desired := false else self.member := 0 self.inactive := 0 self.desired := false self.changed := event or self.desired != beforetype Program0 RsiState calculation array<Samples> history bool entry = false bool exit = falsemethod calculate(Program0 self, float highPrice, float lowPrice, float closePrice) => self.calculation.calculate(highPrice, lowPrice, closePrice) float n0 = self.calculation.lowPivotBarsSincePrevious self.history.get(0).add(n0) float n1 = self.calculation.oscillator self.history.get(1).add(n1) float n2 = self.calculation.previousHighPivotOscillator self.history.get(2).add(n2) float n3 = self.calculation.previousHighPivotPrice self.history.get(3).add(n3) float n4 = self.calculation.previousLowPivotOscillator self.history.get(4).add(n4) float n5 = 0.0 self.history.get(5).add(n5) float n6 = -1.0 self.history.get(6).add(n6) float n7 = 0.0 self.history.get(7).add(n7) float n8 = 1.0 self.history.get(8).add(n8) float n9 = n1 - self.history.get(1).lag(1) self.history.get(9).add(n9) float n10 = n2 - self.history.get(2).lag(1) self.history.get(10).add(n10) float n11 = self.history.get(0).rangePosition(20) self.history.get(11).add(n11) float n12 = f_relative(self.history.get(3), self.history.get(4), 60) self.history.get(12).add(n12) float n13 = na(n9) or na(n10) ? na : f_number(f_gt(n9, 0) and f_lt(n10, 0) or f_lt(n9, 0) and f_gt(n10, 0)) self.history.get(13).add(n13) float n14 = f_compare(n9, n5, "lt") self.history.get(14).add(n14) float n15 = f_compare(n11, n6, "lt") self.history.get(15).add(n15) float n16 = f_compare(n11, n8, "gt") self.history.get(16).add(n16) float n17 = f_compare(n12, n7, "lt") self.history.get(17).add(n17) float n18 = f_votes(array.from(n13, n14), 2) self.history.get(18).add(n18) float n19 = f_votes(array.from(n18, n16, n17), 2) self.history.get(19).add(n19) self.entry := n19 == 1 self.exit := n15 == 1method advance(Account account, Program0 a, Member aMember, float openPrice, float highPrice, float lowPrice, float closePrice, int closeAt, bool scored, bool mayDecide, float quantityStep, float feeRate, float slipRate) => Holding holding = account.holdings.get(0) if scored account.execute(openPrice, quantityStep, feeRate, slipRate) a.calculate(highPrice, lowPrice, closePrice) if mayDecide aMember.decide(a.entry, a.exit, closeAt) if mayDecide and aMember.changed holding.pending := true holding.targetDirection := aMember.active ? 1 : 0 if scored account.mark(closePrice, quantityStep)useWindow = input.bool(true, "Use archive date window", group = "Replay")startAt = input.time(1746144900000, "First scored open", group = "Replay")endAt = input.time(1788220800000, "End (exclusive)", group = "Replay")initialCapital = input.float(10000, "Initial equity", minval = 1, group = "Archive account")quantityStep = input.float(0.01, "Quantity step", minval = 0.000001, group = "Archive account")feeRate = input.float(0.06, "Fee (%)", minval = 0, group = "Archive account") / 100slipRate = input.float(0.02, "Slippage (%)", minval = 0, group = "Archive account") / 100showOrders = input.bool(false, "Show approximate broker orders", group = "Display")showNativeFills = input.bool(true, "Show native fill markers", group = "Display")scored = not useWindow or time >= startAt and time < endAtmayDecide = scored and (not useWindow or time_close < endAt)var Account account = f_account(initialCapital, 1, "open")var int origin = timevar int scoredCount = 0aLength = input.int(7, "RSI length", minval = 1, maxval = 300, group = "Member 1")aLeft = input.int(5, "Left pivot bars", minval = 1, maxval = 300, group = "Member 1")aRight = input.int(5, "Right pivot bars", minval = 1, maxval = 300, group = "Member 1")var Program0 a = Program0.new(f_rsi(aLength, aLeft, aRight), f_histories(20))var Member aMember = Member.new()if barstate.isconfirmed account.advance(a, aMember, open, high, low, close, time_close, scored, mayDecide, quantityStep, feeRate, slipRate) Holding holding = account.holdings.get(0) if scored scoredCount += 1 if showOrders and mayDecide and holding.pending float target = holding.targetDirection == 0 ? 0 : math.floor(math.max(account.equity, 0) / (close * quantityStep)) * quantityStep float delta = target - strategy.position_size if f_gt(delta, 0) strategy.order("Increase", strategy.long, qty = delta) else if f_lt(delta, 0) strategy.order("Decrease", strategy.short, qty = -delta)var table summary = table.new(position.top_right, 2, 8, bgcolor = color.new(color.black, 10))if barstate.islast table.cell(summary, 0, 0, "Archive rules", text_color = color.white) table.cell(summary, 1, 0, "Loaded chart candles", text_color = color.white) table.cell(summary, 0, 1, "Equity", text_color = color.white) table.cell(summary, 1, 1, str.tostring(account.equity, "#.########"), text_color = color.white) table.cell(summary, 0, 2, "Net return", text_color = color.white) table.cell(summary, 1, 2, str.tostring((account.equity / initialCapital - 1) * 100, "#.########") + "%", text_color = color.white) table.cell(summary, 0, 3, "Maximum drawdown", text_color = color.white) table.cell(summary, 1, 3, str.tostring(account.drawdown * 100, "#.########") + "%", text_color = color.white) table.cell(summary, 0, 4, "Closed trades / fills", text_color = color.white) table.cell(summary, 1, 4, str.tostring(account.closed) + " / " + str.tostring(account.fills), text_color = color.white) table.cell(summary, 0, 5, "Fees", text_color = color.white) table.cell(summary, 1, 5, str.tostring(account.fees, "#.########"), text_color = color.white) table.cell(summary, 0, 6, "Calculation origin", text_color = color.white) table.cell(summary, 1, 6, str.format_time(origin, "yyyy-MM-dd HH:mm", "UTC"), text_color = color.white) table.cell(summary, 0, 7, "Scored candles", text_color = color.white) table.cell(summary, 1, 7, str.tostring(scoredCount), text_color = color.white)plot(account.equity, "native_equity", display = display.data_window)plot(account.holdings.get(0).steps * quantityStep, "native_quantity", display = display.data_window)plot(account.holdings.get(0).executedDelta, "native_delta", display = display.data_window)plot(account.fees, "native_fees", display = display.data_window)plot(account.drawdown, "native_drawdown", display = display.data_window)plot(account.fills, "native_fills", display = display.data_window)plot(account.closed, "native_closed", display = display.data_window)plot(aMember.active ? 1 : 0, "a_active", display = display.data_window)plotshape(showNativeFills and scored and barstate.isconfirmed and f_gt(account.holdings.get(0).executedDelta, 0), "Native buy fill", shape.triangleup, location.belowbar, color.teal, size = size.tiny)plotshape(showNativeFills and scored and barstate.isconfirmed and f_lt(account.holdings.get(0).executedDelta, 0), "Native sell fill", shape.triangledown, location.abovebar, color.red, size = size.tiny)plot(a.history.get(0).lag(), "a_feature_001", display = display.data_window)plot(a.history.get(1).lag(), "a_feature_002", display = display.data_window)plot(a.history.get(2).lag(), "a_feature_003", display = display.data_window)plot(a.history.get(3).lag(), "a_feature_004", display = display.data_window)plot(a.history.get(4).lag(), "a_feature_005", display = display.data_window)plot(a.history.get(5).lag(), "a_feature_006", display = display.data_window)plot(a.history.get(6).lag(), "a_feature_007", display = display.data_window)plot(a.history.get(7).lag(), "a_feature_008", display = display.data_window)plot(a.history.get(8).lag(), "a_feature_009", display = display.data_window)plot(a.history.get(9).lag(), "a_feature_010", display = display.data_window)plot(a.history.get(10).lag(), "a_feature_011", display = display.data_window)plot(a.history.get(11).lag(), "a_feature_012", display = display.data_window)plot(a.history.get(12).lag(), "a_feature_013", display = display.data_window)plot(a.history.get(13).lag(), "a_feature_014", display = display.data_window)plot(a.history.get(14).lag(), "a_feature_015", display = display.data_window)plot(a.history.get(15).lag(), "a_feature_016", display = display.data_window)plot(a.history.get(16).lag(), "a_feature_017", display = display.data_window)plot(a.history.get(17).lag(), "a_feature_018", display = display.data_window)plot(a.history.get(18).lag(), "a_feature_019", display = display.data_window)plot(a.history.get(19).lag(), "a_feature_020", display = display.data_window)