
BGUSER-NXB07P6L
2025/08/10 16:53
5
//+------------------------------------------------------------------+
//| MartingalePyramid_DirSelect.mq5|
//| Grid by % from First Price + Dir Selection |
//+------------------------------------------------------------------+
#property copyright "OpenAI"
#property version "1.10"
#property strict
#include <Trade/Trade.mqh>
CTrade trade;
//=========================== 输入参数 ===============================//
input string InpSymbol = _Symbol; // 交易品种
enum DirOpt {LONG_ONLY=1, SHORT_ONLY=-1};
input DirOpt Direction = LONG_ONLY; // 初始方向(只做多或只做空)
input bool AutoStartIfNoPosition = true; // 无持仓自动开首单
// 加仓模式:仅不利方向、仅有利方向、双向(相对首单价的等距百分比层)
enum AddMode {ADVERSE_ONLY=0, FAVOR_ONLY=1, BOTH=2};
input AddMode AddingMode = FAVOR_ONLY; // 默认按你的需求:只在“有利方向”加仓
input double StartLots = 0.10; // 首单手数
input double LotMultiplier = 2.0; // 手数放大倍数(>=1)
input int MaxOrders = 10; // 最大总单数(1~10),含首单
input double StepPercent = 10.0; // 层距(%),相对首单价
input double MinEquityReservePercent = 30.0; // 净值预留比例(风控)
input double MaxVolume = 100.0; // 单符号最大总手数保护
input int DeviationPoints = 20; // 下单滑点(点)
input ulong Magic = 20250810; // 魔术号
// 平仓触发:固定“有利方向第 N 层”或“回到最后一笔加仓的价位”
input int CloseAtLevelIndex = 10; // 固定层(1~MaxOrders)
input bool CloseAtLastLayerPrice = true; // true=到“最后加仓价”即平全仓
//=========================== 全局/状态 ==============================//
#define GV_NS "MGv2::"
string gv_first_price, gv_adds_done, gv_direction, gv_last_added_price;
struct GridState {
double first_price; // 首单参考价
double last_added_price; // 最近一次加仓使用的价位(用于 CloseAtLastLayerPrice)
int adds_done; // 已加仓层数(不含首单)
int direction; // 1=多, -1=空
bool initialized;
} state;
string GVName(string key){ return StringFormat("%s%s[%s][%I64u]", GV_NS, key, InpSymbol, Magic); }
bool LoadState()
{
gv_first_price = GVName("first_price");
gv_adds_done = GVName("adds_done");
gv_direction = GVName("direction");
gv_last_added_price = GVName("last_added_price");
state.initialized=false;
if(GlobalVariableCheck(gv_first_price) && GlobalVariableCheck(gv_adds_done) &&
GlobalVariableCheck(gv_direction) && GlobalVariableCheck(gv_last_added_price))
{
state.first_price = GlobalVariableGet(gv_first_price);
state.adds_done = (int)GlobalVariableGet(gv_adds_done);
state.direction = (int)GlobalVariableGet(gv_direction);
state.last_added_price = GlobalVariableGet(gv_last_added_price);
state.initialized = true;
}
return state.initialized;
}
void SaveState()
{
if(!GlobalVariableCheck(gv_first_price)) GlobalVariableCreate(gv_first_price, TimeCurrent(),0);
if(!GlobalVariableCheck(gv_adds_done)) GlobalVariableCreate(gv_adds_done, TimeCurrent(),0);
if(!GlobalVariableCheck(gv_direction)) GlobalVariableCreate(gv_direction, TimeCurrent(),0);
if(!GlobalVariableCheck(gv_last_added_price)) GlobalVariableCreate(gv_last_added_price, TimeCurrent(),0);
GlobalVariableSet(gv_first_price, state.first_price);
GlobalVariableSet(gv_adds_done, (double)state.adds_done);
GlobalVariableSet(gv_direction, (double)state.direction);
GlobalVariableSet(gv_last_added_price, state.last_added_price);
}
void ResetState()
{
GlobalVariableDel(gv_first_price);
GlobalVariableDel(gv_adds_done);
GlobalVariableDel(gv_direction);
GlobalVariableDel(gv_last_added_price);
state = (GridState)0;
}
//--------------------------- 价格工具 -------------------------------//
double Bid(string s){ return SymbolInfoDouble(s, SYMBOL_BID); }
double Ask(string s){ return SymbolInfoDouble(s, SYMBOL_ASK); }
double Mid(string s){ return (Bid(s)+Ask(s))*0.5; }
double FavorLevelPrice(double first, int dir, int k, double stepPct)
{
double step = stepPct/100.0;
return (dir>0)? first*(1.0 + step*k) // 多:有利在上
: first*(1.0 - step*k); // 空:有利在下
}
double AdverseLevelPrice(double first, int dir, int k, double stepPct)
{
double step = stepPct/100.0;
return (dir>0)? first*(1.0 - step*k) // 多:不利在下
: first*(1.0 + step*k); // 空:不利在上
}
bool PriceCrossedFavor(double price_now, double target, int dir)
{
return (dir>0)? (price_now >= target) : (price_now <= target);
}
bool PriceCrossedAdverse(double price_now, double target, int dir)
{
return (dir>0)? (price_now <= target) : (price_now >= target);
}
//--------------------------- 下单工具 -------------------------------//
double TargetVolumeByAdds(int adds_done)
{
double vol=0.0;
for(int i=0;i<=adds_done;i++)
vol += StartLots * MathPow(MathMax(1.0, LotMultiplier), i);
return vol;
}
bool CanIncreaseVolume(string sym, ENUM_ORDER_TYPE ot, double target_total)
{
if(target_total > MaxVolume) return false;
double price = (ot==ORDER_TYPE_BUY)? Ask(sym) : Bid(sym);
double margin=0.0;
if(!OrderCalcMargin(ot, sym, target_total, price, margin)) return false;
double free_margin = AccountInfoDouble(ACCOUNT_FREEMARGIN);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
if(free_margin < margin) return false;
double reserve = equity*(MinEquityReservePercent/100.0);
if((free_margin - margin) < reserve) return false;
return true;
}
bool GetPosition(string sym, double &vol, double &avg, long &type)
{
vol=0; avg=0; type=-1;
if(!Positi PositionGetDouble(POSITION_VOLUME);
avg = PositionGetDouble(POSITION_PRICE_OPEN);
type = (long)PositionGetInteger(POSITION_TYPE);
return true;
}
bool IncreasePosition(string sym, int dir, double target_total, double exec_price_hint)
{
double vol, avg; long typ;
GetPosition(sym, vol, avg, typ);
double add = MathMax(0.0, target_total - vol);
if(add<=0.0) return true;
ENUM_ORDER_TYPE ot = (dir>0)? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
if(!CanIncreaseVolume(sym, ot, target_total)) return false;
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(DeviationPoints);
bool ok = (dir>0)? trade.Buy(add, sym) : trade.Sell(add, sym);
if(ok){
state.last_added_price = exec_price_hint; // 记录“最近加仓价位”
SaveState();
}
return ok;
}
bool CloseAllPositions(string sym)
{
if(!Positi trade.PositionClose(sym);
if(ok) ResetState();
return ok;
}
//============================== 事件 ================================//
int OnInit()
{
MaxOrders = (int)MathMax(1, MathMin(10, MaxOrders));
CloseAtLevelIndex = (int)MathMax(1, MathMin(MaxOrders, CloseAtLevelIndex));
StepPercent = MathMax(0.01, StepPercent);
LotMultiplier = MathMax(1.0, LotMultiplier);
StartLots = MathMax(SymbolInfoDouble(InpSymbol, SYMBOL_VOLUME_MIN), StartLots);
// 载入/继承状态(若已有仓位)
LoadState();
if(!state.initialized)
{
double v,a; long t;
if(PositiPositionGetDouble(POSITION_VOLUME);
a=PositionGetDouble(POSITION_PRICE_OPEN);
t=(long)PositionGetInteger(POSITION_TYPE);
if(v>0.0){
state.first_price = a;
state.last_added_price = a;
state.adds_done = 0;
state.direction = (t==POSITION_TYPE_BUY)? 1 : -1;
state.initialized = true;
SaveState();
}
}
}
return(INIT_SUCCEEDED);
}
void OnTick()
{
MqlTick tk;
if(!SymbolInfoTick(InpSymbol, tk)) return;
// 启动首单
if(!state.initialized)
{
if(!AutoStartIfNoPosition) return;
int dir = (int)Direction;
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(DeviationPoints);
bool ok = (dir>0)? trade.Buy(StartLots, InpSymbol) : trade.Sell(StartLots, InpSymbol);
if(!ok) return;
double fp = (dir>0)? Ask(InpSymbol) : Bid(InpSymbol);
state.first_price = fp;
state.last_added_price = fp;
state.adds_done = 0;
state.direction = dir;
state.initialized = true;
SaveState();
PrintFormat("First order: %s %.2f @ %.10f",
(dir>0?"BUY":"SELL"), StartLots, fp);
return;
}
// 已初始化:加仓与触发平仓
double bid = Bid(InpSymbol), ask = Ask(InpSymbol);
double ref_down = bid; // 用于多单向下触发、不利方向
double ref_up = ask; // 用于空单向上触发、不利方向
//========== 加仓判定 ==========
if(state.adds_done < (MaxOrders-1))
{
int next_k = state.adds_done + 1;
double px_adv = AdverseLevelPrice(state.first_price, state.direction, next_k, StepPercent);
double px_fav = FavorLevelPrice (state.first_price, state.direction, next_k, StepPercent);
bool hit_adverse=false, hit_favor=false;
if(state.direction>0){
// 多:不利=向下穿 px_adv(看 bid),有利=向上穿 px_fav(看 ask)
hit_adverse = (bid <= px_adv);
hit_favor = (ask >= px_fav);
}else{
// 空:不利=向上穿 px_adv(看 ask),有利=向下穿 px_fav(看 bid)
hit_adverse = (ask >= px_adv);
hit_favor = (bid <= px_fav);
}
bool do_add=false; double exec_hint=0; double target_vol=0;
if(AddingMode==ADVERSE_ONLY && hit_adverse){
target_vol = TargetVolumeByAdds(next_k);
exec_hint = px_adv;
do_add = true;
}
else if(AddingMode==FAVOR_ONLY && hit_favor){
target_vol = TargetVolumeByAdds(next_k);
exec_hint = px_fav;
do_add = true;
}
else if(AddingMode==BOTH){
// 若同时满足,择“更近的一侧”(以 mid 的距离)
if(hit_adverse || hit_favor){
double m = (bid+ask)*0.5;
double d_adv = MathAbs(m - px_adv);
double d_fav = MathAbs(m - px_fav);
bool choose_fav = hit_favor && (!hit_adverse || d_fav<=d_adv);
exec_hint = choose_fav ? px_fav : px_adv;
target_vol = TargetVolumeByAdds(next_k);
do_add = true;
}
}
if(do_add){
if(IncreasePosition(InpSymbol, state.direction, target_vol, exec_hint)){
state.adds_done = next_k;
SaveState();
PrintFormat("Layer %d added at %.10f, total vol=%.2f",
next_k, exec_hint, target_vol);
}
}
}
//========== 平仓触发 ==========
double trigger_price;
if(CloseAtLastLayerPrice && state.last_added_price>0){
trigger_price = state.last_added_price; // “回到最后加仓位”即平仓
}else{
trigger_price = FavorLevelPrice(state.first_price, state.direction, CloseAtLevelIndex, StepPercent);
}
double ref = (state.direction>0)? bid : ask; // 多看 bid 上破;空看 ask 下破(对有利方向)
bool fire = PriceCrossedFavor(ref, trigger_price, state.direction);
if(fire && PositionSelect(InpSymbol)){
if(CloseAllPositions(InpSymbol)){
PrintFormat(">>> ALL CLOSED at trigger %.10f", trigger_price);
}
}
}
void OnDeinit(const int reason)
{
// 保留状态,便于 EA 重载后继续
}

BGUSER-NXB07P6L
2025/08/10 16:48
4
//+------------------------------------------------------------------+
//| Martingale_AllInOne |
//| Grid by % from First Price, All-or-Nothing|
//+------------------------------------------------------------------+
#property copyright "OpenAI"
#property version "1.00"
#property strict
#include <Trade/Trade.mqh>
CTrade trade;
//=========================== 输入参数 ===============================//
input string InpSymbol = _Symbol; // 交易品种
enum DirOpt {LONG_ONLY=1, SHORT_ONLY=-1};
input DirOpt Direction = LONG_ONLY; // 做多或做空
input bool AutoStartIfNoPosition = true; // 无持仓时自动首单
input double StartLots = 0.10; // 首单手数
input double LotMultiplier = 2.0; // 每层手数放大倍数(>=1)
input int MaxOrders = 10; // 最大总单数(1~10),包含首单
input double StepPercent = 10.0; // 层距(%),从首单价起按百分比
input double MinEquityReservePercent = 30.0; // 账户净值保留比例,低于则停止加仓
input double MaxVolume = 100.0; // 单符号最大总手数保护
input int DeviationPoints = 20; // 下单滑点(点)
input ulong Magic = 20250810; // 魔术号
// 平仓触发层级(以“首单价”为参考,在有利方向第 N 层触发“一键平全仓”)
input int CloseAtLevelIndex = 10; // 默认=最后一层;范围 1~MaxOrders
// 可选:改为“到达加仓最后一层后,回到该层价即平全仓”
input bool CloseAtLastLayerPrice = false; // true=按“最后一层价格”触发
//=========================== 常量/全局 ==============================//
#define GV_NS "MGv1::"
string gv_first_price, gv_adds_done, gv_direction;
struct GridState {
double first_price;
int adds_done; // 已触发加仓层数(不含首单)
int direction; // 1=多,-1=空
bool initialized;
} state;
//--------------------------- 工具函数 -------------------------------//
string GVName(string key){ return StringFormat("%s%s[%s][%I64u]", GV_NS, key, InpSymbol, Magic); }
bool LoadState()
{
gv_first_price = GVName("first_price");
gv_adds_done = GVName("adds_done");
gv_direction = GVName("direction");
state.initialized = false;
if(GlobalVariableCheck(gv_first_price) && GlobalVariableCheck(gv_adds_done) && GlobalVariableCheck(gv_direction))
{
state.first_price = GlobalVariableGet(gv_first_price);
state.adds_done = (int)GlobalVariableGet(gv_adds_done);
state.direction = (int)GlobalVariableGet(gv_direction);
state.initialized = true;
}
return state.initialized;
}
void SaveState()
{
if(!GlobalVariableCheck(gv_first_price)) GlobalVariableCreate(gv_first_price, TimeCurrent(), 0.0);
if(!GlobalVariableCheck(gv_adds_done)) GlobalVariableCreate(gv_adds_done, TimeCurrent(), 0.0);
if(!GlobalVariableCheck(gv_direction)) GlobalVariableCreate(gv_direction, TimeCurrent(), 0.0);
GlobalVariableSet(gv_first_price, state.first_price);
GlobalVariableSet(gv_adds_done, (double)state.adds_done);
GlobalVariableSet(gv_direction, (double)state.direction);
}
void ResetState()
{
GlobalVariableDel(gv_first_price);
GlobalVariableDel(gv_adds_done);
GlobalVariableDel(gv_direction);
state = (GridState)0;
}
// 价格与精度
double TickSize(string sym){ return SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE); }
double PointP(string sym){ return SymbolInfoDouble(sym, SYMBOL_POINT); }
double NormalizePrice(string sym, double price)
{
int digits = (int)SymbolInfoInteger(sym, SYMBOL_DIGITS);
return NormalizeDouble(price, digits);
}
// 当前可成交价格
double CurrBid(string sym){ return SymbolInfoDouble(sym, SYMBOL_BID); }
double CurrAsk(string sym){ return SymbolInfoDouble(sym, SYMBOL_ASK); }
double CurrMid(string sym){ return (CurrBid(sym)+CurrAsk(sym))*0.5; }
// 下单侧/价格比较
bool PriceReached(double price_now, double target, int direction_favor) // 方向有利触发
{
if(direction_favor>0) return (price_now >= target); // 多单目标上破
else return (price_now <= target); // 空单目标下破
}
// 计算某一层的“有利方向目标价”(用于一键平仓)
double FavorLevelPrice(double first_price, int direction, int level_index)
{
double step = StepPercent/100.0;
if(direction>0) // 多:有利在上
return first_price * (1.0 + step * level_index);
else // 空:有利在下
return first_price * (1.0 - step * level_index);
}
// 计算第 k 层的“不利方向加仓价”(k>=1)
double AdverseLevelPrice(double first_price, int direction, int k)
{
double step = StepPercent/100.0;
if(direction>0) // 多:不利在下
return first_price * (1.0 - step * k);
else // 空:不利在上
return first_price * (1.0 + step * k);
}
// 计算当前应有的目标总手数(首单 + 已加仓层 * 倍数)
double TargetVolumeByAdds(int adds_done)
{
double vol = 0.0;
for(int i=0;i<=adds_done;i++)
{
double lots_i = StartLots * MathPow(MathMax(1.0, LotMultiplier), i);
vol += lots_i;
}
return vol;
}
// 根据当前净值与保证金预估,检查是否可增仓
bool CanIncreaseVolume(string sym, ENUM_ORDER_TYPE order_type, double new_volume)
{
// 最大手数保护
if(new_volume > MaxVolume) return false;
// 保证金检查(预估)
double price = (order_type==ORDER_TYPE_BUY) ? CurrAsk(sym) : CurrBid(sym);
double margin=0.0;
if(!OrderCalcMargin(order_type, sym, new_volume, price, margin))
return false;
double free_margin = AccountInfoDouble(ACCOUNT_FREEMARGIN);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
// 预留净值比例保护
if(free_margin < margin) return false;
double reserve = equity * (MinEquityReservePercent/100.0);
if(free_margin - margin < reserve) return false;
return true;
}
// 获取当前持仓信息(净值账户仅一个持仓)
bool GetPosition(string sym, double &pos_volume, double &pos_price, long &pos_type)
{
pos_volume=0; pos_price=0; pos_type=-1;
if(!Positi PositionGetDouble(POSITION_VOLUME);
pos_price = PositionGetDouble(POSITION_PRICE_OPEN);
pos_type = (long)PositionGetInteger(POSITION_TYPE); // POSITION_TYPE_BUY/SELL
return true;
}
// 一键平当前符号全部持仓
bool CloseAllPositions(string sym)
{
if(!Positi (long)PositionGetInteger(POSITION_TYPE);
double vol= PositionGetDouble(POSITION_VOLUME);
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(DeviationPoints);
bool ok=false;
if(type==POSITION_TYPE_BUY) ok = trade.PositionClose(sym);
else if(type==POSITION_TYPE_SELL) ok = trade.PositionClose(sym);
if(ok) ResetState();
return ok;
}
// 下单/加仓(净值账户=增量下单)
bool IncreasePosition(string sym, int direction, double target_total_volume)
{
double pos_vol, pos_price; long pos_type;
GetPosition(sym, pos_vol, pos_price, pos_type);
double add_vol = MathMax(0.0, target_total_volume - pos_vol);
if(add_vol <= 0.0) return true;
ENUM_ORDER_TYPE ot = (direction>0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
if(!CanIncreaseVolume(sym, ot, target_total_volume)) return false;
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(DeviationPoints);
bool ok=false;
if(direction>0) ok = trade.Buy(add_vol, sym);
else ok = trade.Sell(add_vol, sym);
return ok;
}
//============================== 事件 ================================//
int OnInit()
{
// 校验参数
MaxOrders = (int)MathMax(1, MathMin(10, MaxOrders));
CloseAtLevelIndex = (int)MathMax(1, MathMin(MaxOrders, CloseAtLevelIndex));
StepPercent = MathMax(0.01, StepPercent);
LotMultiplier = MathMax(1.0, LotMultiplier);
StartLots = MathMax(SymbolInfoDouble(InpSymbol, SYMBOL_VOLUME_MIN), StartLots);
if(!SymbolInfoInteger(InpSymbol, SYMBOL_TRADE_MODE) || !SymbolInfoInteger(InpSymbol, SYMBOL_TRADING_ALLOWED))
{
Print("Symbol not tradable or trading not allowed: ", InpSymbol);
return(INIT_FAILED);
}
if(!LoadState())
{
// 如果已有持仓,自动将首单价设为当前持仓均价,方向据持仓方向确定
double pv, pp; long pt;
if(Positi PositionGetDouble(POSITION_VOLUME);
pp = PositionGetDouble(POSITION_PRICE_OPEN);
pt = (long)PositionGetInteger(POSITION_TYPE);
if(pv>0.0)
{
state.first_price = pp;
state.adds_done = 0;
state.direction = (pt==POSITION_TYPE_BUY)? 1 : -1;
state.initialized = true;
SaveState();
}
}
}
return(INIT_SUCCEEDED);
}
void OnTick()
{
// 切符号安全
if(!SymbolInfoTick(InpSymbol, _Tick)) return;
// 若无状态且允许自动启动:开首单并记录 first_price
if(!state.initialized)
{
if(!AutoStartIfNoPosition) return;
int dir = (int)Direction;
double price = (dir>0)? CurrAsk(InpSymbol): CurrBid(InpSymbol);
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(DeviationPoints);
// 首单下单
bool ok = (dir>0)? trade.Buy(StartLots, InpSymbol)
: trade.Sell(StartLots, InpSymbol);
if(!ok) return;
state.first_price = price;
state.adds_done = 0;
state.direction = dir;
state.initialized = true;
SaveState();
PrintFormat("First order opened: %s %s lots=%.2f @ %.5f",
(dir>0?"BUY":"SELL"), InpSymbol, StartLots, price);
return;
}
// 有状态:驱动加仓与一键平仓逻辑
double bid = CurrBid(InpSymbol), ask = CurrAsk(InpSymbol), mid = (bid+ask)*0.5;
// 计算应触发的下一层(不利方向)
if(state.adds_done < (MaxOrders-1))
{
int next_k = state.adds_done + 1;
double adverse_px = AdverseLevelPrice(state.first_price, state.direction, next_k);
double ref = (state.direction>0)? bid : ask; // 多单看 Bid 下破;空单看 Ask 上破
bool hit=false;
if(state.direction>0) hit = (ref <= adverse_px); // 多:价格跌到/破第 next_k 层
else hit = (ref >= adverse_px); // 空:价格涨到/破第 next_k 层
if(hit)
{
double target_vol = TargetVolumeByAdds(next_k);
if(IncreasePosition(InpSymbol, state.direction, target_vol))
{
state.adds_done = next_k;
SaveState();
PrintFormat("Layer %d added, total volume now %.2f", next_k, target_vol);
}
}
}
// 计算“一键平仓触发价”
double close_trigger_price;
if(CloseAtLastLayerPrice)
{
int last_k = MathMax(0, state.adds_done); // 已到达的最后一层(若尚未触发任何加仓,则=0)
if(last_k<=0)
{
// 尚无“最后层价”可用,则按 CloseAtLevelIndex 计算
close_trigger_price = FavorLevelPrice(state.first_price, state.direction, CloseAtLevelIndex);
}
else
{
// 使用“最后一层”的入场价作为触发价
close_trigger_price = AdverseLevelPrice(state.first_price, state.direction, last_k);
}
}
else
{
// 固定:从首单价起,在“有利方向”第 CloseAtLevelIndex 层触发
close_trigger_price = FavorLevelPrice(state.first_price, state.direction, CloseAtLevelIndex);
}
// 触发“一键平全仓”的判定
double ref_favor = (state.direction>0)? bid : ask;
if(PriceReached(ref_favor, close_trigger_price, state.direction))
{
// 平全仓(仅在有仓时执行)
if(PositionSelect(InpSymbol))
{
if(CloseAllPositions(InpSymbol))
{
Print(">>> ALL POSITIONS CLOSED by trigger @ ", DoubleToString(close_trigger_price, (int)SymbolInfoInteger(InpSymbol,SYMBOL_DIGITS)));
}
}
}
}
// 可选:重置命令(在“搭配脚本”或测试时可用)
void OnDeinit(const int reason)
{
// 不自动清状态,以便 EA 重启后继续;如需清理,可手动删除全局变量或重新加载后调用 ResetState()
}