Archive defaults: ETHUSDT · 4h decisions · 1h execution. Uses the current chart symbol and timeframe.
Regenerated from the installed original archive. TradingView verification on 47,304 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 C00297-X-C00605-FULL-DIRECTIONAL-UNION: 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()) resultf_median(array<float> values) => array<float> ordered = values.copy() ordered.sort() int middle = int(math.floor(ordered.size() / 2)) float lower = ordered.get(math.max(0, middle - 1)) float upper = ordered.get(middle) ordered.size() % 2 == 1 ? upper : f_lt(lower, 0) and f_gt(upper, 0) ? lower / 2 + upper / 2 : lower + (upper - lower) / 2method priorMad(Samples self, int length) => array<float> prior = array.new<float>() bool complete = not na(self.lag()) for i = length to 1 float value = self.lag(i) complete := complete and not na(value) prior.push(value) float result = na if complete float center = f_median(prior) array<float> deviations = array.new<float>() for value in prior deviations.push(math.abs(value - center)) result := (self.lag() - center) / (1.482602218505602 * f_median(deviations)) resultmethod downsideShare(Samples self, int length) => float downside = 0 float total = 0 bool complete = true for i = length to 1 float previous = self.lag(i + 1) float current = self.lag(i) complete := complete and f_gt(previous, 0) and f_gt(current, 0) float change = math.log(current) - math.log(previous) float square = change * change total += square if f_lt(change, 0) downside += square complete ? downside / total : naf_pairStats(Samples left, Samples right, int length, int offset) => [leftMean, leftDeviation] = left.stats(length, offset) [rightMean, rightDeviation] = right.stats(length, offset) float covariance = 0 float leftVariance = 0 float rightVariance = 0 for i = length - 1 to 0 float leftDelta = left.lag(i + offset) - leftMean float rightDelta = right.lag(i + offset) - rightMean covariance += leftDelta * rightDelta leftVariance += leftDelta * leftDelta rightVariance += rightDelta * rightDelta [leftMean, rightMean, covariance, leftVariance, rightVariance]f_correlation(Samples left, Samples right, int length) => [leftMean, rightMean, covariance, leftVariance, rightVariance] = f_pairStats(left, right, length, 0) covariance / math.sqrt(leftVariance * rightVariance)f_regression(Samples left, Samples right, int length) => [leftMean, rightMean, covariance, leftVariance, rightVariance] = f_pairStats(left, right, length, 1) float beta = covariance / leftVariance right.lag() - (rightMean - beta * leftMean + beta * left.lag())f_region(float value, float lower, float upper) => na(value) or na(lower) or na(upper) ? na : f_gt(value, upper) ? 1.0 : f_lt(value, lower) ? -1.0 : 0.0f_breakout(Samples price, Samples lower, Samples upper) => float current = f_region(price.lag(), lower.lag(), upper.lag()) float previous = f_region(price.lag(1), lower.lag(1), upper.lag(1)) na(current) ? na : na(previous) ? 0.0 : current == 1 and previous != 1 ? 1.0 : current == -1 and previous != -1 ? -1.0 : 0.0type AtrRatio float previousClose = na float atr = na float seedSum = 0 int count = 0method calculate(AtrRatio self, float highPrice, float lowPrice, float closePrice, int period) => float trueRange = na(self.previousClose) ? highPrice - lowPrice : math.max(highPrice - lowPrice, math.abs(highPrice - self.previousClose), math.abs(lowPrice - self.previousClose)) float result = trueRange / self.atr if na(self.atr) self.seedSum += trueRange self.count += 1 if self.count == period self.atr := self.seedSum / period else self.atr := (self.atr * (period - 1) + trueRange) / period self.previousClose := closePrice resulttype ZoneState int atrLength int averageLength int minZoneBars float maxZoneHeightAtr float maxDrift float breakBufferAtr float edgeTouchToleranceAtr int cooldownBars float strongBreakThreshold int coilReferenceBars int barIndex = 0 Samples closes Samples highs Samples lows Samples ranges Samples volumes float atr = na float atrSeedSum = 0 int atrSeedCount = 0 bool inZone = false float retainedTop = na float retainedBottom = na float zoneAtr = na int zoneStart = 0 int cooldownUntil = 0 float zoneTop = na float zoneBottom = na float zoneMiddle = na float trueRange = na float averageRange = na float volumeAverage = na float breakStrength = 0 int breakDirection = 0 bool zoneBorn = falsef_zone(int atrLength, int averageLength, int minZoneBars, float maxZoneHeightAtr, float maxDrift, float breakBufferAtr, float edgeTouchToleranceAtr, int cooldownBars, float strongBreakThreshold, int coilReferenceBars) => ZoneState.new(atrLength, averageLength, minZoneBars, maxZoneHeightAtr, maxDrift, breakBufferAtr, edgeTouchToleranceAtr, cooldownBars, strongBreakThreshold, coilReferenceBars, closes = f_samples(), highs = f_samples(), lows = f_samples(), ranges = f_samples(), volumes = f_samples())method calculate(ZoneState self, float highPrice, float lowPrice, float closePrice, float volumeValue) => float previousClose = self.closes.lag() self.trueRange := na(previousClose) ? highPrice - lowPrice : math.max(highPrice - lowPrice, math.abs(highPrice - previousClose), math.abs(lowPrice - previousClose)) if na(self.atr) self.atrSeedSum += self.trueRange self.atrSeedCount += 1 if self.atrSeedCount == self.atrLength self.atr := self.atrSeedSum / self.atrLength else float alpha = 1.0 / self.atrLength self.atr := alpha * self.trueRange + (1 - alpha) * self.atr self.closes.add(closePrice, self.minZoneBars + 1) self.highs.add(highPrice, self.minZoneBars) self.lows.add(lowPrice, self.minZoneBars) self.ranges.add(self.trueRange, self.averageLength) self.volumes.add(volumeValue, self.averageLength) [averageRange, rangeDeviation] = self.ranges.stats(self.averageLength) [volumeAverage, volumeDeviation] = self.volumes.stats(self.averageLength) self.averageRange := averageRange self.volumeAverage := volumeAverage bool hasVolume = f_gt(volumeAverage, 0) float highest = self.highs.values.max() float lowest = self.lows.values.min() self.zoneBorn := false self.breakStrength := 0 self.breakDirection := 0 if f_gt(self.atr, 0) if not self.inZone if self.barIndex >= self.cooldownUntil and self.barIndex > self.minZoneBars float windowRange = highest - lowest float drift = math.abs(closePrice - self.closes.lag(self.minZoneBars)) if f_le(windowRange, self.maxZoneHeightAtr * self.atr) and f_le(drift, windowRange * self.maxDrift) self.inZone := true self.retainedTop := highest self.retainedBottom := lowest self.zoneStart := self.barIndex - self.minZoneBars + 1 self.zoneAtr := self.atr self.zoneBorn := true else bool upBreak = f_gt(closePrice, self.retainedTop + self.breakBufferAtr * self.zoneAtr) bool downBreak = f_lt(closePrice, self.retainedBottom - self.breakBufferAtr * self.zoneAtr) if upBreak or downBreak float displacement = upBreak ? closePrice - self.retainedTop : self.retainedBottom - closePrice float displacementTerm = math.min(displacement / self.zoneAtr, 1) float expansionTerm = f_gt(averageRange, 0) ? math.min(self.trueRange / averageRange / 2, 1) : 0 float volumeTerm = hasVolume ? math.min(volumeValue / volumeAverage / 2, 1) : na float coilTerm = math.min((self.barIndex - self.zoneStart) / float(self.coilReferenceBars), 1) float baseTerm = 0.35 * displacementTerm + 0.3 * expansionTerm + 0.15 * coilTerm self.breakStrength := hasVolume ? (baseTerm + 0.2 * volumeTerm) * 100 : baseTerm / 0.8 * 100 self.breakDirection := upBreak ? 1 : -1 self.inZone := false self.cooldownUntil := self.barIndex + self.cooldownBars else float newTop = math.max(self.retainedTop, highPrice) float newBottom = math.min(self.retainedBottom, lowPrice) if f_le(newTop - newBottom, self.maxZoneHeightAtr * self.zoneAtr) self.retainedTop := newTop self.retainedBottom := newBottom self.barIndex += 1 self.zoneTop := self.inZone ? self.retainedTop : na self.zoneBottom := self.inZone ? self.retainedBottom : na self.zoneMiddle := self.inZone ? (self.retainedTop + self.retainedBottom) / 2 : natype 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 ZoneState calculation array<Samples> history AtrRatio atrRatio bool entry = false bool exit = falsemethod features(Program0 self, float openPrice, float highPrice, float lowPrice, float closePrice, float volumeValue, bool available = true) => float n0 = available ? self.calculation.zoneBottom : na self.history.get(0).add(n0) float n1 = available ? self.calculation.zoneTop : na self.history.get(1).add(n1) float n2 = available ? self.calculation.trueRange : na self.history.get(2).add(n2) float n3 = closePrice self.history.get(3).add(n3) float n4 = 0.0 self.history.get(4).add(n4) float n5 = 0.6 self.history.get(5).add(n5) float n6 = f_breakout(self.history.get(3), self.history.get(0), self.history.get(1)) self.history.get(6).add(n6) float n7 = self.history.get(2).rank(20) self.history.get(7).add(n7) float n8 = f_compare(n6, n4, "gt") self.history.get(8).add(n8) float n9 = f_compare(n6, n4, "lt") self.history.get(9).add(n9) float n10 = f_compare(n7, n5, "ge") self.history.get(10).add(n10) self.entry := n8 == 1 and n10 == 1 self.exit := n9 == 1type Program1 ZoneState calculation array<Samples> history AtrRatio atrRatio bool entry = false bool exit = falsemethod features(Program1 self, float openPrice, float highPrice, float lowPrice, float closePrice, float volumeValue, bool available = true) => float n0 = available ? self.calculation.zoneBottom : na self.history.get(0).add(n0) float n1 = available ? self.calculation.zoneTop : na self.history.get(1).add(n1) float n2 = closePrice self.history.get(2).add(n2) float n3 = 0.6666666666666666 self.history.get(3).add(n3) float n4 = 0.0 self.history.get(4).add(n4) float n5 = f_relative(self.history.get(0), self.history.get(1), 60) self.history.get(5).add(n5) float n6 = self.history.get(2).downsideShare(60) self.history.get(6).add(n6) float n7 = f_compare(n5, n4, "gt") self.history.get(7).add(n7) float n8 = f_compare(n5, n4, "lt") self.history.get(8).add(n8) float n9 = f_compare(n6, n3, "ge") self.history.get(9).add(n9) self.entry := n7 == 1 and n9 == 1 self.exit := n8 == 1type MultiClock int lastCalculationAt = na int desired = 0method advance(Account account, Program0 a, Member aMember, Program1 b, Member bMember, MultiClock clock, float openPrice, float highPrice, float lowPrice, float closePrice, float volumeValue, int openAt, int closeAt, bool scored, bool mayDecide, float quantityStep, float feeRate, float slipRate, bool decisionClosed, float decisionOpen, float decisionHigh, float decisionLow, float decisionClose, float decisionVolume, int decisionAt, int maximumAge) => aMember.changed := false bMember.changed := false int beforeSteps = account.holdings.get(0).steps if scored account.execute(openPrice, quantityStep, feeRate, slipRate) int afterSteps = account.holdings.get(0).steps if beforeSteps != 0 and afterSteps != 0 and math.sign(beforeSteps) != math.sign(afterSteps) account.fills += 1 aMember.fillReference(openPrice, slipRate, 1) bMember.fillReference(openPrice, slipRate, -1) if decisionClosed a.calculation.calculate(decisionHigh, decisionLow, decisionClose, decisionVolume) clock.lastCalculationAt := decisionAt b.calculation.calculate(decisionHigh, decisionLow, decisionClose, decisionVolume) a.features(decisionOpen, decisionHigh, decisionLow, decisionClose, decisionVolume) b.features(decisionOpen, decisionHigh, decisionLow, decisionClose, decisionVolume) if mayDecide if aMember.active aMember.highestClose := na(aMember.highestClose) ? decisionClose : math.max(aMember.highestClose, decisionClose) aMember.lowestClose := na(aMember.lowestClose) ? decisionClose : math.min(aMember.lowestClose, decisionClose) aMember.decide(a.entry, a.exit or (aMember.heldBars + 1 >= 16 or f_le(decisionClose, aMember.entryPrice - aMember.entryPrice * 1 / 100) or f_ge(decisionClose, aMember.entryPrice + aMember.entryPrice * 2 / 100)), closeAt) if bMember.active bMember.highestClose := na(bMember.highestClose) ? decisionClose : math.max(bMember.highestClose, decisionClose) bMember.lowestClose := na(bMember.lowestClose) ? decisionClose : math.min(bMember.lowestClose, decisionClose) bMember.decide(b.entry, b.exit, closeAt) int desired = aMember.active and bMember.active ? 0 : aMember.active ? 1 : bMember.active ? -1 : 0 if aMember.changed or bMember.changed Holding holding = account.holdings.get(0) holding.pending := true holding.targetDirection := desired clock.desired := desired if scored account.mark(closePrice, quantityStep)useWindow = input.bool(true, "Use archive date window", group = "Replay")startAt = input.time(1620115200000, "First scored open", group = "Replay")endAt = input.time(1786060800000, "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 int origin = timevar int scoredCount = 0aatrLength = input.int(14, "Atr length", minval = 1, group = "Zone 1")aaverageLength = input.int(20, "Average length", minval = 1, group = "Zone 1")aminZoneBars = input.int(20, "Min zone bars", minval = 1, group = "Zone 1")amaxZoneHeightAtr = input.float(5, "Max zone height atr", minval = 0.001, group = "Zone 1")amaxDrift = input.float(0.7, "Max drift", minval = 0.001, group = "Zone 1")abreakBufferAtr = input.float(0.3, "Break buffer atr", minval = 0, group = "Zone 1")aedgeTouchToleranceAtr = input.float(0.2, "Edge touch tolerance atr", minval = 0, group = "Zone 1")acooldownBars = input.int(3, "Cooldown bars", minval = 0, group = "Zone 1")astrongBreakThreshold = input.float(55, "Strong break threshold", minval = 0.001, group = "Zone 1")acoilReferenceBars = input.int(50, "Coil reference bars", minval = 1, group = "Zone 1")batrLength = input.int(14, "Atr length", minval = 1, group = "Zone 2")baverageLength = input.int(20, "Average length", minval = 1, group = "Zone 2")bminZoneBars = input.int(5, "Min zone bars", minval = 1, group = "Zone 2")bmaxZoneHeightAtr = input.float(3.5, "Max zone height atr", minval = 0.001, group = "Zone 2")bmaxDrift = input.float(0.8, "Max drift", minval = 0.001, group = "Zone 2")bbreakBufferAtr = input.float(0.1, "Break buffer atr", minval = 0, group = "Zone 2")bedgeTouchToleranceAtr = input.float(1.6, "Edge touch tolerance atr", minval = 0, group = "Zone 2")bcooldownBars = input.int(3, "Cooldown bars", minval = 0, group = "Zone 2")bstrongBreakThreshold = input.float(80, "Strong break threshold", minval = 0.001, group = "Zone 2")bcoilReferenceBars = input.int(200, "Coil reference bars", minval = 1, group = "Zone 2")var ZoneState aCalculation = f_zone(aatrLength, aaverageLength, aminZoneBars, amaxZoneHeightAtr, amaxDrift, abreakBufferAtr, aedgeTouchToleranceAtr, acooldownBars, astrongBreakThreshold, acoilReferenceBars)var Program0 a = Program0.new(aCalculation, f_histories(11), AtrRatio.new())var Member aMember = Member.new()var ZoneState bCalculation = f_zone(batrLength, baverageLength, bminZoneBars, bmaxZoneHeightAtr, bmaxDrift, bbreakBufferAtr, bedgeTouchToleranceAtr, bcooldownBars, bstrongBreakThreshold, bcoilReferenceBars)var Program1 b = Program1.new(bCalculation, f_histories(10), AtrRatio.new())var Member bMember = Member.new()var Account account = f_account(initialCapital, 1, "combination")var MultiClock clock = MultiClock.new()decisionTimeframe = input.timeframe("240", "Higher decision timeframe (archive: 4h)", group = "Decision clocks")if timeframe.in_seconds(decisionTimeframe) < timeframe.in_seconds() runtime.error("Use a chart timeframe at or below the higher decision timeframe. The archive executes on 1h candles.")[dOpenAt, dCloseAt, dOpen, dHigh, dLow, dClose, dVolume] = request.security(syminfo.tickerid, decisionTimeframe, [time, time_close, open, high, low, close, volume], gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)decisionClosed = time_close == dCloseAt and (na(clock.lastCalculationAt) or dCloseAt > clock.lastCalculationAt)if barstate.isconfirmed account.advance(a, aMember, b, bMember, clock, open, high, low, close, volume, time, time_close, scored, mayDecide, quantityStep, feeRate, slipRate, decisionClosed, dOpen, dHigh, dLow, dClose, dVolume, dCloseAt, int(timeframe.in_seconds(decisionTimeframe) * 1000)) if scored scoredCount += 1 if showOrders and mayDecide float target = 0 bool change = false for holding in account.holdings target += holding.pending ? holding.targetDirection * math.floor(math.max(account.equity, 0) * holding.allocation / (close * quantityStep)) * quantityStep : holding.steps * quantityStep change := change or holding.pending float delta = target - strategy.position_size if change and f_gt(delta, 0) strategy.order("Buy delta", strategy.long, qty = delta) else if change and f_lt(delta, 0) strategy.order("Sell delta", 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.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, "native_a_active", display = display.data_window)plot(account.holdings.get(0).steps * quantityStep, "native_quantity_0", display = display.data_window)plot(bMember.active ? 1 : 0, "native_b_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(b.history.get(0).lag(), "b_feature_001", display = display.data_window)plot(b.history.get(1).lag(), "b_feature_002", display = display.data_window)plot(b.history.get(2).lag(), "b_feature_003", display = display.data_window)plot(b.history.get(3).lag(), "b_feature_004", display = display.data_window)plot(b.history.get(4).lag(), "b_feature_005", display = display.data_window)plot(b.history.get(5).lag(), "b_feature_006", display = display.data_window)plot(b.history.get(6).lag(), "b_feature_007", display = display.data_window)plot(b.history.get(7).lag(), "b_feature_008", display = display.data_window)plot(b.history.get(8).lag(), "b_feature_009", display = display.data_window)plot(b.history.get(9).lag(), "b_feature_010", display = display.data_window)plot(a.calculation.zoneTop, "zoneTop")plot(a.calculation.zoneMiddle, "zoneMiddle")plot(a.calculation.zoneBottom, "zoneBottom")