- //+------------------------------------------------------------------+
- //| 蓝小凡精准狙击.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[i].high > high) high = rates[i].high;
- if(rates[i].low < low) low = rates[i].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[i]);
- StringTrimRight(parts[i]);
- output[i] = StringToDouble(parts[i]);
- if(output[i] <= 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);
- }
- //+------------------------------------------------------------------+
复制代码
|