Right time to increment idTrade?

Issue #12 new
Max created an issue

Let’s suppose I want to send every minute buy limit order to exchange. When next candle is formed and order not executed, I will be cancel my previous buy limit order and send new one with new price.

I think it’s good idea to increment idTrade on Cancel event, something like that piece of code :

std::function<void()> quoteLongEnter = [&]() {
buy = new Order( OrderSide::BUY, OrderType::LIMIT, levelLongEnter, "long", idTrade );
buy->onExecuted = [&]() { 
      state = ProcessingState::LONG; 
.
};
buy->onCancelled = [&]() { 
      idTrade++;
      state = ProcessingState::INIT; 
};

    bt.SendOrder( buy );

  };

But if I run this code R crash! :(

If I not increment idTrade on Cancel event, code was run smoothly, but trading log is inconsistent: only first order added to trade (see attachments).

Comments (4)

  1. Stanislav Kovalevsky repo owner

    Could you provide me with the strategy cpp code similar to QuantTools examples so I could debug it. I need the simplest version of it. R shouldn't crash anyway. I will add relevant exception to Processor.

  2. Max reporter

    As I understood the crash happen when processor trying to add record in Trades table with already exist ID due to incorrect strategy code / wrong TradeID increment.

    // [[Rcpp::plugins(cpp11)]]
    // [[Rcpp::depends(QuantTools)]]
    #include <Rcpp.h>
    #include "BackTest.h"
    
    // [[Rcpp::export]] 
    Rcpp::List breakout_limit_orders(
        Rcpp::DataFrame ticks,
        Rcpp::List parameters,
        Rcpp::List options,
        bool fast = false
    ) {
    
      int    smaPeriod = parameters["sma_period" ];
      int    timeFrame  = parameters["timeframe" ];
      enum class ProcessingState{ INIT, LONG, FLAT };
      ProcessingState state = ProcessingState::INIT;
      int idTrade = 0;
      Sma sma( smaPeriod );
    
      Processor bt( timeFrame );
    
      bt.SetOptions( options );
    
      bool isTradingHours = not bt.IsTradingHoursSet();
    
      Order* buy;
    
      double levelLongEnter;
      double stopLoss = -0.05;
      double takeProfit = 0.1;
    
      std::function<void()> quoteLongEnter = [&]() {
    
        buy = new Order( OrderSide::BUY, OrderType::LIMIT, levelLongEnter, "long", idTrade );
    
        buy->onExecuted = [&]() { 
          state = ProcessingState::LONG; 
    
          Order* buy_tp = new Order( OrderSide::SELL, OrderType::LIMIT, levelLongEnter+takeProfit, "long take profit", idTrade );
          buy_tp->onExecuted = [&]() { 
            state = ProcessingState::INIT; 
            idTrade++; 
          };
          bt.SendOrder( buy_tp ); 
        };
    
        buy->onCancelled = [&]() { 
          idTrade++; // the problem is here !!! comment this line and crash disappear
          quoteLongEnter ();
        }; 
    
        bt.SendOrder( buy );
      };
    
    
      bt.onMarketOpen  = [&]() { isTradingHours = true; };
    
      bt.onMarketClose = [&]() {
        printf("market close!\n");
    
        isTradingHours = false;
    
        if( state == ProcessingState::LONG ) {
    
          Order* sell = new Order( OrderSide::SELL, OrderType::MARKET, NA_REAL, "EOD", idTrade );
    
          sell->onExecuted = [&]() {
            state = ProcessingState::INIT; 
            idTrade++; 
          };
          bt.SendOrder( sell ); 
        }
    
      };
    
    
      bt.onCandle = [&]( Candle candle ) {
        sma.Add( candle.close );
    
        if( not sma.IsFormed() ) return;
        if( not bt.CanTrade()  ) return;
        if( not isTradingHours ) return;
    
        levelLongEnter  = sma.GetValue();
    
        switch(state) {
    
        case ProcessingState::INIT : 
          quoteLongEnter();
          state = ProcessingState::FLAT;
          break;
    
        case ProcessingState::FLAT : 
          bt.CancelOrders(); // re-quote on cancel event!
          break;
    
        case ProcessingState::LONG : 
          double pnl = candle.close - buy->GetExecutionPrice();
          if( pnl < stopLoss ) { // create market order to close long position
    
            bt.CancelOrders(); // cancel take profit
            Order* sell = new Order( OrderSide::SELL, OrderType::MARKET, NA_REAL, "long stop loss", idTrade );
    
            sell->onExecuted = [&]() {
              state = ProcessingState::INIT; 
              idTrade++; 
            };
    
            bt.SendOrder( sell ); 
          }
    
          break;
        }
    
      };
    
      bt.Feed( ticks );
    
      Rcpp::List summary = bt.GetSummary();
    
      if( fast ) return summary;
    
      Rcpp::List indicators = ListBuilder().AsDataTable()
                                           .Add( bt.GetCandles()                                )
                                           .Add( "sma"     , sma.GetHistory()                   )
                                           .Add( "pnl"     , bt.GetOnCandleMarketValueHistory() )
                                           .Add( "drawdown", bt.GetOnCandleDrawDownHistory()    );
    
      return ListBuilder()
        .Add( "summary"          , summary                              )
        .Add( "trades"           , bt.GetTrades()                       )
        .Add( "orders"           , bt.GetOrders()                       )
        .Add( "indicators"       , indicators                           )
        .Add( "daily_performance", bt.GetOnDayClosePerformanceHistory() );
    }
    
  3. Log in to comment