如何在另一个交易仍未结束时取消一项交易,并保留该交易的持续时间?

15
我已经编写了下面的代码,可以在特定时间以一定数量的点数上下买入和卖出交易。
  1. 如果其中一个交易被开启,如何立即关闭/取消另一个交易?

  2. 如果交易达到X个点的利润或经过一分钟后(取决于哪个条件首先满足),如何关闭已开放的交易?

我不确定下面的代码是否正确,非常感谢您的帮助。
double spread = Ask-Bid;
extern datetime time;
extern int pipGap = 7;
extern int lotSize = 0.01;
extern int closeTimeInSeconds = 60;


int start() {
  if (TimeCurrent() >= StrToTime(time)){

    OrderSend(Symbol(),OP_BUYSTOP,lotSize, Ask + Point*pipGap, 0,0,0);
    OrderSend(Symbol(),OP_SELLSTOP,lotSize, Bid - Point*pipGap, 0,0,0);


    }


for(int pos = OrdersTotal()-1; pos >= 0 ; pos--) if (
    OrderSelect(pos, SELECT_BY_POS)           
){              
    int duration = TimeCurrent() - OrderOpenTime();
    if (duration >= closeTimeInSeconds)
         OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(),
                     3*Point);
}

   return(0);
}

感谢NotEveryDay邀请我参与这篇文章。@iGetIt想要的基本上是一个新闻交易机器人,它可以放置一个网来捕捉价格波动(例如利率上涨陷阱)。对于高波动事件(例如非农业就业数据报告)并不是很有用。我刚刚看到了这个,之前我已经构建了一个相当复杂的新闻交易机器人。需要将其分解成几个部分来回答你的问题和悬赏。稍后会回复你。 - jlee88my
1
@iGetIt --> 请查看答案部分以获取解决方案。 - jlee88my
2个回答

8
自动化新闻交易 您(@iGetIt)正在寻找的是一个基本的新闻交易机器人。这里提供了一个简化的实现方法。
在更高级的阶段,您需要自动下载新闻并根据受影响的货币对进行自动交易,跟踪波动性(以避免波动),同步您的PC时间(Windows日期/时间不准确,新闻交易需要同步到毫秒级别)。跟踪您的经纪商服务器响应时间,实施追踪止损(以提高利润),实施滑动订单(多个停止订单以捕捉巨大的波动),计算订单集的盈利能力(以知道何时关闭所有订单当价格回撤),等等。
无论如何,这是一个基本版本,您可以尝试使用(基于悬赏要求):
  1. 在特定时间开放买入+卖出挂单。
  2. 可配置的距离当前询价/报价的点数。
  3. 实施OCO(一次取消另一次)。
  4. 以x点利润(即TP水平)关闭已执行的交易。
  5. 在x秒后关闭已执行或未执行的挂单。

可视化: 为了展示它在时间上的执行情况(这是亚洲时间,因此流动性较低,因此价格波动可能会有几秒钟的偏差)。 输入图片描述


关闭: 根据设置,它会自动关闭。 enter image description here

源代码: 这是完整的MQL4源代码。

(更新 15May19 1045 GMT+8) 修复了在TTL后执行订单关闭时报告的错误。

//+------------------------------------------------------------------+
//|                                                                 SO55930471.mq4 |
//|                   Copyright 2019, Joseph Lee, joseph.lee@fs.com.my |
//|                                                       TELEGRAM @JosephLee74 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Joseph Lee, TELEGRAM @JosephLee74"
#property link      "http://www.fs.com.my"
#property version   "1.00"
#property strict


//-------------------------------------------------------------------
// APPLICABLE PARAMETERS
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// NEWS IMPACT SELECTION
//===================================================================
extern string       vsEAComment                         = "Telegram @JosephLee74";      //Ego trip
extern datetime vdTradeStartInGMT                   = D'2019.5.14 06:00';           //When to trade (GMT)
extern int          viStopOrderLevelInPip           = 5;                    // StopOrder distance from ask/bid (pips)
extern double       viFixLots                           = 0.01;             // Lot size
extern int          viStopLossInPip                 = 20;                   // StopLoss (pips)
extern int          viTargetProfitInPip             = 100;              // TargetProfit (pips)
extern int          viDeleteStopOrderAfterInSec = 30;                   // StopOrder TTL (sec)
extern int          viDeleteOpenOrderAfterInSec = 300;              // Executed Order TTL (sec)
extern int          viMaxSlippageInPip              = 2;                    // Max Slippage (pip)


//-------------------------------------------------------------------
// System Variables
//-------------------------------------------------------------------
int     viMagicId                   = 0;
double  viPipsToPrice               = 0.0001;
double  viPipsToPoint               = 1;
int     viBuyStopTicket         = -1;
int     viSellStopTicket            = -1;
int     viBuyOrderTicket            = -1;
int     viSellOrderTicket           = -1;
string  vsDisplay                   = "EVENT-TRADER v1.01 - ";

//-------------------------------------------------------------------



//+------------------------------------------------------------------+
//| EA Initialization function
//+------------------------------------------------------------------+
int init() {
    ObjectsDeleteAll(); Comment("");
    // Caclulate PipsToPrice & PipsToPoints (old sytle, but works)
    if((Digits == 2) || (Digits == 3)) {viPipsToPrice=0.01;}
    if((Digits == 3) || (Digits == 5)) {viPipsToPoint=10;}
    viMagicId = vdTradeStartInGMT;
    start();
    return(0);
}
//+------------------------------------------------------------------+
//| EA Stand-Down function
//+------------------------------------------------------------------+
int deinit() {
    ObjectsDeleteAll();
    return(0);
}


//============================================================
// MAIN EA ROUTINE
//============================================================
int start() {

    //==========================================
    //MANAGE ROBOT EXPIRY
    //==========================================
    if( TimeCurrent() > D'2020.1.1' ) {
        Comment(vsDisplay + "EXPIRED. Please contact josephfhlee74 at gmail dot com"); // Who am I kidding?
        return(0);
    }


    ResetLastError();
    // Exit the routine if it is not time to trade yet.
    if(TimeGMT() < vdTradeStartInGMT) {
        // Show a count-down timer to the trading time.
        Comment(vsDisplay +
            "[" + TimeToStr(TimeGMT()) + " GMT] " + 
            IntegerToString(int(vdTradeStartInGMT - TimeGMT())) + " sec to [" + 
            TimeToStr(vdTradeStartInGMT) + " GMT]"
        );
        return(0);
    }


    viBuyStopTicket     = -1;
    viSellStopTicket        = -1;
    viBuyOrderTicket        = -1;
    viSellOrderTicket       = -1;
    //=========================================================
    //FIND *OPENED* BUY/SELL PENDING ORDERS
    //---------------------------------------------------------
    for( int i=OrdersTotal()-1; i>=0; i-- ) {
        if(OrderSelect( i, SELECT_BY_POS, MODE_TRADES ))
            if( OrderSymbol() == Symbol() )
                if( OrderMagicNumber() == viMagicId) {
                    if( OrderType() == OP_BUYSTOP )
                        viBuyStopTicket  = OrderTicket();
                    if( OrderType() == OP_SELLSTOP )
                        viSellStopTicket  = OrderTicket();
                    if( OrderType() == OP_BUY )
                        viBuyOrderTicket  = OrderTicket();
                    if( OrderType() == OP_SELL )
                        viSellOrderTicket  = OrderTicket();
                }
    }
    //=========================================================
    //FIND *CLOSED* BUY/SELL ORDERS FOR THIS EVENT
    //---------------------------------------------------------
    for(int i=OrdersHistoryTotal()-1; i>=0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
            if(OrderSymbol() == Symbol())
                if(OrderMagicNumber() == viMagicId) {
                    if( OrderType() == OP_BUYSTOP )
                        viBuyStopTicket  = OrderTicket();
                    if( OrderType() == OP_SELLSTOP )
                        viSellStopTicket  = OrderTicket();
                    if( OrderType() == OP_BUY )
                        viBuyOrderTicket  = OrderTicket();
                    if( OrderType() == OP_SELL )
                        viSellOrderTicket  = OrderTicket();
                }
    }
    // The above 2 sections will ensure that each event will only be executed once.
    // If orders are cancelled or closed for whatever reason, they will never be open again.

    string vsVerbose     =  vsDisplay + "[GMT " + TimeToStr(TimeGMT()) + "] Executing ..."
                                    "\nActive BUYSTOP: " + viBuyStopTicket +
                                    "  |  Active SELLSTOP: " + viSellStopTicket +
                                    "" +
                                    "\nActive BUY: " + viBuyOrderTicket +
                                    "  |  Active SELL: " + viSellOrderTicket;
    Comment(vsVerbose);


    //=========================================================
    // HANDLES OCO (One-Cancels-the-Other)
    //---------------------------------------------------------
    // BUY Order EXISTS, cancels all SellStops
    if( viBuyOrderTicket != -1 ) {
        for( int i=OrdersTotal()-1; i>=0; i-- ) {
            if(OrderSelect( i, SELECT_BY_POS, MODE_TRADES ))
                if( OrderSymbol() == Symbol() )
                    if( OrderMagicNumber() == viMagicId)
                        if( OrderType() == OP_SELLSTOP )
                            OrderDelete(OrderTicket());
        }
    }
    // SELL Order EXISTS, cancels all BuyStops
    if( viSellOrderTicket != -1 ) {
        for( int i=OrdersTotal()-1; i>=0; i-- ) {
            if(OrderSelect( i, SELECT_BY_POS, MODE_TRADES ))
                if( OrderSymbol() == Symbol() )
                    if( OrderMagicNumber() == viMagicId)
                        if( OrderType() == OP_BUYSTOP )
                            OrderDelete(OrderTicket());
        }
    }

    //=========================================================
    //CLOSE EXPIRED STOP/EXECUTED ORDERS
    //---------------------------------------------------------
    for( int i=OrdersTotal()-1; i>=0; i-- ) {
        if(OrderSelect( i, SELECT_BY_POS, MODE_TRADES ))
            if( OrderSymbol() == Symbol() )
                if( OrderMagicNumber() == viMagicId) {
                    if( (OrderType() == OP_BUYSTOP) || (OrderType() == OP_SELLSTOP) )
                        if((TimeCurrent()-OrderOpenTime()) >= viDeleteStopOrderAfterInSec)
                            OrderDelete(OrderTicket());

                    if( (OrderType() == OP_BUY) || (OrderType() == OP_SELL) )
                        if((TimeCurrent()-OrderOpenTime()) >= viDeleteOpenOrderAfterInSec) {
                            // For executed orders, need to close them
                            double closePrice = 0;
                            RefreshRates();
                            if(OrderType() == OP_BUY)
                                closePrice  = Bid;
                            if(OrderType() == OP_SELL)
                                closePrice  = Ask;
                            OrderClose(OrderTicket(), OrderLots(), closePrice, int(viMaxSlippageInPip*viPipsToPoint), clrWhite);
                        }
                }
    }



    //===================================================================
    //OPEN STOP ORDERS IF NO EXISTING nor CLOSED NO BUY/SELL STOP/ORDERS
    //-------------------------------------------------------------------
    // Do NOT execute (place new orders) if it is past the trading window.
    if(TimeGMT() >= (vdTradeStartInGMT+viDeleteStopOrderAfterInSec))
    {
        Comment(vsDisplay + "[" + TimeToStr(TimeGMT()) + " GMT] " + "Already passed execution time.");
        return(0);
    }
    // Place BuyStop if not exists; and no executed-Buy order
    if( (viBuyStopTicket == -1) && (viBuyOrderTicket == -1)) {
        RefreshRates();
        viFixLots       = NormalizeDouble(viFixLots, 2);
        double viPrice = NormalizeDouble(Ask + (viStopOrderLevelInPip*viPipsToPrice), Digits);
        double viSL  = viPrice - (viStopLossInPip*viPipsToPrice);
        double viTP  = viPrice + (viTargetProfitInPip*viPipsToPrice);
        viBuyStopTicket   = OrderSend(Symbol(), OP_BUYSTOP, viFixLots
                                        , viPrice
                                        , int(viMaxSlippageInPip*viPipsToPoint)
                                        , viSL, viTP
                                        , vsEAComment, viMagicId, 0, Blue);
        if(viBuyStopTicket == -1)
            Print("Error executing BuyStop [" + IntegerToString(GetLastError()) + "]." );
    }
    // Place SellStop if not exists; and no executed-Sell order
    if( (viSellStopTicket == -1) && (viSellOrderTicket == -1) ) {
        RefreshRates();
        viFixLots       = NormalizeDouble(viFixLots, 2);
        double viPrice  = NormalizeDouble(Bid - (viStopOrderLevelInPip*viPipsToPrice), Digits);
        double viSL     = viPrice + (viStopLossInPip*viPipsToPrice);
        double viTP     = viPrice - (viTargetProfitInPip*viPipsToPrice);
        viSellStopTicket      = OrderSend(Symbol(), OP_SELLSTOP, viFixLots
                                        , viPrice
                                        , int(viMaxSlippageInPip*viPipsToPoint)
                                        , viSL, viTP
                                        , vsEAComment, viMagicId, 0, Red);
        if(viSellStopTicket == -1)
            Print("Error executing SellStop [" + IntegerToString(GetLastError()) + "]." );
    }
    return(0);
}

1
@JosephLee 我已经在代码的HANDLES OCO (One-Cancels-the-Other)OPEN STOP ORDERS IF NOT EXISTS and NO BUY/SELL ORDERS部分发现了问题。当一个挂单被打开时,删除的订单OrderTicket变成-1,这满足了创建新订单的条件,导致订单的重复删除和重新创建。我尝试在订单关闭后更改OrderTicket int,但是当没有任何一个订单被打开时删除两个挂单会出现问题。我在https://pastebin.com/H4N2F6Mq中的行上放置了注释。 - Hilarious404
1
已修复BUG:如@Hilarious404 报告并更新了上面的代码。这是更改跟踪器:https://github.com/fhlee74/mql4-EventTrader/commit/a4ec5648af0eb48044fc9be800c3283e45b29664 - jlee88my
3
@JosephLee 做得好。如何将此扩展以能够在同一货币对上进行多次交易,且使用不同的参数? - TenOutOfTen
1
@TenOutOfTen,你需要的是滑入功能。例如:设置多个不同距离的网(层级)。当发生大的波动时,它会触及多个止损位(级联订单)。而小的波动只会触及第一个止损位。支持这很容易实现,但下一个请求会更加复杂--你会要求基于集合的盈亏计算/平仓操作(例如:在回撤时,关闭整个集合[多个订单])。这是可能的,但在此版本中无法实现。如果在GitHub存储库中有兴趣,请尽快告知,我会在后续版本中进行添加。 - jlee88my
1
@JosephLee 你可能想看一下这个问题。已经为此创建了一个赏金 https://dev59.com/lFMI5IYBdhLWcg3wLYXE - Hilarious404
显示剩余12条评论

0
#property strict
//---
input datetime          InpTime1=D'2019.05.01 00:00';       //time to enter the trade, just as an example
input double            InpPipsDist=10;                     //distance in pips to place BS&SS OCO-orders
input int               InpCloseSeconds=60;                 //close time, seconds since main order is sent
input double            InpProfitPips=1.;                   //profit in pips to close all.
input double            InpLotSize=0.1;                     //lot size
input int               InpMagicNumber=123456789;           //magic number
// ---

#include <Arrays\ArrayObj.mqh>
bool firstOrderOpen;
double PIP;
CArrayObj *ordersList;
// ---

class C2Orders : public CObject
  {
private:
   int                  m_ticket1;
   int                  m_ticket2;
   datetime             m_timeStart;//OrderOpenTime of the two tickets might be different,TimeCurrent() is used as time they are open.
   bool                 m_activated;

   void              checkTicket(const int ticket)  //if one order is open, another is deleted.
      {
        if(ticket>0 && OrderSelect(ticket,SELECT_BY_TICKET))
          {
            if(OrderType()<=OP_SELL)
              {
                if(ticket==m_ticket1)
                  {
                   if(OrderDelete(m_ticket2))
                      printf("%i: failed to delete#%d. error=%d",__LINE__,m_ticket2,_LastError);
                    m_ticket2=-1;
                  }
                else
                  {
                    if(!OrderDelete(m_ticket1))
                       printf("%i: failed to delete#%d. error=%d",__LINE__,m_ticket1,_LastError);
                    m_ticket1=-1;
                  }
                m_activated=true;
              }
          }
     }
   double            getPnlPips(const int ticket)const
     {
       if(ticket>0 && OrderSelect(ticket,SELECT_BY_TICKET))
         {
          return (OrderProfit()>0 ? 1 : -1)*fabs(OrderOpenPrice()-OrderClosePrice());
         }
       return 0;
     }
   bool              try2closeByPnl()const
     {
        const double pnl=getPnlPips(m_ticket1)+getPnlPips(m_ticket2);
        if(pnl-InpProfitPips*PIP>0)
          {
            printf("%i : pnl=%.5f vs %.5f target. closing the tickets",__LINE__,pnl,InpProfitPips*PIP);
            close(m_ticket1);
            close(m_ticket2);
            return(true);
          }
        return(false);
     }
   bool              try2closeByTime()const
     {
        if(TimeCurrent()-m_timeStart-InpCloseSeconds>=0)
          {
            if(!OrderDelete(m_ticket1))printf("%i: failed to delete#%d. error=%d",__LINE__,m_ticket1,_LastError);
            if(!OrderDelete(m_ticket2))printf("%i: failed to delete#%d. error=%d",__LINE__,m_ticket2,_LastError);
            return(true);
          }
        return(false);
     }
   void              close(const int ticket)const
     {
        if(ticket>0 && OrderSelect(ticket,SELECT_BY_TICKET))
          {
            RefreshRates();
            if(OrderClose(ticket,OrderLots(),OrderClosePrice(),1))
               printf("%i: failed to close#%d. error=%d",__LINE__,ticket,_LastError);
          }
      }
public:
   C2Orders(const int ticket1,const int ticket2,const datetime time):
    m_ticket1(ticket1),m_ticket2(ticket2),m_activated(false),m_timeStart(time){}
  ~C2Orders(){}

   bool              check()    //returns FALSE if deleting the object
     {
        if(!m_activated)
          {
            checkTicket(m_ticket1);
            checkTicket(m_ticket2);
          }
        if(m_activated)
          {
            if(try2closeByPnl())
                return(false);
          }
        else
          {
            if(try2closeByTime())
                return(false);
          }
        return true;
     }

  };
//+------------------------------------------------------------------+
int OnInit()
    {
        firstOrderOpen=false;
        PIP=_Point*(_Digits%2==1 ? 10 : 1); //does not work for GOLD and indexes, good for FX.
        ordersList=new CArrayObj();

        return(INIT_SUCCEEDED);
    }
void OnDeinit(const int reason)
    {
        delete(ordersList);
    }
void OnTick()
    {
        if(!firstOrderOpen && TimeCurrent()>=InpTime1)
        {
            RefreshRates();
            const int ticketBS=OrderSend(_Symbol,OP_BUYSTOP,InpLotSize,NormalizeDouble(Ask+InpPipsDist*PIP,_Digits),0,0,0,NULL,InpMagicNumber);
            const int ticketSS=OrderSend(_Symbol,OP_SELLSTOP,InpLotSize,NormalizeDouble(Bid-InpPipsDist*PIP,_Digits),0,0,0,NULL,InpMagicNumber);
            C2Orders *oco=new C2Orders(ticketBS,ticketSS,TimeCurrent());
            ordersList.Add(oco);
            firstOrderOpen=true;
        }
        if(firstOrderOpen)
        {
            C2Orders* oco;
            for(int i=ordersList.Total()-1;i>=0;i--)//of course you have only one instance, but in real world you may need to loop over them.
            {
                oco=ordersList.At(i);
                if(!oco.check())
                    ordersList.Delete(i);
            }

            if(ordersList.Total()==0)
                ExpertRemove();//just to finish the test faster.
        }
    }

我看你只是复制了答案。那你有什么错误? - Daniel Kniaz
根据我对您提供的解决方案的理解,我进行了一些必要的更改。错误为1.'CObject' - declaration without type,2.'}' unexpected end of program和3." - unexpected end of program - NotEveryDay
5
@DanielKniaz 目前,您的解决方案基本上是解决原问题的模板。我希望能够得到一个完整的解决方案,其中包括已经测试过的代码,解决原问题中提到的所有问题。更具体地说,我需要一个解决方案,在特定时间以特定数量的pips开放买入和卖出挂单,在打开另一个交易(买入或卖出)时取消一个交易,并在利润达到X个pips以上或经过T秒/分钟后(取决于先满足哪个条件),关闭已打开的交易。 - iGetIt
2
@DanielKniaz 我忘了提到,此外,如果一段时间内没有任何挂单,它应该取消所有挂单。 - iGetIt
@DanielKniaz 我已经为我的问题 https://dev59.com/TbPma4cB1Zd3GeqPye0V 设置了赏金。请看一下。 - TenOutOfTen
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接