快捷导航
查看: 11|回复: 0

[技术指标] 蓝小凡精准狙击(MT5)

[复制链接]

284

主题

6

回帖

1060

积分

管理员

积分
1060
发表于 昨天 11:30 | 显示全部楼层 |阅读模式
  • //+------------------------------------------------------------------+
  • //|                                              蓝小凡精准狙击.mq5    |
  • //|                                    Copyright 2026, 蓝小凡精准狙击  |
  • //|                                             https://www.mql5.com |
  • //+------------------------------------------------------------------+
  • #property copyright "Copyright 2026, 蓝小凡精准狙击"
  • #property link      "https://www.mql5.com"
  • #property version   "1.09"
  • //+------------------------------------------------------------------+
  • //| 输入参数                                                          |
  • //+------------------------------------------------------------------+
  • input ENUM_TIMEFRAMES InpBoxTimeframe = PERIOD_H1;     // 箱体K线周期
  • input int             InpBoxBars      = 20;            // 箱体K线数量
  • input double   InpShortOffset     = 2.0;               // 做空偏移(最高价-n美金)
  • input double   InpLongOffset      = 2.0;               // 做多偏移(最高价+n美金)
  • input string   InpMartingaleSeries = "0.01,0.01,0.02,0.04,0.08,0.16"; // 倍投序列
  • input int      InpMinGapMinutes   = 5;                 // 加仓最小间隔(分钟)
  • input double   InpMonitorStart    = 5.0;               // 开始监控盈利(美金)
  • input double   InpMonitorStep     = 2.0;               // 监控步进(美金)
  • input double   InpDrawbackPercent = 30.0;              // 回撤平仓百分比(%)
  • input double   InpHardStopLoss    = 50.0;              // 硬止损(美金)
  • input double   InpHardTakeProfit  = 100.0;             // 硬止盈(美金)
  • input bool     InpEnableReverseClose = true;           // 启用反转平仓
  • input int      InpRSIPeriod          = 14;             // RSI周期
  • input int      InpRSIOverbought      = 70;             // RSI超买线
  • input int      InpRSIOversold        = 30;             // RSI超卖线
  • input color   InpUIColor           = clrDodgerBlue;    // 保留未使用
  • input int     InpFontSize          = 14;               // 字体大小
  • //+------------------------------------------------------------------+
  • //| 全局变量                                                          |
  • //+------------------------------------------------------------------+
  • string         g_Symbol;
  • long           g_MagicNumber = 20260805;
  • string         g_EAComment = "LXF_JZ_SNIPE";
  • double         g_BoxHigh = 0, g_BoxLow = 0;
  • datetime       g_BoxStartTime = 0, g_BoxEndTime = 0;
  • bool           g_BoxValid = false;
  • double         g_MartingaleArray[];
  • datetime       g_LastAddTime = 0;
  • int            g_AddCount = 0;
  • double         g_MonitorLevel = 0, g_PeakProfit = 0;
  • bool           g_IsMonitoring = false;
  • string         g_UIPrefix = "LXF_UI_";
  • datetime       g_LastLogTime = 0;
  • //+------------------------------------------------------------------+
  • //| 初始化                                                            |
  • //+------------------------------------------------------------------+
  • int OnInit()
  • {
  •    g_Symbol = Symbol();
  •    Print("✅ EA运行品种: ", g_Symbol);
  •    if(!ParseMartingaleSeries(InpMartingaleSeries, g_MartingaleArray))
  •    {
  •       Print("错误: 倍投序列格式错误!");
  •       return INIT_FAILED;
  •    }
  •    CreateUI();
  •    return INIT_SUCCEEDED;
  • }
  • //+------------------------------------------------------------------+
  • //| 反初始化                                                          |
  • //+------------------------------------------------------------------+
  • void OnDeinit(const int reason)
  • {
  •    ObjectsDeleteAll(0, g_UIPrefix);
  •    ObjectsDeleteAll(0, "LXF_BOX_");
  • }
  • //+------------------------------------------------------------------+
  • //| Tick                                                              |
  • //+------------------------------------------------------------------+
  • void OnTick()
  • {
  •    static bool firstRun = true;
  •    if(firstRun)
  •    {
  •       UpdateBox();
  •       ChartRedraw(0);
  •       firstRun = false;
  •    }
  •    UpdateUI();
  •    static datetime lastBarTime = 0;
  •    datetime currentBarTime = iTime(g_Symbol, InpBoxTimeframe, 0);
  •    if(currentBarTime != lastBarTime)
  •    {
  •       UpdateBox();
  •       ChartRedraw(0);
  •       lastBarTime = currentBarTime;
  •    }
  •    if(InpEnableReverseClose)
  •       CheckReverseClose();
  •    CheckDynamicTakeProfit();
  •    CheckHardSLTP();
  •    CheckTradeConditions();
  •    if(TimeCurrent() - g_LastLogTime >= 10)
  •    {
  •       LogStatus();
  •       g_LastLogTime = TimeCurrent();
  •    }
  • }
  • //+------------------------------------------------------------------+
  • //| 箱体绘制(标签移至右上角)                                        |
  • //+------------------------------------------------------------------+
  • void UpdateBox()
  • {
  •    MqlRates rates[];
  •    int copied = CopyRates(g_Symbol, InpBoxTimeframe, 0, InpBoxBars, rates);
  •    if(copied < InpBoxBars)
  •    {
  •       Print("箱体更新失败:K线数量不足,需要 ", InpBoxBars, " 根,实际获取 ", copied);
  •       g_BoxValid = false;
  •       return;
  •    }
  •    double high = rates[0].high, low = rates[0].low;
  •    datetime startTime = rates[0].time, endTime = rates[copied-1].time;
  •    for(int i = 1; i < copied; i++)
  •    {
  •       if(rates.high > high) high = rates.high;
  •       if(rates.low < low) low = rates.low;
  •    }
  •    g_BoxHigh = high;
  •    g_BoxLow = low;
  •    g_BoxStartTime = startTime;
  •    g_BoxEndTime = endTime;
  •    g_BoxValid = true;
  •    Print("箱体更新成功: 高点=", DoubleToString(high, _Digits),
  •          " 低点=", DoubleToString(low, _Digits),
  •          " 时间范围=", TimeToString(startTime), " ~ ", TimeToString(endTime));
  •    string boxName = "LXF_BOX_MAIN";
  •    ObjectDelete(0, boxName);
  •    ObjectDelete(0, boxName + "_FILL");
  •    if(ObjectCreate(0, boxName + "_FILL", OBJ_RECTANGLE, 0, startTime, high, endTime, low))
  •    {
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_FILL, true);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_COLOR, clrDodgerBlue);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_STYLE, STYLE_SOLID);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_WIDTH, 1);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_BACK, true);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_SELECTABLE, false);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_HIDDEN, false);
  •       ObjectSetInteger(0, boxName + "_FILL", OBJPROP_ZORDER, 0);
  •    }
  •    ObjectCreate(0, boxName + "_TOP", OBJ_HLINE, 0, 0, high);
  •    ObjectSetInteger(0, boxName + "_TOP", OBJPROP_COLOR, clrRed);
  •    ObjectSetInteger(0, boxName + "_TOP", OBJPROP_STYLE, STYLE_SOLID);
  •    ObjectSetInteger(0, boxName + "_TOP", OBJPROP_WIDTH, 2);
  •    ObjectSetInteger(0, boxName + "_TOP", OBJPROP_BACK, false);
  •    ObjectCreate(0, boxName + "_BOTTOM", OBJ_HLINE, 0, 0, low);
  •    ObjectSetInteger(0, boxName + "_BOTTOM", OBJPROP_COLOR, clrLime);
  •    ObjectSetInteger(0, boxName + "_BOTTOM", OBJPROP_STYLE, STYLE_SOLID);
  •    ObjectSetInteger(0, boxName + "_BOTTOM", OBJPROP_WIDTH, 2);
  •    ObjectSetInteger(0, boxName + "_BOTTOM", OBJPROP_BACK, false);
  •    ObjectCreate(0, boxName + "_LEFT", OBJ_VLINE, 0, startTime, 0);
  •    ObjectSetInteger(0, boxName + "_LEFT", OBJPROP_COLOR, clrGray);
  •    ObjectSetInteger(0, boxName + "_LEFT", OBJPROP_STYLE, STYLE_DASH);
  •    ObjectSetInteger(0, boxName + "_LEFT", OBJPROP_WIDTH, 1);
  •    ObjectSetInteger(0, boxName + "_LEFT", OBJPROP_BACK, false);
  •    ObjectCreate(0, boxName + "_RIGHT", OBJ_VLINE, 0, endTime, 0);
  •    ObjectSetInteger(0, boxName + "_RIGHT", OBJPROP_COLOR, clrGray);
  •    ObjectSetInteger(0, boxName + "_RIGHT", OBJPROP_STYLE, STYLE_DASH);
  •    ObjectSetInteger(0, boxName + "_RIGHT", OBJPROP_WIDTH, 1);
  •    ObjectSetInteger(0, boxName + "_RIGHT", OBJPROP_BACK, false);
  •    // ===== 箱体高点/低点标签 → 移至右上角 =====
  •    string labelHigh = boxName + "_LABEL_H";
  •    string labelLow = boxName + "_LABEL_L";
  •    // 删除旧标签(避免残留)
  •    ObjectDelete(0, labelHigh);
  •    ObjectDelete(0, labelLow);
  •    // 创建新标签,锚点设为右上角
  •    ObjectCreate(0, labelHigh, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, labelHigh, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);   // 右上角锚点
  •    ObjectSetInteger(0, labelHigh, OBJPROP_XDISTANCE, 10);                // 距右边缘10像素
  •    ObjectSetInteger(0, labelHigh, OBJPROP_YDISTANCE, 30);                // 距上边缘30像素
  •    ObjectSetString(0, labelHigh, OBJPROP_TEXT, "箱体高点: " + DoubleToString(high, _Digits));
  •    ObjectSetInteger(0, labelHigh, OBJPROP_COLOR, clrRed);
  •    ObjectSetInteger(0, labelHigh, OBJPROP_FONTSIZE, 9);
  •    ObjectSetString(0, labelHigh, OBJPROP_FONT, "Arial");
  •    ObjectSetInteger(0, labelHigh, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, labelHigh, OBJPROP_SELECTABLE, false);
  •    ObjectCreate(0, labelLow, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, labelLow, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
  •    ObjectSetInteger(0, labelLow, OBJPROP_XDISTANCE, 10);
  •    ObjectSetInteger(0, labelLow, OBJPROP_YDISTANCE, 50);                // 第二行,与高点间隔20像素
  •    ObjectSetString(0, labelLow, OBJPROP_TEXT, "箱体低点: " + DoubleToString(low, _Digits));
  •    ObjectSetInteger(0, labelLow, OBJPROP_COLOR, clrLime);
  •    ObjectSetInteger(0, labelLow, OBJPROP_FONTSIZE, 9);
  •    ObjectSetString(0, labelLow, OBJPROP_FONT, "Arial");
  •    ObjectSetInteger(0, labelLow, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, labelLow, OBJPROP_SELECTABLE, false);
  •    ChartRedraw(0);
  • }
  • //+------------------------------------------------------------------+
  • //| 获取填充模式                                                      |
  • //+------------------------------------------------------------------+
  • int GetFillingMode()
  • {
  •    long fillingMode = SymbolInfoInteger(g_Symbol, SYMBOL_FILLING_MODE);
  •    if(fillingMode & SYMBOL_FILLING_FOK) return ORDER_FILLING_FOK;
  •    if(fillingMode & SYMBOL_FILLING_IOC) return ORDER_FILLING_IOC;
  •    return ORDER_FILLING_RETURN;
  • }
  • //+------------------------------------------------------------------+
  • //| 交易条件检查                                                      |
  • //+------------------------------------------------------------------+
  • void CheckTradeConditions()
  • {
  •    if(!g_BoxValid) return;
  •    double bid = SymbolInfoDouble(g_Symbol, SYMBOL_BID);
  •    double ask = SymbolInfoDouble(g_Symbol, SYMBOL_ASK);
  •    double point = SymbolInfoDouble(g_Symbol, SYMBOL_POINT);
  •    double tickValue = SymbolInfoDouble(g_Symbol, SYMBOL_TRADE_TICK_VALUE);
  •    double offsetPrice = InpShortOffset / tickValue * point;
  •    double shortTriggerPrice = g_BoxHigh - offsetPrice;
  •    double longTriggerPrice = g_BoxHigh + offsetPrice;
  •    int posCount = PositionsTotal();
  •    bool hasPosition = false, hasBuy = false, hasSell = false;
  •    double totalProfit = 0;
  •    for(int i = 0; i < posCount; i++)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •          {
  •             hasPosition = true;
  •             if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) hasBuy = true;
  •             else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) hasSell = true;
  •             totalProfit += PositionGetDouble(POSITION_PROFIT);
  •          }
  •    }
  •    if(!hasPosition)
  •    {
  •       if(bid <= shortTriggerPrice)
  •       {
  •          OpenPosition(ORDER_TYPE_SELL, g_MartingaleArray[0]);
  •          g_AddCount = 1;
  •          g_LastAddTime = TimeCurrent();
  •          return;
  •       }
  •       if(ask >= longTriggerPrice)
  •       {
  •          OpenPosition(ORDER_TYPE_BUY, g_MartingaleArray[0]);
  •          g_AddCount = 1;
  •          g_LastAddTime = TimeCurrent();
  •          return;
  •       }
  •    }
  •    else
  •    {
  •       if(totalProfit < 0)
  •       {
  •          if((TimeCurrent() - g_LastAddTime) < InpMinGapMinutes * 60) return;
  •          if(g_AddCount >= ArraySize(g_MartingaleArray)) return;
  •          if(hasSell && !hasBuy && ask >= shortTriggerPrice)
  •          {
  •             double lot = g_MartingaleArray[g_AddCount];
  •             OpenPosition(ORDER_TYPE_SELL, lot);
  •             g_AddCount++;
  •             g_LastAddTime = TimeCurrent();
  •             Print("空单加仓: 手数=", lot, " 次数=", g_AddCount);
  •          }
  •          else if(hasBuy && !hasSell && bid <= longTriggerPrice)
  •          {
  •             double lot = g_MartingaleArray[g_AddCount];
  •             OpenPosition(ORDER_TYPE_BUY, lot);
  •             g_AddCount++;
  •             g_LastAddTime = TimeCurrent();
  •             Print("多单加仓: 手数=", lot, " 次数=", g_AddCount);
  •          }
  •       }
  •    }
  • }
  • //+------------------------------------------------------------------+
  • //| 开仓                                                              |
  • //+------------------------------------------------------------------+
  • void OpenPosition(ENUM_ORDER_TYPE type, double lot)
  • {
  •    MqlTradeRequest request = {};
  •    MqlTradeResult result = {};
  •    request.action = TRADE_ACTION_DEAL;
  •    request.symbol = g_Symbol;
  •    request.volume = lot;
  •    request.type = type;
  •    request.deviation = 10;
  •    request.magic = g_MagicNumber;
  •    request.comment = g_EAComment;
  •    request.type_filling = GetFillingMode();
  •    request.price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(g_Symbol, SYMBOL_ASK) : SymbolInfoDouble(g_Symbol, SYMBOL_BID);
  •    if(!OrderSend(request, result))
  •       Print("开仓失败: ", result.retcode, " - ", result.comment);
  •    else
  •       Print("开仓成功: ", (type == ORDER_TYPE_BUY) ? "多" : "空", " 手数=", lot);
  • }
  • //+------------------------------------------------------------------+
  • //| 动态止盈                                                          |
  • //+------------------------------------------------------------------+
  • void CheckDynamicTakeProfit()
  • {
  •    double totalProfit = GetTotalProfit();
  •    if(totalProfit < InpMonitorStart)
  •    {
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •       return;
  •    }
  •    if(!g_IsMonitoring)
  •    {
  •       g_IsMonitoring = true;
  •       g_MonitorLevel = InpMonitorStart;
  •       g_PeakProfit = totalProfit;
  •       Print("动态止盈启动: 盈利=", totalProfit);
  •       return;
  •    }
  •    if(totalProfit > g_PeakProfit)
  •    {
  •       g_PeakProfit = totalProfit;
  •       int newLevel = (int)(g_PeakProfit / InpMonitorStep) * InpMonitorStep;
  •       if(newLevel > g_MonitorLevel)
  •       {
  •          g_MonitorLevel = newLevel;
  •          Print("动态止盈升级: 监控=", g_MonitorLevel);
  •       }
  •    }
  •    double drawback = (g_PeakProfit - totalProfit) / g_PeakProfit * 100;
  •    if(drawback >= InpDrawbackPercent && g_PeakProfit > 0)
  •    {
  •       Print("触发动态止盈: 峰值=", g_PeakProfit, " 当前=", totalProfit, " 回撤=", drawback, "%");
  •       CloseAllPositions();
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •    }
  • }
  • //+------------------------------------------------------------------+
  • //| 获取当前总盈利                                                    |
  • //+------------------------------------------------------------------+
  • double GetTotalProfit()
  • {
  •    double total = 0;
  •    for(int i = PositionsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •             total += PositionGetDouble(POSITION_PROFIT);
  •    }
  •    return total;
  • }
  • //+------------------------------------------------------------------+
  • //| 硬止损止盈                                                        |
  • //+------------------------------------------------------------------+
  • void CheckHardSLTP()
  • {
  •    double totalProfit = GetTotalProfit();
  •    if(totalProfit <= -InpHardStopLoss && InpHardStopLoss > 0)
  •    {
  •       Print("触发硬止损: ", totalProfit);
  •       CloseAllPositions();
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •    }
  •    if(totalProfit >= InpHardTakeProfit && InpHardTakeProfit > 0)
  •    {
  •       Print("触发硬止盈: ", totalProfit);
  •       CloseAllPositions();
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •    }
  • }
  • //+------------------------------------------------------------------+
  • //| 平仓所有                                                          |
  • //+------------------------------------------------------------------+
  • void CloseAllPositions()
  • {
  •    for(int i = PositionsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •       {
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •          {
  •             MqlTradeRequest request = {};
  •             MqlTradeResult result = {};
  •             request.action = TRADE_ACTION_DEAL;
  •             request.symbol = g_Symbol;
  •             request.volume = PositionGetDouble(POSITION_VOLUME);
  •             request.deviation = 10;
  •             request.magic = g_MagicNumber;
  •             request.comment = g_EAComment + "_close";
  •             request.type_filling = GetFillingMode();
  •             if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
  •             {
  •                request.type = ORDER_TYPE_SELL;
  •                request.price = SymbolInfoDouble(g_Symbol, SYMBOL_BID);
  •             }
  •             else
  •             {
  •                request.type = ORDER_TYPE_BUY;
  •                request.price = SymbolInfoDouble(g_Symbol, SYMBOL_ASK);
  •             }
  •             if(!OrderSend(request, result))
  •                Print("平仓失败: ", result.retcode);
  •          }
  •       }
  •    }
  • }
  • //+------------------------------------------------------------------+
  • //| 反转平仓(RSI)                                                   |
  • //+------------------------------------------------------------------+
  • void CheckReverseClose()
  • {
  •    double rsiBuffer[];
  •    ArraySetAsSeries(rsiBuffer, true);
  •    int rsiHandle = iRSI(g_Symbol, PERIOD_CURRENT, InpRSIPeriod, PRICE_CLOSE);
  •    if(rsiHandle == INVALID_HANDLE) return;
  •    if(CopyBuffer(rsiHandle, 0, 0, 3, rsiBuffer) < 3) { IndicatorRelease(rsiHandle); return; }
  •    bool hasBuy = false, hasSell = false;
  •    for(int i = PositionsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •          {
  •             if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) hasBuy = true;
  •             else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) hasSell = true;
  •          }
  •    }
  •    if(hasBuy && rsiBuffer[1] >= InpRSIOverbought && rsiBuffer[0] < InpRSIOverbought)
  •    {
  •       Print("RSI反转(超买下跌),平多");
  •       CloseAllPositions();
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •       IndicatorRelease(rsiHandle);
  •       return;
  •    }
  •    if(hasSell && rsiBuffer[1] <= InpRSIOversold && rsiBuffer[0] > InpRSIOversold)
  •    {
  •       Print("RSI反转(超卖上涨),平空");
  •       CloseAllPositions();
  •       g_IsMonitoring = false;
  •       g_MonitorLevel = 0;
  •       g_PeakProfit = 0;
  •       IndicatorRelease(rsiHandle);
  •       return;
  •    }
  •    IndicatorRelease(rsiHandle);
  • }
  • //+------------------------------------------------------------------+
  • //| 解析倍投序列                                                      |
  • //+------------------------------------------------------------------+
  • bool ParseMartingaleSeries(string series, double &output[])
  • {
  •    string parts[];
  •    ushort sep = ',';
  •    int count = StringSplit(series, sep, parts);
  •    if(count <= 0) return false;
  •    ArrayResize(output, count);
  •    for(int i = 0; i < count; i++)
  •    {
  •       StringTrimLeft(parts);
  •       StringTrimRight(parts);
  •       output = StringToDouble(parts);
  •       if(output <= 0) return false;
  •    }
  •    return true;
  • }
  • //+------------------------------------------------------------------+
  • //| UI创建(左上角仅文字,右上角箱体标签由UpdateBox管理)          |
  • //+------------------------------------------------------------------+
  • void CreateUI()
  • {
  •    // ========== 标题 LOGO(居中) ==========
  •    string titleName = g_UIPrefix + "TITLE";
  •    ObjectCreate(0, titleName, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, titleName, OBJPROP_ANCHOR, ANCHOR_CENTER);
  •    ObjectSetInteger(0, titleName, OBJPROP_XDISTANCE, 0);
  •    ObjectSetInteger(0, titleName, OBJPROP_YDISTANCE, 0);
  •    ObjectSetString(0, titleName, OBJPROP_TEXT, "★ 蓝小凡精准狙击 ★");
  •    ObjectSetInteger(0, titleName, OBJPROP_COLOR, clrGold);
  •    ObjectSetInteger(0, titleName, OBJPROP_FONTSIZE, 24);
  •    ObjectSetString(0, titleName, OBJPROP_FONT, "Arial Black");
  •    ObjectSetInteger(0, titleName, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, titleName, OBJPROP_SELECTABLE, false);
  •    ObjectSetInteger(0, titleName, OBJPROP_ZORDER, 100);
  •    // ========== 左上角信息(仅文字,无背景,无边框) ==========
  •    string posLabel = g_UIPrefix + "POS";
  •    ObjectCreate(0, posLabel, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, posLabel, OBJPROP_XDISTANCE, 15);
  •    ObjectSetInteger(0, posLabel, OBJPROP_YDISTANCE, 50);
  •    ObjectSetString(0, posLabel, OBJPROP_TEXT, "持仓: 0");
  •    ObjectSetInteger(0, posLabel, OBJPROP_COLOR, clrWhite);
  •    ObjectSetInteger(0, posLabel, OBJPROP_FONTSIZE, InpFontSize);
  •    ObjectSetString(0, posLabel, OBJPROP_FONT, "Arial");
  •    ObjectSetInteger(0, posLabel, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, posLabel, OBJPROP_SELECTABLE, false);
  •    string profitLabel = g_UIPrefix + "PROFIT";
  •    ObjectCreate(0, profitLabel, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, profitLabel, OBJPROP_XDISTANCE, 15);
  •    ObjectSetInteger(0, profitLabel, OBJPROP_YDISTANCE, 75);
  •    ObjectSetString(0, profitLabel, OBJPROP_TEXT, "当前盈利: $0.00");
  •    ObjectSetInteger(0, profitLabel, OBJPROP_COLOR, clrWhite);
  •    ObjectSetInteger(0, profitLabel, OBJPROP_FONTSIZE, InpFontSize);
  •    ObjectSetString(0, profitLabel, OBJPROP_FONT, "Arial");
  •    ObjectSetInteger(0, profitLabel, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, profitLabel, OBJPROP_SELECTABLE, false);
  •    string totalLabel = g_UIPrefix + "TOTAL";
  •    ObjectCreate(0, totalLabel, OBJ_LABEL, 0, 0, 0);
  •    ObjectSetInteger(0, totalLabel, OBJPROP_XDISTANCE, 15);
  •    ObjectSetInteger(0, totalLabel, OBJPROP_YDISTANCE, 100);
  •    ObjectSetString(0, totalLabel, OBJPROP_TEXT, "总计盈利: $0.00");
  •    ObjectSetInteger(0, totalLabel, OBJPROP_COLOR, clrWhite);
  •    ObjectSetInteger(0, totalLabel, OBJPROP_FONTSIZE, InpFontSize);
  •    ObjectSetString(0, totalLabel, OBJPROP_FONT, "Arial");
  •    ObjectSetInteger(0, totalLabel, OBJPROP_BACK, false);
  •    ObjectSetInteger(0, totalLabel, OBJPROP_SELECTABLE, false);
  •    ChartRedraw(0);
  • }
  • //+------------------------------------------------------------------+
  • //| UI更新(标题居中,数据刷新)                                      |
  • //+------------------------------------------------------------------+
  • void UpdateUI()
  • {
  •    // --- 1. 标题位置(始终居中) ---
  •    int chartWidth = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
  •    int chartHeight = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
  •    ObjectSetInteger(0, g_UIPrefix + "TITLE", OBJPROP_XDISTANCE, chartWidth / 2);
  •    ObjectSetInteger(0, g_UIPrefix + "TITLE", OBJPROP_YDISTANCE, chartHeight / 2);
  •    // --- 2. 持仓 ---
  •    int buyCount = 0, sellCount = 0;
  •    for(int i = PositionsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •          {
  •             if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) buyCount++;
  •             else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) sellCount++;
  •          }
  •    }
  •    ObjectSetString(0, g_UIPrefix + "POS", OBJPROP_TEXT, "持仓: 多" + IntegerToString(buyCount) + " 空" + IntegerToString(sellCount));
  •    // --- 3. 当前盈利 ---
  •    double profit = GetTotalProfit();
  •    string profitText = "当前盈利: [        DISCUZ_CODE_0        ]quot; + DoubleToString(profit, 2);
  •    ObjectSetString(0, g_UIPrefix + "PROFIT", OBJPROP_TEXT, profitText);
  •    ObjectSetInteger(0, g_UIPrefix + "PROFIT", OBJPROP_COLOR, (profit >= 0) ? clrLime : clrRed);
  •    
  •    // --- 4. 总计盈利 ---
  •    double totalProfit = GetHistoryProfit();
  •    string totalText = "总计盈利: [        DISCUZ_CODE_0        ]quot; + DoubleToString(totalProfit, 2);
  •    ObjectSetString(0, g_UIPrefix + "TOTAL", OBJPROP_TEXT, totalText);
  •    ObjectSetInteger(0, g_UIPrefix + "TOTAL", OBJPROP_COLOR, (totalProfit >= 0) ? clrLime : clrRed);
  • }
  • //+------------------------------------------------------------------+
  • //| 获取历史总计盈利                                                  |
  • //+------------------------------------------------------------------+
  • double GetHistoryProfit()
  • {
  •    double total = 0;
  •    HistorySelect(0, TimeCurrent());
  •    for(int i = HistoryDealsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = HistoryDealGetTicket(i);
  •       if(HistoryDealGetString(ticket, DEAL_SYMBOL) == g_Symbol &&
  •          HistoryDealGetInteger(ticket, DEAL_MAGIC) == g_MagicNumber)
  •          total += HistoryDealGetDouble(ticket, DEAL_PROFIT);
  •    }
  •    return total;
  • }
  • //+------------------------------------------------------------------+
  • //| 实时状态输出(专家栏)                                           |
  • //+------------------------------------------------------------------+
  • void LogStatus()
  • {
  •    string status = "========== 蓝小凡精准狙击 状态 ==========";
  •    status += "\n品种: " + g_Symbol;
  •    status += "\n箱体有效: " + (g_BoxValid ? "是" : "否") +
  •              (g_BoxValid ? (" 高点=" + DoubleToString(g_BoxHigh, _Digits) +
  •                             " 低点=" + DoubleToString(g_BoxLow, _Digits)) : "");
  •    status += "\n当前浮动盈利: [        DISCUZ_CODE_0        ]quot; + DoubleToString(GetTotalProfit(), 2);
  •    status += "\n硬止损: [        DISCUZ_CODE_0        ]quot; + DoubleToString(InpHardStopLoss, 2) +
  •              "  硬止盈: [        DISCUZ_CODE_0        ]quot; + DoubleToString(InpHardTakeProfit, 2);
  •    status += "\n动态止盈监控: " + (g_IsMonitoring ? "开启" : "关闭") +
  •              (g_IsMonitoring ? (" 监控阈值=" + DoubleToString(g_MonitorLevel, 2) +
  •                                 " 峰值=" + DoubleToString(g_PeakProfit, 2)) : "");
  •    
  •    int buyCount = 0, sellCount = 0;
  •    double buyVol = 0, sellVol = 0;
  •    for(int i = PositionsTotal()-1; i >= 0; i--)
  •    {
  •       ulong ticket = PositionGetTicket(i);
  •       if(PositionSelectByTicket(ticket))
  •          if(PositionGetString(POSITION_SYMBOL) == g_Symbol && PositionGetInteger(POSITION_MAGIC) == g_MagicNumber)
  •          {
  •             if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
  •             { buyCount++; buyVol += PositionGetDouble(POSITION_VOLUME); }
  •             else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
  •             { sellCount++; sellVol += PositionGetDouble(POSITION_VOLUME); }
  •          }
  •    }
  •    status += "\n持仓: 多" + IntegerToString(buyCount) + "手(" + DoubleToString(buyVol, 2) +
  •              ") 空" + IntegerToString(sellCount) + "手(" + DoubleToString(sellVol, 2) + ")";
  •    status += "\n加仓次数: " + IntegerToString(g_AddCount) +
  •              "  上次加仓间隔: " + IntegerToString((int)((TimeCurrent()-g_LastAddTime)/60)) + " 分钟";
  •    status += "\n==========================================";
  •    Print(status);
  • }
  • //+------------------------------------------------------------------+

=
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|量化魔方 ( 陕ICP备2025062059号-3 )|网站地图

GMT+8, 2026-9-18 01:22 , Processed in 0.160089 second(s), 5 queries , Redis On.

快速回复 返回顶部 返回列表