//+------------------------------------------------------------------+ //| sonic | //| Copyright 2021, NhatNamBe | //| | //+------------------------------------------------------------------+ #include "init.mqh" #include "pnlInfo.mqh" input int MagicNumber=1234567; // Expert Advisor ID input bool DescriptionModeFull=true; // Detailed output mode input double inputProfit=0.00005; // Profit input double step=0.00005; // Step input double amount=0.01; // Amount input double reachPNL=0.001; // Reach PNL input int maxOrder=5; // Max Order input string testSide="Buy"; // Side for backtest datetime history_start; ulong currentPendingBuyTicket=0; ulong currentPendingSellTicket=0; bool tradingLong=false; bool tradingShort=false; CpnlInfo ExtScript; //+------------------------------------------------------------------+ //|Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- check if autotrading is allowed if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { Alert("Autotrading in the terminal is disabled, Expert Advisor will be removed."); ExpertRemove(); return(-1); } int ret=CheckAccount(); if(ret) { ExpertRemove(); return(ret); } GetSymbolInfo(); //--- save the time of launching the Expert Advisor for receiving trading history history_start=TimeCurrent(); //--- if(MQLInfoInteger(MQL_TESTER)) { Print("Backtest"); if(testSide=="Buy") { tradingLong=true; CheckPositionAndPlaceNewTrade(POSITION_TYPE_BUY); } else if(testSide=="Sell") { tradingShort=true; CheckPositionAndPlaceNewTrade(POSITION_TYPE_SELL); } } else CreateBuySellButtons(); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- delete all graphical objects ObjectDelete(0,"Buy"); ObjectDelete(0,"Sell"); EventKillTimer(); //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnTimer() { PNLStart(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PNLStart() { double pPnl = ExtScript.Processing(0.001); if(pPnl) { // TODO: Do something here closePosition(); ExtScript.SetLastPnl(pPnl); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void closePosition() { // TODO: // 1. cancel all open-order // 2. closed trade ENUM_POSITION_TYPE targetType = POSITION_TYPE_BUY; CPositionInfo position; double nearestTakeProfit=0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket>0) { position.SelectByTicket(ticket); ENUM_POSITION_TYPE posType = position.PositionType(); double tpPrice = position.TakeProfit(); Print(EnumToString(posType) + " : " + (string)ticket + " price: " + tpPrice); CTrade trade; //trade.PositionClose(_Symbol); if(!trade.PositionClose(ticket)) { Print("Loi roi...."); } } } while(true) { int i = PositionsTotal() - 1; if(i <= 0) { break; } Sleep(1000); } } //+------------------------------------------------------------------+ //| TradeTransaction function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { ulong lastOrderID =trans.order; ENUM_ORDER_TYPE lastOrderType =trans.order_type; ENUM_ORDER_STATE lastOrderState=trans.order_state; //--- the name of the symbol, for which a transaction was performed string trans_symbol=trans.symbol; //--- type of transaction ENUM_TRADE_TRANSACTION_TYPE trans_type=trans.type; switch(trans.type) { case TRADE_TRANSACTION_HISTORY_ADD: // adding an order to the history { //--- order ID in an external system - a ticket assigned by an Exchange string Exchange_ticket=""; if(lastOrderState==ORDER_STATE_FILLED) { if(HistoryOrderSelect(lastOrderID)) Exchange_ticket=HistoryOrderGetString(lastOrderID,ORDER_EXTERNAL_ID); if(Exchange_ticket!="") Exchange_ticket=StringFormat("(Exchange ticket=%s)",Exchange_ticket); } PrintFormat("MqlTradeTransaction: %s order #%d %s %s %s %s",EnumToString(trans_type), lastOrderID,EnumToString(lastOrderType),trans_symbol,EnumToString(lastOrderState),Exchange_ticket); if(lastOrderState==ORDER_STATE_FILLED) { ENUM_POSITION_TYPE targetType; if(lastOrderID==currentPendingBuyTicket) currentPendingBuyTicket=0; else if(lastOrderID==currentPendingSellTicket) currentPendingSellTicket=0; } } break; default: // other transactions { } break; } //--- } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void OnTrade(void) { static int positions=0; // number of open positions int curr_positions=PositionsTotal(); if(curr_positions!=positions) { positions=curr_positions; if(tradingLong) CheckPositionAndPlaceNewTrade(POSITION_TYPE_BUY); if(tradingShort) CheckPositionAndPlaceNewTrade(POSITION_TYPE_SELL); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CheckPositionAndPlaceNewTrade(ENUM_POSITION_TYPE targetType) { if((targetType==POSITION_TYPE_BUY && !tradingLong) || (targetType==POSITION_TYPE_SELL && !tradingShort)) { Print("### " + EnumToString(targetType) + " is disable"); return; } CPositionInfo position; CTrade trade; COrderInfo orderInfo; double nearestPos=0; double farthestPos=0; ulong farthestTicket=0; ulong currentPendingTicket; int openPosNum=0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket>0) { position.SelectByTicket(ticket); ENUM_POSITION_TYPE posType = position.PositionType(); double posPrice = position.PriceOpen(); //Print(EnumToString(posType) + " : " + (string)ticket + " price: " + tpPrice); if(targetType==posType) { if(!nearestPos || nearestPos*GetStepWise(targetType) > posPrice*GetStepWise(targetType)) nearestPos=posPrice; if(!farthestTicket || farthestPos*GetStepWise(targetType) < posPrice*GetStepWise(targetType)) { farthestPos=posPrice; farthestTicket=ticket; } } } } openPosNum+=1; if(openPosNum > maxOrder) { //--- Cut farthest one Print("### Reach max order, cut farthest Pos " + farthestTicket + " at " + farthestPos); trade.PositionClose(farthestTicket); } if(targetType==POSITION_TYPE_BUY) currentPendingTicket=currentPendingBuyTicket; else currentPendingTicket=currentPendingSellTicket; if(!nearestPos) { Print("#### " + EnumToString(targetType) + " there is no pos yet"); if(currentPendingTicket) { //--- delete existing pending order trade.OrderDelete(currentPendingTicket); } //--- receiving a buy price double price=(targetType==POSITION_TYPE_BUY)?SymbolInfoDouble(_Symbol,SYMBOL_ASK):SymbolInfoDouble(_Symbol,SYMBOL_BID); //--- filling comments ENUM_ORDER_TYPE order_type=(targetType==POSITION_TYPE_BUY)?ORDER_TYPE_BUY:ORDER_TYPE_SELL; string comment=EnumToString(order_type) + " market "+_Symbol+" "+amount+" at "+ price; Print(comment); //--- everything is ready, trying to open a buy position currentPendingTicket=PlaceOrder(_Symbol, targetType, order_type, amount, price, 0, inputProfit, comment); } else { Print("#### " + EnumToString(targetType) + " nearestPos: " + nearestPos); //--- receiving a buy price double price=nearestPos - GetStepWise(targetType)*step; //--- filling comments ENUM_ORDER_TYPE order_type=(targetType==POSITION_TYPE_BUY)?ORDER_TYPE_BUY_LIMIT:ORDER_TYPE_SELL_LIMIT; string comment=EnumToString(order_type) + " " +_Symbol+" "+amount+" at "+ price; Print(comment); //--- everything is ready, trying to open a buy position if(currentPendingTicket) { //--- check if new pending order is same to existing one orderInfo.Select(currentPendingTicket); double existPrice=orderInfo.PriceOpen(); if(existPrice==price) { Print("existing price ", existPrice); return; } //--- delete existing pending order trade.OrderDelete(currentPendingTicket); } currentPendingTicket=PlaceOrder(_Symbol, targetType, order_type, amount, price, 0, inputProfit, comment); } if(targetType==POSITION_TYPE_BUY) currentPendingBuyTicket=currentPendingTicket; else currentPendingSellTicket=currentPendingTicket; } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { CTrade trade; //--- handling CHARTEVENT_CLICK event ("Clicking the chart") if(id==CHARTEVENT_OBJECT_CLICK) { Print("=> ",__FUNCTION__,": sparam = ",sparam); //--- minimum volume for a deal // double volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); //--- if "Buy" button is pressed, then buy if(sparam=="Buy") { tradingLong=true; CheckPositionAndPlaceNewTrade(POSITION_TYPE_BUY); //--- unpress the button ObjectSetInteger(0,"Buy",OBJPROP_STATE,false); } //--- if "Sell" button is pressed, then sell if(sparam=="Sell") { tradingShort=true; CheckPositionAndPlaceNewTrade(POSITION_TYPE_SELL); //--- unpress the button ObjectSetInteger(0,"Sell",OBJPROP_STATE,false); } if(sparam=="BuyStop") { //--- unpress the button ObjectSetInteger(0,"BuyStop",OBJPROP_STATE,false); if(currentPendingBuyTicket) trade.OrderDelete(currentPendingBuyTicket); tradingLong=false; } //--- if "Sell" button is pressed, then sell if(sparam=="SellStop") { //--- unpress the button ObjectSetInteger(0,"SellStop",OBJPROP_STATE,false); if(currentPendingSellTicket) trade.OrderDelete(currentPendingSellTicket); tradingShort=false; } ChartRedraw(); } //--- } //+------------------------------------------------------------------+ //| Create two buttons for buying and selling | //+------------------------------------------------------------------+ void CreateBuySellButtons() { //--- check the object named "Buy" if(ObjectFind(0,"Buy")>=0) { //--- if the found object is not a button, delete it if(ObjectGetInteger(0,"Buy",OBJPROP_TYPE)!=OBJ_BUTTON) ObjectDelete(0,"Buy"); } else ObjectCreate(0,"Buy",OBJ_BUTTON,0,0,0); // create "Buy" button //--- configure "Buy" button ObjectSetInteger(0,"Buy",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetInteger(0,"Buy",OBJPROP_XDISTANCE,100); ObjectSetInteger(0,"Buy",OBJPROP_YDISTANCE,50); ObjectSetInteger(0,"Buy",OBJPROP_XSIZE,70); ObjectSetInteger(0,"Buy",OBJPROP_YSIZE,30); ObjectSetString(0,"Buy",OBJPROP_TEXT,"Buy"); ObjectSetInteger(0,"Buy",OBJPROP_COLOR,clrGreen); //--- check presence of the object named "Sell" if(ObjectFind(0,"Sell")>=0) { //--- if the found object is not a button, delete it if(ObjectGetInteger(0,"Sell",OBJPROP_TYPE)!=OBJ_BUTTON) ObjectDelete(0,"Sell"); } else ObjectCreate(0,"Sell",OBJ_BUTTON,0,0,0); // create "Sell" button //--- configure "Sell" button ObjectSetInteger(0,"Sell",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetInteger(0,"Sell",OBJPROP_XDISTANCE,100); ObjectSetInteger(0,"Sell",OBJPROP_YDISTANCE,100); ObjectSetInteger(0,"Sell",OBJPROP_XSIZE,70); ObjectSetInteger(0,"Sell",OBJPROP_YSIZE,30); ObjectSetString(0,"Sell",OBJPROP_TEXT,"Sell"); ObjectSetInteger(0,"Sell",OBJPROP_COLOR,clrRed); //--- check the object named "BuyStop" if(ObjectFind(0,"BuyStop")>=0) { //--- if the found object is not a button, delete it if(ObjectGetInteger(0,"BuyStop",OBJPROP_TYPE)!=OBJ_BUTTON) ObjectDelete(0,"BuyStop"); } else ObjectCreate(0,"BuyStop",OBJ_BUTTON,0,0,0); // create "Buy" button //--- configure "Buy" button ObjectSetInteger(0,"BuyStop",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetInteger(0,"BuyStop",OBJPROP_XDISTANCE,250); ObjectSetInteger(0,"BuyStop",OBJPROP_YDISTANCE,50); ObjectSetInteger(0,"BuyStop",OBJPROP_XSIZE,150); ObjectSetInteger(0,"BuyStop",OBJPROP_YSIZE,30); ObjectSetString(0,"BuyStop",OBJPROP_TEXT,"Pause Buy"); ObjectSetInteger(0,"BuyStop",OBJPROP_COLOR,clrGreen); //--- check presence of the object named "SellStop" if(ObjectFind(0,"SellStop")>=0) { //--- if the found object is not a button, delete it if(ObjectGetInteger(0,"SellStop",OBJPROP_TYPE)!=OBJ_BUTTON) ObjectDelete(0,"SellStop"); } else ObjectCreate(0,"SellStop",OBJ_BUTTON,0,0,0); // create "SellStop" button //--- configure "SellStop" button ObjectSetInteger(0,"SellStop",OBJPROP_CORNER,CORNER_RIGHT_UPPER); ObjectSetInteger(0,"SellStop",OBJPROP_XDISTANCE,250); ObjectSetInteger(0,"SellStop",OBJPROP_YDISTANCE,100); ObjectSetInteger(0,"SellStop",OBJPROP_XSIZE,150); ObjectSetInteger(0,"SellStop",OBJPROP_YSIZE,30); ObjectSetString(0,"SellStop",OBJPROP_TEXT,"Pause Sell"); ObjectSetInteger(0,"SellStop",OBJPROP_COLOR,clrRed); //--- perform forced update of the chart to see the buttons immediately ChartRedraw(); //--- } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+