黄金1H。100刀起步
- //+------------------------------------------------------------------+
- //| 波段突破策略.mq5 |
- //| v6.1 Pivot局部高低点突破 + 动态刷新压力支撑位 |
- //+------------------------------------------------------------------+
- #property copyright "Swing Breakout Strategy"
- #property version "6.10"
-
- #include <Trade\Trade.mqh>
- CTrade trade;
-
- //+------------------------------------------------------------------+
- //| 参数 |
- //+------------------------------------------------------------------+
- input int PivotLeft = 5; // 左侧K线数(找波段高/低点)
- input int PivotRight = 5; // 右侧K线数
- input double SL_Points = 150; // 止损点数
- input double TP_Step = 50; // 止盈步进(点)
- input double RiskPercent = 1.0; // 每笔风险%
- input int MagicNumber = 8888;
- input int Slippage = 3;
- input string TradeComment = "Swing";
- input bool EnableLong = true;
- input bool EnableShort = true;
- input int ConfirmBars = 1; // 突破确认K线数
-
- //+------------------------------------------------------------------+
- double g_point;
- datetime g_lastBar = 0;
- double g_entryPrice = 0;
-
- double g_swingHigh = 0;
- double g_swingLow = 0;
- bool g_levelsValid = false;
-
- datetime g_lastSignalBar = 0;
- int g_tpSteps = 0;
- int g_cooldownBars = 0;
- int g_breakoutConfirm = 0;
-
- //+------------------------------------------------------------------+
- //| 初始化 |
- //+------------------------------------------------------------------+
- int OnInit()
- {
- trade.SetExpertMagicNumber(MagicNumber);
- trade.SetDeviationInPoints(Slippage);
- trade.SetTypeFillingBySymbol(_Symbol);
-
- g_point = _Point;
- if(_Digits == 3 || _Digits == 5) g_point *= 10;
-
- g_cooldownBars = 0;
- g_levelsValid = false;
- g_breakoutConfirm = 0;
-
- Print("波段突破 v6.0 | Pivot(", PivotLeft, ",", PivotRight, ") 止损:", SL_Points, "点 步进:", TP_Step, "点");
- return INIT_SUCCEEDED;
- }
-
- //+------------------------------------------------------------------+
- void OnDeinit(const int reason)
- {
- if(ObjectFind(0, "Swing_High") >= 0) ObjectDelete(0, "Swing_High");
- if(ObjectFind(0, "Swing_Low") >= 0) ObjectDelete(0, "Swing_Low");
- Comment("");
- }
-
- //+------------------------------------------------------------------+
- //| 找最近的波段高点(pivot high: 比左右都高) |
- //+------------------------------------------------------------------+
- double FindRecentSwingHigh()
- {
- double high[];
- ArraySetAsSeries(high, true);
-
- // 扩大搜索范围到100根K线
- int searchRange = 100;
- int leftBars = PivotLeft;
- int rightBars = PivotRight;
- int needBars = searchRange + leftBars + rightBars;
-
- if(CopyHigh(_Symbol, PERIOD_CURRENT, 1, needBars, high) < needBars) return 0;
-
- // 从近到远搜索,找到第一个有效的pivot high
- for(int start = rightBars; start < needBars - leftBars; start++)
- {
- bool isPivot = true;
- for(int l = 1; l <= leftBars; l++)
- {
- if(high[start+l] >= high[start]) { isPivot = false; break; }
- }
- if(!isPivot) continue;
- for(int r = 1; r <= rightBars; r++)
- {
- if(high[start-r] >= high[start]) { isPivot = false; break; }
- }
- if(isPivot)
- {
- Print("找到波段高点 #", start, " 价格:", high[start]);
- return high[start];
- }
- }
-
- // 找不到pivot就用最近N根K线的最高价
- double maxH = 0;
- int lookback = MathMin(50, needBars);
- for(int i = 1; i < lookback; i++)
- {
- if(high[i] > maxH) maxH = high[i];
- }
- return maxH > 0 ? maxH : high[1];
- }
-
- //+------------------------------------------------------------------+
- //| 找最近的波段低点(pivot low: 比左右都低) |
- //+------------------------------------------------------------------+
- double FindRecentSwingLow()
- {
- double low[];
- ArraySetAsSeries(low, true);
-
- int searchRange = 100;
- int leftBars = PivotLeft;
- int rightBars = PivotRight;
- int needBars = searchRange + leftBars + rightBars;
-
- if(CopyLow(_Symbol, PERIOD_CURRENT, 1, needBars, low) < needBars) return 0;
-
- for(int start = rightBars; start < needBars - leftBars; start++)
- {
- bool isPivot = true;
- for(int l = 1; l <= leftBars; l++)
- {
- if(low[start+l] <= low[start]) { isPivot = false; break; }
- }
- if(!isPivot) continue;
- for(int r = 1; r <= rightBars; r++)
- {
- if(low[start-r] <= low[start]) { isPivot = false; break; }
- }
- if(isPivot)
- {
- Print("找到波段低点 #", start, " 价格:", low[start]);
- return low[start];
- }
- }
-
- // 找不到pivot就用最近N根K线的最低价
- double minL = DBL_MAX;
- int lookback = MathMin(50, needBars);
- for(int i = 1; i < lookback; i++)
- {
- if(low[i] < minL) minL = low[i];
- }
- return minL < DBL_MAX ? minL : low[1];
- }
-
- //+------------------------------------------------------------------+
- //| 更新压力/支撑位(持仓时也要定期更新) |
- //+------------------------------------------------------------------+
- bool CalcLevels()
- {
- double sh = FindRecentSwingHigh();
- double sl = FindRecentSwingLow();
-
- if(sh > 0 && sl > 0 && sh > sl)
- {
- g_swingHigh = sh;
- g_swingLow = sl;
- g_levelsValid = true;
- return true;
- }
- return false;
- }
-
- //+------------------------------------------------------------------+
- //| 检查是否需要刷新压力/支撑位 |
- //+------------------------------------------------------------------+
- void CheckRefreshLevels()
- {
- if(!g_levelsValid)
- {
- CalcLevels();
- return;
- }
-
- // 价格已经远离当前区间,需要重新计算
- double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
- if(bid <= 0) return;
-
- bool farAbove = (bid > g_swingHigh + g_point * 50); // 远离压力位50点以上
- bool farBelow = (bid < g_swingLow - g_point * 50); // 远离支撑位50点以上
-
- if(farAbove || farBelow)
- {
- Print("价格远离当前区间,刷新压力支撑位");
- g_levelsValid = false;
- CalcLevels();
- }
- }
-
- //+------------------------------------------------------------------+
- void ResetAfterClose()
- {
- g_entryPrice = 0;
- g_tpSteps = 0;
- g_levelsValid = false;
- g_cooldownBars = 10;
- g_breakoutConfirm = 0;
- }
-
- //+------------------------------------------------------------------+
- void OnTick()
- {
- MqlRates rates[];
- ArraySetAsSeries(rates, true);
- if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 3, rates) < 3) return;
-
- bool isNewBar = (rates[0].time != g_lastBar);
-
- if(!isNewBar)
- {
- int posType = GetPositionType();
- if(posType != 0) CheckTPStep(rates);
- return;
- }
- g_lastBar = rates[0].time;
-
- double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
- double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
- if(ask <= 0 || bid <= 0 || ask == bid) return;
-
- int posType = GetPositionType();
-
- // 检测持仓是否刚被止损
- if(posType == 0 && g_entryPrice > 0)
- {
- Print(">>>检测止损平仓<<< 重置状态");
- ResetAfterClose();
- UpdateDashboard();
- return;
- }
-
- // 持仓中
- if(posType != 0)
- {
- CheckTPStep(rates);
- UpdateDashboard();
- return;
- }
-
- // 冷却期
- if(g_cooldownBars > 0)
- {
- g_cooldownBars--;
- UpdateDashboard();
- return;
- }
-
- // 动态计算/刷新压力/支撑位
- CheckRefreshLevels();
- if(!g_levelsValid)
- {
- UpdateDashboard();
- return;
- }
-
- // 每根新K线都重绘
- DrawLevelLines(g_swingHigh, g_swingLow);
-
- double prevClose = rates[1].close;
-
- static int dbg = 0;
- if(dbg < 15)
- {
- Print("信号[", dbg, "] 收盘:", DoubleToString(prevClose, _Digits),
- " 压力:", DoubleToString(g_swingHigh, _Digits),
- " 支撑:", DoubleToString(g_swingLow, _Digits),
- " 突破压力:", (prevClose > g_swingHigh),
- " 跌破支撑:", (prevClose < g_swingLow));
- dbg++;
- }
-
- bool above = (prevClose > g_swingHigh);
- bool below = (prevClose < g_swingLow);
-
- if(!above && !below)
- {
- g_breakoutConfirm = 0;
- }
- else if(above && g_lastSignalBar != rates[1].time)
- {
- if(g_breakoutConfirm <= 0) g_breakoutConfirm = 1;
- else g_breakoutConfirm++;
- }
- else if(below && g_lastSignalBar != rates[1].time)
- {
- if(g_breakoutConfirm >= 0) g_breakoutConfirm = -1;
- else g_breakoutConfirm--;
- }
-
- if(EnableLong && g_breakoutConfirm >= ConfirmBars)
- {
- double lot = CalcLot();
- double slPrice = ask - SL_Points * g_point;
- if(trade.Buy(lot, _Symbol, ask, slPrice, 0, TradeComment))
- {
- g_entryPrice = ask;
- g_tpSteps = 0;
- g_lastSignalBar = rates[1].time;
- g_breakoutConfirm = 0;
- Print(">>>突破做多<<< 压力:", DoubleToString(g_swingHigh, _Digits),
- " 入场:", ask, " 止损:", slPrice, " 手数:", lot);
- }
- else Print("做多失败: ", trade.ResultRetcodeDescription());
- }
- else if(EnableShort && g_breakoutConfirm <= -ConfirmBars)
- {
- double lot = CalcLot();
- double slPrice = bid + SL_Points * g_point;
- if(trade.Sell(lot, _Symbol, bid, slPrice, 0, TradeComment))
- {
- g_entryPrice = bid;
- g_tpSteps = 0;
- g_lastSignalBar = rates[1].time;
- g_breakoutConfirm = 0;
- Print(">>>跌破做空<<< 支撑:", DoubleToString(g_swingLow, _Digits),
- " 入场:", bid, " 止损:", slPrice, " 手数:", lot);
- }
- else Print("做空失败: ", trade.ResultRetcodeDescription());
- }
-
- UpdateDashboard();
- }
-
- //+------------------------------------------------------------------+
- double CalcLot()
- {
- double equity = AccountInfoDouble(ACCOUNT_EQUITY);
- double riskAmount = equity * RiskPercent / 100.0;
- double slDistance = SL_Points * g_point;
-
- double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
- double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
- if(tickValue <= 0 || tickSize <= 0) return 0.01;
-
- double dollarPerPoint = tickValue / tickSize;
- double lot = riskAmount / (slDistance * dollarPerPoint);
-
- double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
- double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
- double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
-
- if(lot < minLot) lot = minLot;
- if(lot > maxLot) lot = maxLot;
- lot = MathFloor(lot / step) * step;
- return lot;
- }
-
- //+------------------------------------------------------------------+
- int GetPositionType()
- {
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong tk = PositionGetTicket(i);
- if(!PositionSelectByTicket(tk)) continue;
- if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
- if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
- return (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? 1 : -1;
- }
- return 0;
- }
-
- //+------------------------------------------------------------------+
- void CloseAll()
- {
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong tk = PositionGetTicket(i);
- if(!PositionSelectByTicket(tk)) continue;
- if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
- if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
- trade.PositionClose(tk);
- }
- }
-
- //+------------------------------------------------------------------+
- void DrawLevelLines(double high, double low)
- {
- static double prevH = 0, prevL = 0;
- double tol = g_point * 5;
- if(MathAbs(high - prevH) < tol && MathAbs(low - prevL) < tol) return;
-
- prevH = high;
- prevL = low;
-
- if(ObjectFind(0, "Swing_High") >= 0) ObjectDelete(0, "Swing_High");
- if(ObjectFind(0, "Swing_Low") >= 0) ObjectDelete(0, "Swing_Low");
-
- ObjectCreate(0, "Swing_High", OBJ_HLINE, 0, 0, high);
- ObjectSetInteger(0, "Swing_High", OBJPROP_COLOR, clrRed);
- ObjectSetInteger(0, "Swing_High", OBJPROP_STYLE, STYLE_SOLID);
- ObjectSetInteger(0, "Swing_High", OBJPROP_WIDTH, 2);
- ObjectSetInteger(0, "Swing_High", OBJPROP_SELECTABLE, false);
- ObjectSetInteger(0, "Swing_High", OBJPROP_BACK, true);
-
- ObjectCreate(0, "Swing_Low", OBJ_HLINE, 0, 0, low);
- ObjectSetInteger(0, "Swing_Low", OBJPROP_COLOR, clrBlue);
- ObjectSetInteger(0, "Swing_Low", OBJPROP_STYLE, STYLE_SOLID);
- ObjectSetInteger(0, "Swing_Low", OBJPROP_WIDTH, 2);
- ObjectSetInteger(0, "Swing_Low", OBJPROP_SELECTABLE, false);
- ObjectSetInteger(0, "Swing_Low", OBJPROP_BACK, true);
- }
-
- //+------------------------------------------------------------------+
- void CheckTPStep(MqlRates &rates[])
- {
- int posType = GetPositionType();
- if(posType == 0)
- {
- ResetAfterClose();
- return;
- }
-
- double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
- double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
-
- double currentProfit = 0;
- int posCount = 0;
- double openPrice = 0;
-
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong tk = PositionGetTicket(i);
- if(!PositionSelectByTicket(tk)) continue;
- if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
- if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
-
- currentProfit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
- openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
- posCount++;
- }
-
- if(posCount == 0) return;
-
- double profitPoints = 0;
- if(posType == 1)
- profitPoints = (bid - openPrice) / g_point;
- else
- profitPoints = (openPrice - ask) / g_point;
-
- if(profitPoints <= -SL_Points)
- {
- Print(">>>止损触发<<< 亏损:[ DISCUZ_CODE_0 ]quot;, DoubleToString(currentProfit, 2));
- CloseAll();
- ResetAfterClose();
- return;
- }
-
- int targetSteps = (int)(profitPoints / TP_Step);
- if(targetSteps > g_tpSteps && targetSteps > 0)
- {
- g_tpSteps = targetSteps;
- double newSL = 0;
- if(posType == 1)
- newSL = openPrice + (g_tpSteps - 1) * TP_Step * g_point;
- else
- newSL = openPrice - (g_tpSteps - 1) * TP_Step * g_point;
-
- for(int i = PositionsTotal() - 1; i >= 0; i--)
- {
- ulong tk = PositionGetTicket(i);
- if(!PositionSelectByTicket(tk)) continue;
- if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
- if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
-
- double curSL = PositionGetDouble(POSITION_SL);
- if(posType == 1 && (newSL > curSL || curSL == 0))
- trade.PositionModify(tk, newSL, 0);
- else if(posType == -1 && (newSL < curSL || curSL == 0))
- trade.PositionModify(tk, newSL, 0);
- }
-
- Print(">>>止盈步进<<< 第", g_tpSteps, "步 新止损:", DoubleToString(newSL, _Digits), " 盈利:[ DISCUZ_CODE_0 ]quot;, DoubleToString(currentProfit, 2));
- }
- }
-
- //+------------------------------------------------------------------+
- void UpdateDashboard()
- {
- double eq = AccountInfoDouble(ACCOUNT_EQUITY);
- double bal = AccountInfoDouble(ACCOUNT_BALANCE);
- int posType = GetPositionType();
- string dirStr = (posType == 1) ? "多" : (posType == -1) ? "空" : "无";
-
- string s = "═══ 波段突破 v6.1 ══\n";
- s += "Balance [ DISCUZ_CODE_0 ]quot; + DoubleToString(bal, 2) + " Equity [ DISCUZ_CODE_0 ]quot; + DoubleToString(eq, 2) + "\n";
- s += "方向: " + dirStr + " 止盈步进: " + IntegerToString(g_tpSteps);
- if(g_cooldownBars > 0) s += " 冷却: " + IntegerToString(g_cooldownBars) + "根";
- if(g_breakoutConfirm != 0) s += " 突破计数: " + IntegerToString(MathAbs(g_breakoutConfirm));
- s += "\n压力: " + DoubleToString(g_swingHigh, _Digits) + " 支撑: " + DoubleToString(g_swingLow, _Digits) + "\n";
- s += "Pivot(" + IntegerToString(PivotLeft) + "," + IntegerToString(PivotRight) + ") 止损: " + DoubleToString(SL_Points, 0) + "点 步进: " + DoubleToString(TP_Step, 0) + "点";
-
- if(posType != 0 && g_entryPrice > 0)
- s += "\n开仓: " + DoubleToString(g_entryPrice, _Digits);
-
- Comment(s);
- }
- //+------------------------------------------------------------------+
复制代码 [/codebuy] |