//---
// 简称: candel
// 名称: EXPMA金叉死叉+吊灯止损_一次性执行
// 类别: 公式应用
// 类型: 用户应用
// 输出: Void
//---

/*
策略说明:手动指定方向的一次性执行工具。
  进场:启动前设 TradeDir(1做多等金叉 / -1做空等死叉);出现指定方向交叉,下一根开盘价进场。
  出场:吊灯线(峰值∓K×ATR,峰值自进场价起跨根累积)与固定止损(进场∓MaxLoss)取更紧者;
        价格触及即平;反向交叉兜底平仓。平仓后不再进场(一次性)。
  ★所有条件用已收线的 [1] 前值判断,避免信号闪烁(与EXPMA40示例一致)。
*/

Params
    Numeric TradeDir(1);        // 本次方向: 1做多等金叉  -1做空等死叉
    Numeric EXPMA_Fast(21);     // EXPMA 快线
    Numeric EXPMA_Slow(42);     // EXPMA 慢线
    Numeric ATR_Length(20);     // ATR 窗口
    Numeric K(2.5);             // 吊灯 ATR 倍数
    Numeric MaxLoss(15);        // 固定止损点数(0=关闭只用吊灯)
    Numeric Lots(1);            // 开仓手数

Vars
    Series<Numeric> ema_fast;
    Series<Numeric> ema_slow;
    Series<Numeric> atr_val;
    Series<Bool> golden_cross;
    Series<Bool> death_cross;
    Global Numeric extreme(0);      // 多:进场后最高 / 空:进场后最低(自进场价起累积)
    Numeric chandLine;
    Numeric fixedLine;
    Series<Numeric> stopLine;       // 画出来看,声明为序列
    Global Bool tradeDone(False);   // 一次性完成
    Global Numeric prevPos(0);

Events
    OnBar(ArrayRef<Integer> indexs)
    {
        Range[0:DataSourceSize() - 1]
        {
            ema_fast = XAverage(Close, EXPMA_Fast);
            ema_slow = XAverage(Close, EXPMA_Slow);
            atr_val = AvgTrueRange(ATR_Length);
            golden_cross = CrossOver(ema_fast[1], ema_slow[1]);
            death_cross = CrossUnder(ema_fast[1], ema_slow[1]);
        }

        Range[0:0]
        {
            If(CurrentBar < 100) Return;
            If(EXPMA_Fast >= EXPMA_Slow) Return;

            PlotNumeric("EXPMA_Fast", ema_fast, 0, Yellow);
            PlotNumeric("EXPMA_Slow", ema_slow, 0, Red);

            // 一次性完成检测
            If(prevPos <> 0 && MarketPosition == 0)
            {
                tradeDone = True;
            }

            // ---------- 进场:空仓且未完成,只做指定方向,下一根开盘价进场 ----------
            If(MarketPosition == 0 && !tradeDone)
            {
                If(TradeDir == 1 && golden_cross)
                {
                    Buy(Lots, Open);
                    Commentary("金叉开多");
                }
                Else If(TradeDir == -1 && death_cross)
                {
                    SellShort(Lots, Open);
                    Commentary("死叉开空");
                }
            }

            // ---------- 持多:吊灯+固定止损(取更紧),死叉兜底 ----------
            If(MarketPosition == 1 && BarsSinceEntry > 0)
            {
                // 峰值:进场价起,用已收线高点跨根累积
                If(BarsSinceEntry == 1)
                {
                    extreme = AvgEntryPrice;
                }
                extreme = Max(extreme, High[1]);

                chandLine = extreme - K * atr_val[1];
                If(MaxLoss > 0)
                {
                    fixedLine = AvgEntryPrice - MaxLoss;
                }
                Else
                {
                    fixedLine = -1000000;
                }
                stopLine = Max(chandLine, fixedLine);
                PlotNumeric("StopLine", stopLine, 0, Green);

                If(death_cross)
                {
                    Sell(Lots, Open);
                    Commentary("死叉平多");
                }
                Else If(Low[1] <= stopLine)
                {
                    Sell(Lots, Open);
                    Commentary("吊灯/固定止损平多");
                }
            }

            // ---------- 持空:对称 ----------
            If(MarketPosition == -1 && BarsSinceEntry > 0)
            {
                If(BarsSinceEntry == 1)
                {
                    extreme = AvgEntryPrice;
                }
                extreme = Min(extreme, Low[1]);

                chandLine = extreme + K * atr_val[1];
                If(MaxLoss > 0)
                {
                    fixedLine = AvgEntryPrice + MaxLoss;
                }
                Else
                {
                    fixedLine = 1000000;
                }
                stopLine = Min(chandLine, fixedLine);
                PlotNumeric("StopLine", stopLine, 0, Green);

                If(golden_cross)
                {
                    BuyToCover(Lots, Open);
                    Commentary("金叉平空");
                }
                Else If(High[1] >= stopLine)
                {
                    BuyToCover(Lots, Open);
                    Commentary("吊灯/固定止损平空");
                }
            }

            prevPos = MarketPosition;
        }
    }
