问题
I have written the code below that opens a buy and sell trade (a certain number of pips above and below the ask and bid price) at a specific time.
How can I close/cancel one immediately when the other is opened?
How can I close the opened trade if it's say X pips in profit or after a minute (depending on which condition is reached first)?
I'm a not too sure I've done the right thing in the code below and would really appreciate some help.
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);
}
回答1:
AUTOMATED NEWS TRADING What you (@iGetIt ) are looking for is a rudimentary News Trading bot. Here's a diluted implementation for it.
In the more advanced stages, you will need to automatically download news and auto-trade base on the affected pairs, track volatility (to avoid swings), sync your PC time (Windows date/time is NOT accurate and news trading need to be synced to the millisecond level). Track your broker server response time, implement Trailing-StopLoss (for improved profit), implement slide-in-orders (multiple stop orders to catch huge spikes), calculate order-set profitability (to know when to close all the orders when price retrace), etc etc.
Anyway, here's a basic version that you can play with (based on the Bounty requirements):
- Opens buy + sell stop-orders at specific time.
- Configurable number of pips AWAY from current ask/bid.
- Implements OCO (One Cancels the Other).
- Closes executed trades with x-pip profit (aka TP level).
- Closes executed or outstanding stop-orders after x-seconds.
Visual: To show that it executes in time (this is Asian time, so liquidity is low, so +- a few seconds before price ticks).
Closing: It closes automatically based on the settings.
SOURCE CODE: And this is the complete MQL4 source-code for it.
(UPDATED 15May19 1045 GMT+8) to fix bug as reported in the closing of executed orders after 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);
}
回答2:
#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.
}
}
来源:https://stackoverflow.com/questions/55930471/how-can-i-cancel-a-trade-when-another-is-open-and-keep-the-open-trade-for-a-give