侦云取势 发表于 2025-6-18 23:57:00

嗷嗷叫

这是一个叫:【圆点指标.ex5】 的mt5指标。
现在用中文,帮我写一个mt5 ea
【多头信号:】圆点指标.ex5 参数 last length 为6 slow length为14 出现ptl trend start DodgerBlue 蓝色圆点。开多单。


【加仓】开单后,同时在顺势方向现价上方每隔1000点处挂1笔buy stop突破单。(挂20单)
如果价格上涨 buy stop成交, 如果价格下跌 超过1000点,则之前挂单不取消。然后在现价的上方1000点,重新挂1笔(B订单buy订单)订单,
如果价格继续下跌超过1000点,则继续在现价上方挂一笔(B订单:buy订单)订单。
相当于,只要是多头信号,那么。订单始终跟着现价上方1000点,挂单,反复跟着现价,每次超过1000点移动一次。直到成交,或者是反转。
【空头信号】:圆点指标.ex5 参数 last length 为6 slow length为14 出现ptl trend startCrimson 红色圆点。开空单。
【空单加仓和多单方向相反即可】


【如果多信号或者空信号 没盈利出局,出现了反转,那么启动第二个拐点策略。】第二个拐点策略:趋势 空转多,多转空
当趋势从多头转空头,计算持仓buy订单和sell订单的差,反向加倍下现价成交单,然后重复上面的突破挂单多转空的下单手数计算公式:(10手buy-5手sell)的差*2,下单10手sell现价成交单,此时仓位应该是10手buy和5手sell+10手sell订单,行情每次反转,都是如此处理反转。

获利了结,采用的是整体止盈,盈利超过5000点(5美元)回撤3000点,整体平仓。不管是1单还是100单,都是相同止盈策略

侦云取势 发表于 2025-6-18 23:57:41

//+------------------------------------------------------------------+
//|                                             Grid_Reversal_EA.mq5 |
//|                                  Copyright 2024, GPT-4 for MQL5 |
//|                                             https://www.google.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, GPT-4 for MQL5"
#property link      "https://www.google.com"
#property version   "1.40"
#property description "带时间控制和整体止损的圆点指标EA"

#include <Trade/Trade.mqh>

//--- EA 输入参数
input group             "指标参数"
input int               inpFastLength   = 6;            // 圆点指标 - Fast Length
input int               inpSlowLength   = 14;         // 圆点指标 - Slow Length
input string            indicator_name= "圆点指标";   // 指标文件名称

input group             "订单参数"
input double            initial_lots    = 0.01;         // 初始/加仓订单手数
input ulong             magic_number    = 12345;      // EA魔术数字
input double            reversal_multiplier = 2.0;      // 反转加倍乘数

input group             "顺势加仓参数"
input int               grid_distance_points = 1000;    // 挂单间隔 (点)
input int               max_pending_orders   = 20;      // 最大挂单数量

input group             "盈利管理参数"
input double            profit_target_usd   = 5.0;      // 整体盈利目标(美元)
input double            profit_drawdown_usd = 3.0;      // 盈利回撤(美元)

input group             "【新】亏损管理参数"
input bool            EnableBasketStopLoss = true;    // 启用整体止损
input double            BasketStopLossUSD    = -200.0;// 整体止损金额 (美元, 请使用负数)

input group             "时间控制参数"
input int               StartHour       = 0;            // 开单开始时间 (小时)
input int               EndHour         = 14;         // 开单结束时间 (小时, 14点代表0:00-13:59)
input bool            EnableDailyClose= true;         // 启用每日清仓
input int               CloseHour       = 14;         // 每日清仓时间 (小时)
input bool            Monday          = true;         // 周一开单
input bool            Tuesday         = true;         // 周二开单
input bool            Wednesday       = true;         // 周三开单
input bool            Thursday      = true;         // 周四开单
input bool            Friday          = true;         // 周五开单
input bool            Saturday      = true;         // 周六开单
input bool            Sunday          = true;         // 周日开单


//--- 全局变量
CTrade trade;
int    indicator_handle;
string ea_comment = "PyramidEA_TS";

//--- 用于跟踪状态的静态变量
enum TrendDirection
{
    NONE,
    UP,
    DOWN
};
static TrendDirection current_trend = NONE;
static double max_profit = 0.0;
static datetime last_close_time = 0; // 用于跟踪每日清仓

//+------------------------------------------------------------------+
//| EA初始化函数                                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    trade.SetExpertMagicNumber(magic_number);
    trade.SetMarginMode();
    trade.SetTypeFillingBySymbol(_Symbol);

    indicator_handle = iCustom(_Symbol, _Period, indicator_name, inpFastLength, inpSlowLength);
    if(indicator_handle == INVALID_HANDLE)
    {
      Alert("错误: 无法加载圆点指标. 请确保 '", indicator_name, ".ex5' 在 MQL5/Indicators 文件夹中。");
      return(INIT_FAILED);
    }
    InitializeTrendState();
    Print("EA初始化成功. 魔术数字: ", magic_number, ". 风险控制已启用.");
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA启动时,检查现有仓位以确定当前趋势状态                         |
//+------------------------------------------------------------------+
void InitializeTrendState()
{
    int buys = 0;
    int sells = 0;

    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
      if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == magic_number)
      {
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                buys++;
            else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                sells++;
      }
    }
    if(buys > 0 && sells == 0) current_trend = UP;
    else if(sells > 0 && buys == 0) current_trend = DOWN;
    else current_trend = NONE;
    Print("EA启动,检测到当前趋势状态: ", EnumToString(current_trend));
}

//+------------------------------------------------------------------+
//| EA去初始化函数                                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    if(indicator_handle != INVALID_HANDLE) IndicatorRelease(indicator_handle);
    Print("EA已停止。原因代码: ", reason);
}

//+------------------------------------------------------------------+
//| EA核心逻辑 - OnTick                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    // 盈利平仓检查
    if(CheckBasketProfitClosure()) return;

    // 【新】亏损平仓检查
    if(CheckBasketStopLoss()) return;

    // 每日定时清仓检查
    CheckDailyClose();

    // 新K线信号检查
    if(IsNewBar())
    {
      CheckSignal();
    }
}

//+------------------------------------------------------------------+
//| 每日定时清仓                                                   |
//+------------------------------------------------------------------+
void CheckDailyClose()
{
    if(!EnableDailyClose) return;
    MqlDateTime dt;
    TimeCurrent(dt);
    if(dt.hour == CloseHour)
    {
      MqlDateTime last_dt;
      TimeToStruct(last_close_time, last_dt);
      if(last_dt.day_of_year != dt.day_of_year || last_dt.year != dt.year)
      {
            Print("每日清仓时间到达 (", IntegerToString(CloseHour), ":00). 平仓所有订单...");
            CloseAllTrades();
            last_close_time = TimeCurrent(dt);
      }
    }
}

//+------------------------------------------------------------------+
//| 检查是否在允许的交易时间内                                       |
//+------------------------------------------------------------------+
bool IsTradingAllowed()
{
    MqlDateTime dt;
    TimeCurrent(dt);
    bool day_allowed = false;
    switch(dt.day_of_week)
    {
      case 0: day_allowed = Sunday;    break;
      case 1: day_allowed = Monday;    break;
      case 2: day_allowed = Tuesday;   break;
      case 3: day_allowed = Wednesday; break;
      case 4: day_allowed = Thursday;break;
      case 5: day_allowed = Friday;    break;
      case 6: day_allowed = Saturday;break;
    }
    bool hour_allowed = (dt.hour >= StartHour && dt.hour < EndHour);
    return day_allowed && hour_allowed;
}

//+------------------------------------------------------------------+
//| 检查新K线                                                      |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime last_bar_time = 0;
    datetime current_bar_time = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE);
    if(last_bar_time != current_bar_time)
    {
      last_bar_time = current_bar_time;
      return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| 检查指标信号                                                   |
//+------------------------------------------------------------------+
void CheckSignal()
{
    if(!IsTradingAllowed()) return;

    double arrow_price_buffer[], arrow_color_buffer[];
    if(CopyBuffer(indicator_handle, 7, 1, 2, arrow_price_buffer) < 2 ||
       CopyBuffer(indicator_handle, 8, 1, 2, arrow_color_buffer) < 2)
    {
      Print("错误: 无法从指标复制数据. Error code: ", GetLastError());
      return;
    }
    double arrow_value = arrow_price_buffer, color_value = arrow_color_buffer;
    if(arrow_value != EMPTY_VALUE)
    {
      if(color_value == 0) // 多头信号
      {
            if(current_trend == DOWN) HandleReversal(UP);
            else if(current_trend == NONE)
            {
                if(trade.Buy(initial_lots, _Symbol, 0, 0, 0, ea_comment))
                {
                   current_trend = UP;
                   PlacePyramidGrid(UP);
                }
            }
      }
      else if(color_value == 1) // 空头信号
      {
            if(current_trend == UP) HandleReversal(DOWN);
            else if(current_trend == NONE)
            {
                if(trade.Sell(initial_lots, _Symbol, 0, 0, 0, ea_comment))
                {
                   current_trend = DOWN;
                   PlacePyramidGrid(DOWN);
                }
            }
      }
    }
}

//+------------------------------------------------------------------+
//| 处理反转逻辑                                                   |
//+------------------------------------------------------------------+
void HandleReversal(TrendDirection new_trend)
{
    double buy_lots = 0, sell_lots = 0;
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
      if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == magic_number)
      {
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) buy_lots += PositionGetDouble(POSITION_VOLUME);
            else sell_lots += PositionGetDouble(POSITION_VOLUME);
      }
    }
    double lot_diff = MathAbs(buy_lots - sell_lots);
    double new_trade_lots = NormalizeDouble(lot_diff * reversal_multiplier, 2);
    double min_lots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    if(new_trade_lots < min_lots) new_trade_lots = min_lots;

    if(new_trend == UP)
    {
      DeleteAllPendingSells();
      if(trade.Buy(new_trade_lots, _Symbol, 0, 0, 0, ea_comment))
      {
         current_trend = UP;
         PlacePyramidGrid(UP);
      }
    }
    else if(new_trend == DOWN)
    {
      DeleteAllPendingBuys();
      if(trade.Sell(new_trade_lots, _Symbol, 0, 0, 0, ea_comment))
      {
         current_trend = DOWN;
         PlacePyramidGrid(DOWN);
      }
    }
}

//+------------------------------------------------------------------+
//| 信号出现后,一次性挂出顺势的突破单网格                           |
//+------------------------------------------------------------------+
void PlacePyramidGrid(TrendDirection trend)
{
    if(trend == NONE) return;
    if(trend == UP)
    {
      double current_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      for(int i = 1; i <= max_pending_orders; i++)
      {
            double stop_price = current_ask + (i * grid_distance_points * _Point);
            stop_price = NormalizeDouble(stop_price, _Digits);
            trade.BuyStop(initial_lots, stop_price, _Symbol, 0, 0, ORDER_TIME_GTC, 0, ea_comment);
      }
    }
    else if(trend == DOWN)
    {
      double current_bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      for(int i = 1; i <= max_pending_orders; i++)
      {
            double stop_price = current_bid - (i * grid_distance_points * _Point);
            stop_price = NormalizeDouble(stop_price, _Digits);
            trade.SellStop(initial_lots, stop_price, _Symbol, 0, 0, ORDER_TIME_GTC, 0, ea_comment);
      }
    }
}

//+------------------------------------------------------------------+
//| 检查整体盈利平仓条件                                             |
//+------------------------------------------------------------------+
bool CheckBasketProfitClosure()
{
    double current_profit = GetTotalFloatingProfit();
    if(current_profit <= 0)
    {
      max_profit = 0;
      return false;
    }
    if(current_profit > max_profit) max_profit = current_profit;
    if(max_profit >= profit_target_usd && current_profit <= max_profit - profit_drawdown_usd)
    {
      Print("盈利平仓条件触发. Max Profit: ", DoubleToString(max_profit,2), " USD. 平仓所有订单.");
      CloseAllTrades();
      return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| 【新】检查整体亏损平仓条件                                       |
//+------------------------------------------------------------------+
bool CheckBasketStopLoss()
{
    if (!EnableBasketStopLoss) return false;

    double current_profit = GetTotalFloatingProfit();

    if (current_profit <= BasketStopLossUSD)
    {
      Print("整体止损触发. 当前亏损: ", DoubleToString(current_profit, 2), " USD. 止损线: ", DoubleToString(BasketStopLossUSD, 2), " USD. 平仓所有订单.");
      CloseAllTrades();
      return true;
    }
    return false;
}


//+------------------------------------------------------------------+
//| 计算当前交易品种和魔术数字的总浮动盈亏                           |
//+------------------------------------------------------------------+
double GetTotalFloatingProfit()
{
    double total_profit = 0;
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
      if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == magic_number)
      {
            total_profit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
      }
    }
    return total_profit;
}

//+------------------------------------------------------------------+
//| 关闭所有持仓单和挂单                                             |
//+------------------------------------------------------------------+
void CloseAllTrades()
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
      if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == magic_number)
            trade.PositionClose(PositionGetTicket(i));
    }
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
      ulong ticket = OrderGetTicket(i);
      if(ticket > 0)
      {
          if(OrderGetString(ORDER_SYMBOL) == _Symbol && OrderGetInteger(ORDER_MAGIC) == magic_number)
            trade.OrderDelete(ticket);
      }
    }
    current_trend = NONE;
    max_profit = 0.0;
    Print("所有仓位已清理完毕。");
}

//+------------------------------------------------------------------+
//| Helper Functions (辅助函数)                                    |
//+------------------------------------------------------------------+
void DeleteAllPendingBuys()
{
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
      ulong ticket = OrderGetTicket(i);
      if(ticket > 0)
      {
         if(OrderGetString(ORDER_SYMBOL) == _Symbol &&
            OrderGetInteger(ORDER_MAGIC) == magic_number &&
            OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP)
         {
               trade.OrderDelete(ticket);
         }
      }
    }
}

void DeleteAllPendingSells()
{
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
       ulong ticket = OrderGetTicket(i);
       if(ticket > 0)
       {
          if(OrderGetString(ORDER_SYMBOL) == _Symbol &&
             OrderGetInteger(ORDER_MAGIC) == magic_number &&
             OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
          {
            trade.OrderDelete(ticket);
          }
       }
    }
}

页: [1]
查看完整版本: 嗷嗷叫

人生者,生存也。
生存所需,财(钱)官(权)也。
财自食伤(子孙福德爻)生,
印星生身荫护,官财印全,适合人间生存也。
若命缺财,缺官,则失去生存权。
一旦脱离父母养育,将天天面临,
从绝望中醒来,又从绝望中睡去。来去如烟!