Overall Statistics
Total Orders
306
Average Win
3.32%
Average Loss
-0.69%
Compounding Annual Return
17.566%
Drawdown
9.000%
Expectancy
1.067
Start Equity
100000.00
End Equity
233114.65
Net Profit
133.115%
Sharpe Ratio
0.899
Sortino Ratio
0.746
Probabilistic Sharpe Ratio
74.721%
Loss Rate
64%
Win Rate
36%
Profit-Loss Ratio
4.82
Alpha
0.089
Beta
0.075
Annual Standard Deviation
0.096
Annual Variance
0.009
Information Ratio
1.154
Tracking Error
0.112
Treynor Ratio
1.15
Total Fees
$0.00
Estimated Strategy Capacity
$38000.00
Lowest Capacity Asset
XAUUSD 8I
Portfolio Turnover
21.48%
Drawdown Recovery
343
from AlgorithmImports import *

class GoldApexV135(QCAlgorithm):
    def initialize(self):
        # 1. Horizonte Temporal de Longo Prazo (5 Anos)
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2026, 6, 1)
        self.set_cash(100000)
        
        self.set_brokerage_model(BrokerageName.OandaBrokerage, AccountType.Margin)
        self.gold = self.add_cfd("XAUUSD", Resolution.Hour, Market.OANDA).symbol

        # 2. Configuração do Chassis Dual Daily do V127
        self.ema_macro = self.ema(self.gold, 200, Resolution.Daily)
        self.ema_fast = self.ema(self.gold, 50, Resolution.Daily)
        self.atr = self.atr(self.gold, 14)
        self.atr_window = RollingWindow[float](24)
        
        # Buffers de hardware para fatiamento limpo
        self.high_window = RollingWindow[float](120)
        self.low_window = RollingWindow[float](120)
        self.high_trail = RollingWindow[float](60) 
        self.low_trail = RollingWindow[float](60)  
        self.close_window = RollingWindow[float](3)

        # Matriz de Estado Base V127
        self.entry_price = 0.0
        self.sl_price = 0.0
        self.tp_price = 0.0
        self.entry_leverage = 0.0
        self.is_be_active = False
        self.is_scaled_in = False
        self.is_trailing_active = False
        self.last_trade_day = -1
        
        self.set_warm_up(200, Resolution.Daily)

    def on_data(self, data: Slice):
        if self.time.hour == 17: return
        if self.gold not in data or data[self.gold] is None: return
        
        self.high_window.add(data[self.gold].high)
        self.low_window.add(data[self.gold].low)
        self.close_window.add(data[self.gold].close)
        self.high_trail.add(data[self.gold].high)
        self.low_trail.add(data[self.gold].low)
        self.atr_window.add(self.atr.current.value)
        
        if self.is_warming_up or not self.ema_macro.is_ready or not self.ema_fast.is_ready or not self.high_window.is_ready or not self.close_window.is_ready or not self.atr_window.is_ready: 
            return

        close_price = data[self.gold].close
        quantity = self.portfolio[self.gold].quantity

        # ================= 1. GESTÃO DE RISCO DE ESTRUTURA PURA V127 =================
        if quantity != 0:
            atr_val = self.atr.current.value
            if atr_val <= 0: atr_val = 1.0
            
            if quantity > 0:
                # Estágio 1: BE no empate (+2.2 ATR)
                if not self.is_be_active and (close_price - self.entry_price) >= (atr_val * 2.2):
                    self.sl_price = self.entry_price + (atr_val * 0.5)
                    self.is_be_active = True
                
                # Estágio 2: Piramidação linear (1.5x)
                if not self.is_scaled_in and (close_price - self.entry_price) >= (atr_val * 3.5):
                    self.set_holdings(self.gold, self.entry_leverage * 1.5)
                    self.sl_price = self.entry_price + (atr_val * 1.5)
                    self.is_scaled_in = True
                
                # Estágio 3: Trailing Stop de 48h
                if not self.is_trailing_active and (close_price - self.entry_price) >= (atr_val * 5.0):
                    self.is_trailing_active = True
                
                if self.is_trailing_active:
                    structural_low = min(list(self.low_trail)[1:49])
                    if structural_low > self.sl_price:
                        self.sl_price = structural_low
                
                if close_price <= self.sl_price or close_price >= self.tp_price:
                    self.liquidate(self.gold)
                    self.reset_trade_state()
                    
            elif quantity < 0:
                if not self.is_be_active and (self.entry_price - close_price) >= (atr_val * 2.2):
                    self.sl_price = self.entry_price - (atr_val * 0.5)
                    self.is_be_active = True
                    
                if not self.is_scaled_in and (self.entry_price - close_price) >= (atr_val * 3.5):
                    self.set_holdings(self.gold, -self.entry_leverage * 1.5)
                    self.sl_price = self.entry_price - (atr_val * 1.5)
                    self.is_scaled_in = True
                    
                if not self.is_trailing_active and (self.entry_price - close_price) >= (atr_val * 5.0):
                    self.is_trailing_active = True
                    
                if self.is_trailing_active:
                    structural_high = max(list(self.high_trail)[1:49])
                    if structural_high < self.sl_price or self.sl_price == 0:
                        self.sl_price = structural_high
                        
                if close_price >= self.sl_price or close_price <= self.tp_price:
                    self.liquidate(self.gold)
                    self.reset_trade_state()
            return

        # ================= 2. JANELA DE SESSÃO INSTITUCIONAL NY =================
        if not (7 <= self.time.hour <= 13): return
        if self.time.day == self.last_trade_day: return
        if self.time.weekday() == 4 and self.time.hour >= 12: return 

        atr_val = self.atr.current.value
        avg_atr_24h = sum(list(self.atr_window)) / 24
        
        macro_200 = self.ema_macro.current.value
        fast_50 = self.ema_fast.current.value

        if atr_val < avg_atr_24h: return

        # Caixote estável de 72 horas do chassi mestre
        vol_ratio = atr_val / avg_atr_24h if avg_atr_24h > 0 else 1.0
        lookback = int(max(48, min(96, 72 / vol_ratio)))

        high_pool = list(self.high_window)[1:lookback+1]
        low_pool = list(self.low_window)[1:lookback+1]
        highest_high = max(high_pool)
        lowest_low = min(low_pool)

        risk_percentage = 0.032 
        risk_per_unit = atr_val * 2.5 
        if risk_per_unit <= 0: return
        target_size = (self.portfolio.total_portfolio_value * risk_percentage) / risk_per_unit
        self.entry_leverage = min((target_size * close_price) / self.portfolio.total_portfolio_value, 1.35)

        last_close = self.close_window[1]

        # ================= 3. DISPARO COM FILTRO DE MOMENTUM (V135) =================
        # COMPRA: Exige deslocamento real de preço acima do fechamento anterior para barrar violinada
        if close_price > highest_high and close_price > fast_50 and fast_50 > macro_200 and close_price > last_close:
            if (close_price - last_close) >= (atr_val * 0.2):
                self.entry_price = close_price
                self.sl_price = close_price - (atr_val * 2.5)
                self.tp_price = close_price + (atr_val * 9.5)
                self.set_holdings(self.gold, self.entry_leverage)
                self.last_trade_day = self.time.day
            
        # VENDA
        elif close_price < lowest_low and close_price < fast_50 and fast_50 < macro_200 and close_price < last_close:
            if (last_close - close_price) >= (atr_val * 0.2):
                self.entry_price = close_price
                self.sl_price = close_price + (atr_val * 2.5)
                self.tp_price = close_price - (atr_val * 9.5)
                self.set_holdings(self.gold, -self.entry_leverage)
                self.last_trade_day = self.time.day

    def reset_trade_state(self):
        self.entry_price = 0.0
        self.sl_price = 0.0
        self.tp_price = 0.0
        self.entry_leverage = 0.0
        self.is_be_active = False
        self.is_scaled_in = False
        self.is_trailing_active = False