Библиотеки: Virtual - страница 73

 
hini #:

Это контент UpdatePosi

В коде нигде не используется totalProfit.

 
fxsaber #:

Похоже, забыл рассказать про древний функционал.


Пример.


Результат.

Я не совсем понимаю этот процесс, почему некоторые tick изменяются и возвращают false, а некоторые возвращают true.

Operation: Tick.ask -= Offset / 2; VIRTUAL::NewTick(Tick)
Result:
 time = 2025.03.04 14:26:35.335 bid = 1.05495 ask = 1.05445 last = 0.00000 volume = 0 66566 TICK_FLAG_BID TICK_FLAG_ASK FLAG_UNKNOWN (66560)

#2 2025.03.04 14:26:35.335 buy limit 1.00 EURUSD 1.05395 0.00000 1.05595 1.05445 0.00 0.00 0.00 0 - 00:00:00

Balance = 1000.00, Equity = 1000.00, Profit = 0.00, 2025.03.04 - 2025.03.04 14:26:35
VIRTUAL::IsChanged() = false
 
fxsaber #:

В коде нигде не используется totalProfit.

m_totalProfit = totalProfit + totalComm;    Вызов будет выполнен по завершении цикла

 
hini #:

Я не совсем понимаю этот процесс, почему некоторые tick изменяются и возвращают false, а некоторые возвращают true.

Переведите комментарий.

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: Virtual

fxsaber, 2025.03.04 12:27

VIRTUAL::IsChanged(); // Возвращает true только в том случае, если что-то произошло с ордерами с предыдущего вызова этой функции в том же виртуальном окружении.
 
fxsaber #:

Переведите комментарий.

ok

 
hini #:

m_totalProfit = totalProfit + totalComm;    Вызов будет выполнен по завершении цикла

Обновите библиотеку и попробуйте это решение.

class CStrategyBase
{
private:
  double m_PriceAvgBuy;
  double m_PriceAvgSell;

  double m_totalComm;
  double m_totalSwap;

  const double m_TickValue;

  void CalcProfit()
  {    
    MqlTick Tick;
    
    if (SymbolInfoTick(_Symbol, Tick))                               
      m_totalProfit = ((m_buyCnt ? (Tick.bid * m_buyLot - m_PriceAvgBuy) : 0) -
                       (m_sellCnt ? (Tick.ask * m_sellLot - m_PriceAvgSell) : 0)) * m_TickValue +
                      m_totalComm + m_totalSwap;
                      
    Print(__FUNCSIG__);                      
  }
  
protected:
  int m_buyCnt, m_sellCnt;
  double m_buyLot, m_sellLot;
  
  double m_firstBuyPrice, m_firstSellPrice;
  double m_lastBuyPrice, m_lastSellPrice;
  
  double m_totalProfit;
      
  void ResetPosiVariable()
  {
    m_PriceAvgBuy = 0;
    m_PriceAvgSell = 0;
    
    m_buyCnt = 0;
    m_sellCnt = 0;

    m_buyLot = 0;
    m_sellLot = 0;
/*
    m_firstBuyPrice = 0;
    m_firstSellPrice = 0;
    
    m_lastBuyPrice = 0;
    m_lastSellPrice = 0;

    m_totalProfit = 0;
*/    
  }
  
public:
  const MAGIC_TYPE m_magic;

  CStrategyBase( const MAGIC_TYPE iMagic = 0 ) : m_magic(iMagic),
                                                 // VIRTUAL - required!
                                                 m_TickValue(SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) /
                                                             SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE))
  {
    if (!VIRTUAL::GetHandle())
      ::Alert("m_TickValue - not created in Virtual.");
  }

  // https://www.mql5.com/ru/forum/282062/page72#comment_56066035
  void               UpdatePosi() {
    int totalPosi = OrdersTotal();
    CStrategyBase::ResetPosiVariable();
    datetime firstBuyOpenTime = 0, firstSellOpenTime = 0;
    datetime lastBuyOpenTime = 0, lastSellOpenTime = 0;
    double totalProfit = 0, totalComm = 0, totalSwap = 0;
    for(int i = OrdersTotal() - 1; i >= 0; --i) {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if(OrderMagicNumber() != m_magic) continue;
      totalProfit += OrderProfit(); // + OrderSwap();// + OrderCommission();
      totalComm += OrderCommission();
      totalSwap += OrderSwap();
      ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)OrderType();
      datetime orderOpenTime = OrderOpenTime();
      double orderOpenPrice = OrderOpenPrice();
      if (type == OP_BUY) {
        m_buyCnt++;
        m_buyLot += OrderLots();
        m_PriceAvgBuy += OrderLots() * orderOpenPrice;
        if (firstBuyOpenTime == 0 || orderOpenTime < firstBuyOpenTime) {
          m_firstBuyPrice = orderOpenPrice;
          firstBuyOpenTime = orderOpenTime;
        }
        if (lastBuyOpenTime == 0 || orderOpenTime > lastBuyOpenTime) {
          m_lastBuyPrice = orderOpenPrice;
          lastBuyOpenTime = orderOpenTime;
        }
      } else if (type == OP_SELL) {
        m_sellCnt++;
        m_sellLot += OrderLots();
        m_PriceAvgSell += OrderLots() * orderOpenPrice;        
        if (firstSellOpenTime == 0 || orderOpenTime < firstSellOpenTime) {
          m_firstSellPrice = orderOpenPrice;
          firstSellOpenTime = orderOpenTime;
        }
        if (lastSellOpenTime == 0 || orderOpenTime > lastSellOpenTime) {
          m_lastSellPrice = orderOpenPrice;
          lastSellOpenTime = orderOpenTime;
        }
      }
    }

    m_totalComm = totalComm;
    m_totalSwap = totalSwap;
    
    // https://www.mql5.com/ru/forum/282062/page73#comment_56066148
    m_totalProfit = totalProfit + m_totalComm + m_totalSwap;

    Print(__FUNCSIG__);    
  }

  void               UpdatePosiFast() {
    if (VIRTUAL::IsChanged())
      this.UpdatePosi();
    else
      this.CalcProfit();
  }

  
  double GetProfit() const
  {
    return(m_totalProfit);
  }
};


Проверка.

void OnStart()
{
  MqlTick Tick;  
  SymbolInfoTick(_Symbol, Tick);
  
  _VS(VIRTUAL::Create(1000.0));
  CStrategyBase Strategy;
  
  for (int i = 1; i <= 3; i++)
  {
    Tick.ask -= _Point;
    Tick.bid -= _Point;
    
    VIRTUAL::NewTick(Tick);
    
    OrderSend(_Symbol, OP_BUY, i, Tick.ask, 0, 0, 0);
    OrderSend(_Symbol, OP_SELL, i + 1, Tick.bid, 0, 0, 0);
  }
  
  Print(VIRTUAL::ToString());

  for (int i = 0; i < 3; i++)
  {
    Tick.ask += _Point;
    Tick.bid += _Point;
    
    VIRTUAL::NewTick(Tick);
    
    Strategy.UpdatePosiFast();
    Print(Strategy.GetProfit());
  }
  
  // Check.
  Strategy.UpdatePosi();
  Print(Strategy.GetProfit());    

  Print(VIRTUAL::ToString());
}


Результат.

 time = 2025.03.04 19:09:12.162 bid = 189.448 ask = 189.454 last = 0.000 volume = 0 66566 TICK_FLAG_BID TICK_FLAG_ASK FLAG_UNKNOWN (66560)

#2 2025.03.04 19:09:12.162 buy 1.00 GBPJPY 189.456 0.000 0.000 189.448 0.00 0.00 -8.00 0: -8 (-8) - 00:00:00
#3 2025.03.04 19:09:12.162 sell 2.00 GBPJPY 189.450 0.000 0.000 189.454 0.00 0.00 -8.00 0: -4 (-4) - 00:00:00
#4 2025.03.04 19:09:12.162 buy 2.00 GBPJPY 189.455 0.000 0.000 189.448 0.00 0.00 -14.00 0: -7 (-7) - 00:00:00
#5 2025.03.04 19:09:12.162 sell 3.00 GBPJPY 189.449 0.000 0.000 189.454 0.00 0.00 -15.00 0: -5 (-5) - 00:00:00
#6 2025.03.04 19:09:12.162 buy 3.00 GBPJPY 189.454 0.000 0.000 189.448 0.00 0.00 -18.00 0: -6 (-6) - 00:00:00
#7 2025.03.04 19:09:12.162 sell 4.00 GBPJPY 189.448 0.000 0.000 189.454 0.00 0.00 -24.00 0: -6 (-6) - 00:00:00

Balance = 1000.00, Equity = 913.00, Profit = -87.00, 2025.03.04 - 2025.03.04 19:09:12
void CStrategyBase::UpdatePosi()
-90.00000000000341
void CStrategyBase::CalcProfit()
-93.00000000007458
void CStrategyBase::CalcProfit()
-96.00000000000364
void CStrategyBase::UpdatePosi()
-96.00000000003206
 time = 2025.03.04 19:09:12.162 bid = 189.451 ask = 189.457 last = 0.000 volume = 0 66566 TICK_FLAG_BID TICK_FLAG_ASK FLAG_UNKNOWN (66560)

#2 2025.03.04 19:09:12.162 buy 1.00 GBPJPY 189.456 0.000 0.000 189.451 0.00 0.00 -5.00 0: -5 (-5) - 00:00:00
#3 2025.03.04 19:09:12.162 sell 2.00 GBPJPY 189.450 0.000 0.000 189.457 0.00 0.00 -14.00 0: -7 (-7) - 00:00:00
#4 2025.03.04 19:09:12.162 buy 2.00 GBPJPY 189.455 0.000 0.000 189.451 0.00 0.00 -8.00 0: -4 (-4) - 00:00:00
#5 2025.03.04 19:09:12.162 sell 3.00 GBPJPY 189.449 0.000 0.000 189.457 0.00 0.00 -24.00 0: -8 (-8) - 00:00:00
#6 2025.03.04 19:09:12.162 buy 3.00 GBPJPY 189.454 0.000 0.000 189.451 0.00 0.00 -9.00 0: -3 (-3) - 00:00:00
#7 2025.03.04 19:09:12.162 sell 4.00 GBPJPY 189.448 0.000 0.000 189.457 0.00 0.00 -36.00 0: -9 (-9) - 00:00:00

Balance = 1000.00, Equity = 904.00, Profit = -96.00, 2025.03.04 - 2025.03.04 19:09:12


UpdatePosiFast совпадает с UpdatePosi, но при этом почти не использует OrdersTotal-цикл.


Что-то мне подсказывает, что такое решение никто не использует. И если воспользуетесь этим механизмом, получите самый быстрый Мартингейл в индустрии.

 
fxsaber #:

Обновите библиотеку и попробуйте это решение.


Проверка.


Результат.


UpdatePosiFast совпадает с UpdatePosi, но при этом почти не использует OrdersTotal-цикл.


Что-то мне подсказывает, что такое решение никто не использует. И если воспользуетесь этим механизмом, получите самый быстрый Мартингейл в индустрии.

Большое спасибо за ваше решение. После его применения обработка 10 миллионов тиков заняла менее секунды, что значительно повысило скорость. Результаты тестирования полностью совпадают.
 
hini #:
обработка 10 миллионов тиков заняла менее секунды

Вы можете замерить максимальную теоретическую производительность на своей машине. И сравнить, во сколько раз ваш советник медленнее вычисляется.

 
fxsaber #:

Вы можете замерить максимальную теоретическую производительность на своей машине. И сравнить, во сколько раз ваш советник медленнее вычисляется.

Это результаты тестирования производительности, но на торговой системе обработка 10 миллионов тиков занимает 0,6 секунды, что, похоже, все еще оставляет место для улучшения.

 
hini #:

Это результаты тестирования производительности, но на торговой системе обработка 10 миллионов тиков занимает 0,6 секунды, что, похоже, все еще оставляет место для улучшения.

Я проверил код, и, похоже, уже нет места для улучшений. Обработка 10 миллионов тиков за 0,5 секунды — это предел.