在mql4中用什么来代替OnTradeTransaction()? - 页 8

 
Vitaly Muzichenko:

就是这样,解决方案很简单:我们引入另一个检查来改变历史,这样就不会有任何损失,而且会100%地工作。

这甚至可以作为一个不完整的OnTrade()使用。

void OnTrade()
 {
  ...
 }

static __OTotal = -1;
static __HTotal = -1;
int OT=OrdersTotal();
int HT=OrdersHistoryTotal();
  if(OT!=__OTotal || HT!=__HTotal) // если изменилось - выполняем
   {
     OnTrade(); // здесь дёргаем текущую ситуацию на счёте и заполняем структуры
     __OTotal=OrdersTotal(); // запомним текущее количество
     __HTotal=OrdersHistoryTotal(); // запомним количество в истории
   }
 
Vitaly Muzichenko:

我想我还不够聪明)。

我如何应用这个?

只有一个问题,而且极其罕见,今天是几年来第一次发现这个问题,可能以前就有,只是没有注意。


我说的是哈希和计算--你如何在哈希和值中加入一个字符名称--计算构成字符名称的字母代码的值。

 
Vitaly Muzichenko:

就是这样,解决方案很简单:引入另一个历史变更检查,这样就不会有任何损失,而且会100%地工作。

以下是我的文章#3的摘录。

-------

让我们更多地关注作为结构一部分的哈希金额。
仅仅知道订单和头寸的数量还不足以准确判断账户中的变化--,一个挂单可以被删除,在这种情况下,账户中的订单和头寸总数将发生变化。但是...一个挂单可能触发并成为一个头寸。在这种情况下,订单和头寸的总量不会改变(对于对冲账户和MQL4)-,头寸的数量增加了,但订单的数量减少了,所以总量还是一样的。这对我们来说并不可行。

让我们考虑一张票。 添加/删除挂单将改变账户上的总点数,触发挂单不会改变账户上的总点数。

我们来看看总的数量。你下了或删除了一个挂单-- 账户中的总金额发生了变化;我们开仓或平仓,或改变了仓位-- 账户中的总金额发生了变化。这似乎是合适的,但再一次,激活一个挂单不会改变总成交量。

那么我们再来查看一个仓位属性-- 其变化的时间,以毫秒为单位:开立新仓位将改变总的仓位变化时间,部分平仓将改变仓位变化时间,向净值账户增加交易量将改变总仓位变化时间。

其中哪种方法适合确定账户变化的准确位置?车票+位置改变的时间。 让我们检查一下。

  • 开仓-- 票量有变化+ 仓位变化时间量有变化-- 有变化
  • 我们关闭了一个仓位--,点数发生了变化+ 仓位变化 的时间-- ,有了变化。
  • 下了一个挂单 -+ 仓位变化的时间没有变化-- 有一个变化
  • 删除的挂单-- 票据金额变化+ 仓位变化时间金额保持不变-- 变化
  • 挂单激活 - 票面金额没有变化+仓位变化时间金额有变化 - - 有变化
  • 部分仓位关闭 - 票面金额变化+ 仓位变化时间变化 - - 有变化
  • 在仓位上加量 - 票面金额保持不变+仓位变化时间改变 - - 有变化
因此,我们将使用门票+一个位置的变化时间,以毫秒为单位进行哈希求和

不过,在这里,我没有在哈希和中添加一个符号--没有这样的先例。但我有它与检查历史相结合的工作。因此--应该没有错误地工作。然而,我将在某个时候检查它。

Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
  • www.mql5.com
В первой части данного цикла статей мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформы MetaTrader 5 и MetaTrader 4. Во второй части продолжили развитие библиотеки и сделали коллекцию исторических ордеров и сделок. В данной части повествования создадим класс для удобного...
 
Vitaly Muzichenko:

解决办法很简单:引入另一个历史变更检查,这样就不会有任何损失,而且会100%地发挥作用。

是的,它将会。如果未结订单的数量没有变化,那么历史上的数字就会改变。(我不关心待定的订单--我不使用它们),而且我们也不必为了只抓一个事件而翻遍 整个一天。

而如果用户收到了一条短信,并决定在终端显示历史记录,而不是只显示上个月的所有记录,这将是一个额外的检查与尝试所有订单,这不是致命的。

这似乎是一个很好的解决方案。而且,除了我们所拥有的东西,即一个交易账户和一个终端之外,没有任何参考资料。

 
Artyom Trishkin:

以下是我的文章#3的摘录。

-------

让我们更多地关注作为结构一部分的哈希金额。
仅仅知道账户中订单和头寸的数量发生了变化,还不足以准确判断这种变化--,一个挂单可以被删除,在这种情况下,账户中订单和头寸的总量会发生变化。但是...一个挂单可能触发并成为一个头寸。在这种情况下,订单和头寸的总量不会改变(对于对冲账户和MQL4)-,头寸的数量增加了,但订单的数量减少了,所以总量还是一样的。这对我们来说并不可行。

考虑买票。添加/删除挂单会改变账户中的票据总量,触发挂单不会改变账户中的票据总量。

考虑到总体积。你下了或删除了一个挂单- 账户上的总成交量发生变化,开仓、平仓或改变头寸 - 账户上的总成交量发生变化。这似乎是合适的,但再一次,激活一个挂单不会改变总成交量。

那么我们再来查看一个仓位属性-- 其变化的时间,以毫秒为单位:开立一个新仓位会改变总的仓位变化时间,部分平仓会改变仓位变化时间,向净值账户增加交易量会改变总的仓位变化时间。

其中哪种方法适合确定账户变化的准确位置?车票+位置改变的时间。 让我们检查一下。

  • 开仓-- 票数变化量+ 仓位变化时间量-- ,有变化。
  • 我们关闭了一个仓位--,点数发生了变化+ 仓位变化 的时间-- ,有了变化。
  • 下了一个挂单 -+ 仓位变化的时间没有变化-- 有一个变化
  • 删除的挂单-- 票据金额变化+ 仓位变化时间金额保持不变-- 变化
  • 挂单激活 - 票面金额没有变化+仓位变化时间金额有变化 - - 有变化
  • 部分仓位关闭 - 票面金额变化+ 仓位变化时间变化 - - 有变化
  • 在仓位上加量 - 票面金额保持不变+仓位变化时间改变 - - 有变化
因此,我们将使用门票+一个位置的变化时间,以毫秒为单位进行哈希求和。

不过,在这里,我没有在哈希和中添加一个符号--没有这样的先例。但我有它与检查历史相结合的工作。因此--应该没有错误地工作。然而,我将在某个时候检查它。

脂肪解决方案,还不需要这样的变体。

谢谢你!

 
Vitaly Muzichenko:

脂肪决定,还不需要这个选项。

谢谢你!

"大胆 "是因为它不是为本地解决方案而制作的,而是作为OnTradeXXXX全面替代的一个部分。有更多有历史的作品在里面。

而这是一个很大的优势--我们有现成的数据,可以在程序中对任何订单和头寸进行搜索和排序(我们不需要再次搜索订单和头寸来满足程序需要--一切都已经在列表中了)。另一个好处是,程序知道哪个订单在MQL4中的位置,这在上述版本中是做不到的。

我再重复一遍,图书馆的建立是为了让那些有太多时间和金钱而无法自己完成的人更轻松。当然,我并不坚持什么 :)

 
Aleksandr Volotko:

事实也是如此。如果未结订单的数量没有变化,历史上的数量就会变化。(我不关心待处理的订单--我不使用它们)。 而且,你不必麻烦你的 祖母,整天翻阅订单,只抓一个事件。

而如果用户收到了一条短信,并决定在终端显示历史记录,而不是只显示上个月的所有记录,这将是一个额外的检查与尝试所有订单,这不是致命的。

这似乎是一个很好的解决方案。如果你有一个交易账户和终端,你可以只使用你所拥有的,而不受任何约束。

为了不通过一整天,你可以只检查当可能导致变化的条件,打开,关闭位置,即专注于实现专家顾问用来打开,TP,SL的价格。嗯,这取决于专家顾问的逻辑,你知道什么是便宜的。

 
Aleksey Mavrin:

为了避免经历一整天,你可以只在能够导致改变、开仓、平仓的条件得到满足时才检查,也就是集中精力实现EA用来开仓、TP、SL的价格。嗯,是的,这取决于专家顾问的逻辑,你知道什么是便宜的。

一个EA(在一台电脑上,在一个大陆上)交易。另一台(在另一台电脑上,在另一个大陆)处理其功能。 已经找到了一个解决方案。

 
fxsaber:

如果你能提供一些可重复的例子(不调查交易历史),我将非常感激。

以下是出现的情况(虽然偏离了这里的主题,但在这里要求)。

切换到现场。没有MT4兼容性(当然),没有错误处理等。

交易是原始的,打开买入,在SL/TP上关闭。唯一的要点是演示OnTradeTransaction() 与 "轮询服务器"。

对我来说,在给定的时间范围内,花了2.34秒对3.06秒才通过。由于服务器功能的低负荷(只有一个位置,没有检查magik和符号),差异很小。在真实的EA中,差异会更大。通过计算信号和添加尾随止损,差异将得到轻微补偿,但它们不需要在每个tick上进行。我的ATR是按M1计算的,但为6小时(即有空间放大TF)。而追踪和盈亏平衡是按H3计算的。这一切都取决于战略。

// Test OnTradeTransaction.mqh
#property version   "1.00"
#property copyright "(c)2020 Edgar Akhmadeev"
#property link      "https://www.mql5.com/en/users/dali"
// 2020.01.27

//      Primitive expert to test OnTradeTransaction().
//      BUY only one position a time. There's no any signals.
//      Try OHLC M1 EURUSD 2016.12.19-2018.04.14 (bull trend) with default SL/TP.



//#define TESTER



#define  MT4_TICKET_TYPE
#include <MT4Orders.mqh>
#include <mql4_to_mql5.mqh>



struct PosInfoBase {
        double                  price, sl, tp;
        datetime                time;
        int                     ticket;
        ENUM_ORDER_TYPE 	 type;

        #ifndef  TESTER
                int             mn;
                string          sym;
        #endif 
};

struct PosInfo {
        PosInfoBase             base;
        int                     ticket;
};



input int       SL              = 6;
input int       TP              = 900;



MqlTick         tick;
PosInfo         posInfo         = { 0 };



#ifdef  TESTER

//*************************************************************************************************************
void 
OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
        if (trans.type == TRADE_TRANSACTION_ORDER_DELETE && trans.order_state == ORDER_STATE_PLACED) {
                // No money
                //errFatal = true;
                return;
        }
        
        static long lastTick;

        if (trans.type == TRADE_TRANSACTION_DEAL_ADD && trans.order_state == ORDER_STATE_STARTED) {
                // Open on market step1, SL/Order triggered step1, SL/Order triggered step4
                
                if (!HistoryDealSelect(trans.deal)) {
                        //errFatal = true;
                        return;
                }
                
                ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
                if (entry != DEAL_ENTRY_OUT)
                        return;
                
                ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
                if (reason != DEAL_REASON_SL && reason != DEAL_REASON_TP)
                        return;
                
                if (lastTick == tick.time_msc)
                        return;

                posInfo.base.ticket = 0;
                InitPos();

                lastTick = tick.time_msc;
                return;
        }
}



#else // TESTER



//*************************************************************************************************************
bool
Support() {
        posInfo.base.ticket = 0;
        
        int cnt = PosTotal();
        if (cnt > 1)
                return false;
        
        PosInfo _posInfo;
        
        if (cnt == 0)
                _posInfo.base.ticket = 0;
        else {
                PosInfoFill(_posInfo);
                _posInfo.ticket = _posInfo.base.ticket;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Position: process
        
        if (_posInfo.base.ticket != 0 && posInfo.ticket != 0 && _posInfo.base.ticket == posInfo.ticket) {
                // Ничего не произошло, та же позиция
                
                posInfo.base.ticket = _posInfo.base.ticket;
                posInfo.base.time = _posInfo.base.time;
                //posInfo.base.price = _posInfo.base.price;
                posInfo.base.sl = _posInfo.base.sl;
                posInfo.base.tp = _posInfo.base.tp;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Инициализация новой позиции
        
        if (posInfo.base.ticket > 0)
                return true;
        
        return InitPos();
}

#endif // TESTER



//*************************************************************************************************************
bool
InitPos() {
        if (!SymbolInfoTick(_Symbol, tick))
                return false;
        
        posInfo.base.type = ORDER_TYPE_BUY;
        posInfo.base.sl = NormalizeDouble(tick.bid - SL * Point, Digits); 
        posInfo.base.tp = NormalizeDouble(tick.bid + TP * Point, Digits);       

        ResetLastError();
        int order = OrderSend(_Symbol, posInfo.base.type, 0.01, tick.ask, 99, posInfo.base.sl, posInfo.base.tp); 
        if (order < 0)
                return false;
        
        if (!OrderSelect(order, SELECT_BY_TICKET))
                return false;

        posInfo.base.price = OrderOpenPrice();
        posInfo.ticket = posInfo.base.ticket = order;
        posInfo.base.time = tick.time;
        return true;
}



//*************************************************************************************************************
int
PosTotal() {
        int posTotal = OrdersTotal();
        int cnt = 0;
        for (int i = posTotal - 1; i >= 0; --i) {
                if (!OrderSelect(i, SELECT_BY_POS)) {
                        //errFatal = true;
                        return -1;
                }

                if (OrderType() > OP_SELL)
                        continue;

                /*
                #ifndef TESTER
                        if (OrderMagicNumber() != MagicNum)
                                continue;
                        if (OrderSymbol() != symInfo.sym)
                                continue;
                #endif 
                */
                        
                ++cnt;
        } // for
        
        return cnt;
}


        
//*************************************************************************************************************
void
PosInfoFill(PosInfo& _posInfo) {
        ZeroMemory(_posInfo);

        _posInfo.base.ticket = (int)PositionGetInteger(POSITION_TICKET);
        _posInfo.base.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
        _posInfo.base.price = PositionGetDouble(POSITION_PRICE_OPEN);
        _posInfo.base.time = (datetime)PositionGetInteger(POSITION_TIME);
        _posInfo.base.sl = PositionGetDouble(POSITION_SL);
        _posInfo.base.tp = PositionGetDouble(POSITION_TP);

        #ifndef  TESTER
                _posInfo.base.mn = (int)PositionGetInteger(POSITION_MAGIC);
                _posInfo.base.sym = PositionGetString(POSITION_SYMBOL);
        #endif 
}



//*************************************************************************************************************
void 
OnTick() {
        ResetLastError();
        if (!SymbolInfoTick(_Symbol, tick)) {
                int LE = GetLastError();
                //errFatal = true;
                return;
        }
        
        #ifdef  TESTER

                if (posInfo.base.ticket > 0)
                        return;
                
                if (!InitPos()) {
                        //errFatal = true;
                        return;
                }

        #else  // TESTER
                
                if (!Support()) {
                        //errFatal = true;
                        return;
                }
        
        #endif // TESTER
}



//*************************************************************************************************************
int 
OnInit() {
        return INIT_SUCCEEDED;
}



//*************************************************************************************************************
void 
OnDeinit(const int reason) {
}
 
prostotrader:

你已经无可救药地落后于时代了!

这些活动已经保证了 很长时间了!

假设OnTradeTransaction() 中发生了一个事件,之后必须执行一些行动,但在第一次尝试执行这个行动时发生了错误。该怎么做?很明显,它必须被重复,为此,有必要在某处保存有关重复这一行动的必要性的数据--很可能,这些数据被保存在专家顾问的通常全局变量或静态函数中。突然,我不得不重新启动终端......数据已经消失。

而当你分析目前的情况和历史时--没有任何东西可以去哪里。