- //+------------------------------------------------------------------+
- //| 金手指 v7 稳定版 |
- //| H1方向 + M5入场 + 缓冲止损 + 1:2半平 + 微利推保 |
- //+------------------------------------------------------------------+
- #property version "7.2"
- #property strict
-
- #include <Trade/Trade.mqh>
- CTrade trade;
-
- //==== 参数 ====
- input double LotSize = 0.01;
- input int MA_Period = 20;
- input double RR_Ratio = 2.0;
- input int MagicNumber = 888888;
- input int MaxSpread = 50;
- input int Slippage = 10;
- input double SL_Buffer = 50;
- input double Trail_Profit_Level = 0.3;
- input bool Use_ADX_Filter = true;
- input int ADX_Period = 14;
- input double ADX_Level = 25;
-
- //==== 指标句柄 ====
- int hMA_H1 = INVALID_HANDLE;
- int hMA_M5 = INVALID_HANDLE;
- int hADX = INVALID_HANDLE;
-
- //==== 新K线门控 ====
- datetime g_lastM5BarTime = 0;
-
- //+------------------------------------------------------------------+
- int OnInit()
- {
- trade.SetExpertMagicNumber(MagicNumber);
- trade.SetDeviationInPoints(Slippage);
-
- hMA_H1 = iMA(_Symbol, PERIOD_H1, MA_Period, 0, MODE_SMA, PRICE_CLOSE);
- hMA_M5 = iMA(_Symbol, PERIOD_M5, MA_Period, 0, MODE_SMA, PRICE_CLOSE);
- hADX = iADX(_Symbol, PERIOD_H1, ADX_Period);
-
- if(hMA_H1 == INVALID_HANDLE || hMA_M5 == INVALID_HANDLE || (Use_ADX_Filter && hADX == INVALID_HANDLE))
- {
- Print("指标句柄创建失败");
- return INIT_FAILED;
- }
-
- MqlRates r[];
- ArraySetAsSeries(r, true);
- if(CopyRates(_Symbol, PERIOD_M5, 0, 1, r) > 0)
- g_lastM5BarTime = r[0].time;
-
- Print("金手指 v7.2 初始化成功");
- return INIT_SUCCEEDED;
- }
-
- //+------------------------------------------------------------------+
- void OnDeinit(const int reason)
- {
- if(hMA_H1 != INVALID_HANDLE) IndicatorRelease(hMA_H1);
- if(hMA_M5 != INVALID_HANDLE) IndicatorRelease(hMA_M5);
- if(hADX != INVALID_HANDLE) IndicatorRelease(hADX);
- }
-
- //+------------------------------------------------------------------+
- // 安全的K线数据获取:返回 true 表示成功取到
- bool GetOHLC(ENUM_TIMEFRAMES tf, int shift, MqlRates &out[])
- {
- ArraySetAsSeries(out, true);
- return (CopyRates(_Symbol, tf, shift, 1, out) > 0);
- }
-
- // 取单值指标缓冲
- bool GetIndicatorValue(int handle, double &value)
- {
- double buf[1];
- ArraySetAsSeries(buf, true);
- if(CopyBuffer(handle, 0, 0, 1, buf) <= 0)
- return false;
- value = buf[0];
- return true;
- }
-
- bool IsNewM5Bar()
- {
- MqlRates r[];
- if(!GetOHLC(PERIOD_M5, 0, r)) return false;
- if(r[0].time != g_lastM5BarTime)
- {
- g_lastM5BarTime = r[0].time;
- return true;
- }
- return false;
- }
-
- //+------------------------------------------------------------------+
- void OnTick()
- {
- if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return;
- if(!MQLInfoInteger(MQL_TRADE_ALLOWED)) return;
-
- long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
- if(spread > MaxSpread) return;
-
- ManagePositions();
-
- if(PositionsTotal() == 0 && IsNewM5Bar())
- CheckOpen();
- }
-
- //+------------------------------------------------------------------+
- void CheckOpen()
- {
- double maH1, maM5;
- if(!GetIndicatorValue(hMA_H1, maH1)) return;
- if(!GetIndicatorValue(hMA_M5, maM5)) return;
-
- if(Use_ADX_Filter)
- {
- double adx;
- if(!GetIndicatorValue(hADX, adx)) return;
- if(adx < ADX_Level) return;
- }
-
- MqlRates h1[], m5[];
- if(!GetOHLC(PERIOD_H1, 1, h1)) return;
- if(!GetOHLC(PERIOD_M5, 1, m5)) return;
-
- double h1_close = h1[0].close;
- double m5_close = m5[0].close;
-
- double vol = NormalizeLot(LotSize);
- long stopsLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
- double minDist = (double)stopsLevel * _Point;
-
- // 多
- if(h1_close > maH1 && m5_close > maM5)
- {
- double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
- double sl = h1[0].low - SL_Buffer * _Point;
- if(ask - sl < minDist) sl = ask - minDist;
- double risk = ask - sl;
- double tp = ask + risk * RR_Ratio;
-
- trade.Buy(vol, _Symbol, ask, sl, tp, "JF_Long");
- Print("开多 retcode=", trade.ResultRetcode());
- }
- // 空
- else if(h1_close < maH1 && m5_close < maM5)
- {
- double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
- double sl = h1[0].high + SL_Buffer * _Point;
- if(sl - bid < minDist) sl = bid + minDist;
- double risk = sl - bid;
- double tp = bid - risk * RR_Ratio;
-
- trade.Sell(vol, _Symbol, bid, sl, tp, "JF_Short");
- Print("开空 retcode=", trade.ResultRetcode());
- }
- }
-
- //+------------------------------------------------------------------+
- void ManagePositions()
- {
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong ticket = PositionGetTicket(i);
- if(ticket == 0) continue;
- if(!PositionSelectByTicket(ticket)) continue;
- if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
- if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
-
- long pos_type = PositionGetInteger(POSITION_TYPE);
- double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
- double sl_now = PositionGetDouble(POSITION_SL);
- double tp_now = PositionGetDouble(POSITION_TP);
- double vol_now = PositionGetDouble(POSITION_VOLUME);
-
- double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
- double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
-
- if(tp_now > 0)
- {
- bool hit = false;
- if(pos_type == POSITION_TYPE_BUY && ask >= tp_now) hit = true;
- if(pos_type == POSITION_TYPE_SELL && bid <= tp_now) hit = true;
-
- if(hit)
- {
- double half_vol = NormalizeLot(vol_now / 2.0);
- double volMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
- if(half_vol < volMin) half_vol = volMin;
-
- double risk = (pos_type == POSITION_TYPE_BUY) ? (open_price - sl_now) : (sl_now - open_price);
- double lock = risk * Trail_Profit_Level;
-
- double new_sl = (pos_type == POSITION_TYPE_BUY) ? (open_price + lock) : (open_price - lock);
-
- long stopsLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
- double minDist = (double)stopsLevel * _Point;
- if(pos_type == POSITION_TYPE_BUY && (ask - new_sl) < minDist) new_sl = ask - minDist;
- if(pos_type == POSITION_TYPE_SELL && (new_sl - bid) < minDist) new_sl = bid + minDist;
-
- trade.PositionModify(ticket, new_sl, 0);
- trade.PositionClosePartial(ticket, half_vol);
- Print("1.5R达成,半平并推保");
- }
- }
- }
- }
-
- //+------------------------------------------------------------------+
- double NormalizeLot(double lot)
- {
- double vMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
- double vMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
- double vStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
- lot = MathMax(lot, vMin);
- lot = MathMin(lot, vMax);
- if(vStep > 0) lot = MathRound(lot / vStep) * vStep;
- return lot;
- }
- //+------------------------------------------------------------------+
复制代码
|