# ============================================================================
#  PipAtlas Backtrader Strategy Template - MIT License - (c) 2026 PipAtlas
#  Free to use/modify. Education only - NOT financial advice. Demo-first!
#  Companion guide: pipatlas.com/learn/conversions/backtrader-to-pine
# ============================================================================
import backtrader as bt

class AtrRiskTemplate(bt.Strategy):
    """MA-cross entries, ATR stops, percent-risk sizing, daily circuit breaker."""
    params = dict(
        fast=21, slow=55,
        atr_period=14, atr_mult=2.0,
        risk_pct=1.0,          # % of broker cash risked per trade
        max_daily_pct=3.0,     # flatten + halt after this daily loss
    )

    def __init__(self):
        self.fast = bt.ind.EMA(self.data.close, period=self.p.fast)
        self.slow = bt.ind.EMA(self.data.close, period=self.p.slow)
        self.atr = bt.ind.ATR(self.data, period=self.p.atr_period)
        self.cross = bt.ind.CrossOver(self.fast, self.slow)
        self.order = None
        self.day = None
        self.day_start_value = self.broker.getvalue()

    def notify_order(self, order):
        if order.status in (order.Completed, order.Canceled, order.Rejected):
            self.order = None

    def next(self):
        # daily circuit breaker
        today = self.data.datetime.date(0)
        if self.day != today:
            self.day = today
            self.day_start_value = self.broker.getvalue()
        day_pnl_pct = (self.broker.getvalue() / self.day_start_value - 1) * 100
        if day_pnl_pct <= -self.p.max_daily_pct:
            if self.position:
                self.close()
            return

        if self.order:                      # one order at a time
            return

        stop_dist = self.atr[0] * self.p.atr_mult
        risk_cash = self.broker.getvalue() * self.p.risk_pct / 100.0
        size = max(0, int(risk_cash / stop_dist)) if stop_dist > 0 else 0

        if not self.position and size:
            if self.cross[0] > 0:           # golden cross
                self.order = self.buy(size=size, exectype=bt.Order.Market)
            elif self.cross[0] < 0:         # death cross
                self.order = self.sell(size=size, exectype=bt.Order.Market)
        elif self.position:
            if self.position.size > 0:
                self.order = self.sell(exectype=bt.Order.Stop, price=self.data.close[0] - stop_dist)
            else:
                self.order = self.buy(exectype=bt.Order.Stop, price=self.data.close[0] + stop_dist)


if __name__ == '__main__':
    cerebro = bt.Cerebro()
    # Point at YOUR data source; demo/paper data first.
    # cerebro.adddata(bt.feeds.GenericCSVData(dataname='EURUSD_1H.csv', dtformat='%Y-%m-%d %H:%M'))
    cerebro.addstrategy(AtrRiskTemplate)
    cerebro.broker.setcash(10000)
    cerebro.broker.setcommission(commission=0.0)
    cerebro.run()
    # cerebro.plot(style='candlestick')
