Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Simulation system

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Simulation system

    I am testing strategy using Zen Fire demo feed. I have faced with interesting problem while testing strategy on different contracts.
    Have tested it on NQ 09-12, ES 09-12, YM-09-12 with no problems.

    When running strategy on FDAX contract - NinjaTrader just freezes. Then ninjaTrader starts rapidly increasing amount of memory and that's all I can get. Having encountered this problem today - I made strategy logging its actions into file. That is when I found out reason for rapid memory increase - when strategy is run through historical data, it gets into 'simulation loop'. Since Log function is used to print information - Ninja's memory increases endlessly, and file, where logs are printed, increases as well.

    Strategy is based on unmanaged approach, with CalculateOnbarClose=true. Uses onExecution() callback for decisions. It uses also additional 1 minute timeframe. Here follows entire code of onExecution
    Code:
            protected override void Initialize()
            {
                CalculateOnBarClose = true;
                Unmanaged=true;
                ExitOnClose=true;
                
                _startTime =DateTime.Parse(startTime);
                _endTime =DateTime.Parse(endTime);
                _stopTime =DateTime.Parse(stopTime);
                
        
                Add(PeriodType.Minute,1);
                _bHasStarted=false;
                _bEndTimeIsReached=false;
                
                
            }
            protected override void OnExecution(IExecution execution)
            {
                Log("OnFilled order update at: " + Times[1][0].ToString(),LogLevel.Information);
                printLn("OnFilled order update at: " + Time[0].ToString());//tracing to file
                
                int pos =Position.Quantity;
                if (Position.MarketPosition==MarketPosition.Short)
                    pos=-pos;
                int lotsAmountForBuy=0,lotsAmountForSell=0;
                if (pos>0)
                {
                    if (Math.Abs(pos)* 2>  maximumContracts) //maximumContracts=4
                        lotsAmountForBuy=maximumContracts-Math.Abs(pos);
                    else
                        lotsAmountForBuy=Math.Abs(pos);
                    if (_bEndTimeIsReached)
                    {
                        lotsAmountForSell=Math.Abs(pos);
                        lotsAmountForBuy=0;
                        cancelLongEntryOrder();
                    }
                    else 
                    {
                        lotsAmountForSell=Math.Abs(pos)+openingPositions; //openingPositions=1
                    }
                }
                else if (pos<0)
                {
                    if (Math.Abs(pos) * 2>  maximumContracts)
                        lotsAmountForSell=maximumContracts-Math.Abs(pos);
                    else
                        lotsAmountForSell=Math.Abs(pos);
                    if (_bEndTimeIsReached)
                    {
                        lotsAmountForBuy=Math.Abs(pos);
                        lotsAmountForSell=0;
                        cancelShortEntryOrder();
    
                    }
                    else 
                    {
                        lotsAmountForBuy=Math.Abs(pos)+openingPositions;
                    }
                }
                else if (pos==0)
                {
                    if (_bEndTimeIsReached)
                    {
                        lotsAmountForSell=0;
                        lotsAmountForBuy=0;
                        cancelOrders();
                    }    
                }            
                
                
                double filledPrice=execution.Price;
                double newAvgPrice=Position.AvgPrice;
                if (pos==0)
                {
                    newAvgPrice=filledPrice;
                }
                double buyPrice=newAvgPrice;    
                double sellPrice=newAvgPrice;
    
                buyPrice= buyPrice - profitTarget* TickSize;//profitTarget=10
                sellPrice=  sellPrice + profitTarget* TickSize;
    
                
                Log("Position: " + Position.Quantity.ToString() + "Direction: " + Position.MarketPosition.ToString(),LogLevel.Information);
                Log("BuyPrice: " + buyPrice.ToString(),LogLevel.Information);
                Log("SellPrice: " + sellPrice.ToString(),LogLevel.Information);
                Log("LotsAmountToBuy: " + lotsAmountForBuy.ToString(),LogLevel.Information);
                Log("LotsAmountToSell: " + lotsAmountForSell.ToString(),LogLevel.Information);            
                Log("UnrealizedPnL: " + Position.GetProfitLoss(execution.Price,PerformanceUnit.Currency).ToString(),LogLevel.Information);            
    
                printLn("Position: " + Position.Quantity.ToString() + "Direction: " + Position.MarketPosition.ToString());
                printLn("BuyPrice: " + buyPrice.ToString());
                printLn("SellPrice: " + sellPrice.ToString());
                printLn("LotsAmountToBuy: " + lotsAmountForBuy.ToString());
                printLn("LotsAmountToSell: " + lotsAmountForSell.ToString());            
                printLn("UnrealizedPnL: " + Position.GetProfitLoss(execution.Price,PerformanceUnit.Currency).ToString());            
                
                
                if (longEntryOrder != null && longEntryOrder == execution.Order)
                {
                    Log("Buy order is filled at " + execution.Order.AvgFillPrice,LogLevel.Information);
                    printLn("Buy order is filled at " + execution.Order.AvgFillPrice);
                    cancelOrders();
                    if (lotsAmountForBuy!=0)
                        longEntryOrder=SubmitOrder(0,OrderAction.Buy,OrderType.Limit,lotsAmountForBuy,buyPrice,0,"","");
                    if (lotsAmountForSell!=0)
                        shortEntryOrder=SubmitOrder(0,OrderAction.Sell,OrderType.Limit,lotsAmountForSell,sellPrice,0,"","");
    
    
                }
                if (shortEntryOrder != null && shortEntryOrder == execution.Order)
                {
                    Log("Sell order is filled at " + execution.Order.AvgFillPrice,LogLevel.Information);
                    printLn("Sell order is filled at " + execution.Order.AvgFillPrice);
                    cancelOrders();                
                    if (lotsAmountForBuy!=0)
                        longEntryOrder=SubmitOrder(0,OrderAction.Buy,OrderType.Limit,lotsAmountForBuy,buyPrice,0,"","");
    
                    if (lotsAmountForSell!=0)
                        shortEntryOrder=SubmitOrder(0,OrderAction.Sell,OrderType.Limit,lotsAmountForSell,sellPrice,0,"","");
                }
                if (closePositionOrder!=null && closePositionOrder==execution.Order)
                {
                    Log("Close positoin order is filled at " + execution.Order.AvgFillPrice,LogLevel.Information);
                    printLn("Close positoin order is filled at " + execution.Order.AvgFillPrice);
                }
        
            }
    And here is what I have in logs, printed in file:

    Sending entry orders at : 25.06.2012 9:21:00
    Entry BuyPrice: 6265,5
    Entry SellPrice: 6267,5
    OnFilled order update at: 25.06.2012 9:21:00
    Position: 1Direction: Short
    BuyPrice: 6262,5
    SellPrice: 6272,5
    LotsAmountToBuy: 2
    LotsAmountToSell: 1
    UnrealizedPnL: 0
    Sell order is filled at 6267,5
    OnFilled order update at: 25.06.2012 9:27:00
    Position: 1Direction: Long
    BuyPrice: 6257,5
    SellPrice: 6267,5
    LotsAmountToBuy: 1
    LotsAmountToSell: 2
    UnrealizedPnL: 0
    Buy order is filled at 6262,5
    OnFilled order update at: 25.06.2012 9:30:00
    Position: 2Direction: Long
    BuyPrice: 6255
    SellPrice: 6265
    LotsAmountToBuy: 2
    LotsAmountToSell: 3
    UnrealizedPnL: -125
    Buy order is filled at 6257,5
    OnFilled order update at: 25.06.2012 9:30:00
    Position: 4Direction: Long
    BuyPrice: 6252,5
    SellPrice: 6262,5
    LotsAmountToBuy: 0
    LotsAmountToSell: 5
    UnrealizedPnL: -250
    Buy order is filled at 6255
    OnFilled order update at: 25.06.2012 9:30:00
    Position: 1Direction: Short
    BuyPrice: 6257,5
    SellPrice: 6267,5
    LotsAmountToBuy: 2
    LotsAmountToSell: 1
    UnrealizedPnL: 0
    Sell order is filled at 6262,5
    OnFilled order update at: 25.06.2012 9:30:00
    Position: 1Direction: Long
    BuyPrice: 6252,5
    SellPrice: 6262,5
    LotsAmountToBuy: 1
    LotsAmountToSell: 2
    UnrealizedPnL: 0
    Buy order is filled at 6257,5

    OnFilled order update at: 25.06.2012 9:30:00
    Position: 1Direction: Short
    BuyPrice: 6257,5
    SellPrice: 6267,5
    LotsAmountToBuy: 2
    LotsAmountToSell: 1
    UnrealizedPnL: 0
    Sell order is filled at 6262,5
    OnFilled order update at: 25.06.2012 9:30:00
    Position: 1Direction: Long
    BuyPrice: 6252,5
    SellPrice: 6262,5
    LotsAmountToBuy: 1
    LotsAmountToSell: 2
    UnrealizedPnL: 0
    Buy order is filled at 6257,5


    The rest of the log file is filled with the repetition of selected above in bold.
    It just keeps executing buy limit at 6257.5 and sell limit order at 6262.5 in the loop.
    Both prices are within ranges of 09:30-09:31 bar. I may believe that orders might have played ping pong couple of times during this minute, but not 1000 times.
    So from what I gathered - I would assume that it is some kind of simulation system bug. But I do believe that you have tested it extensively, so I am looking for any suggestion or hint as to where might be the problem.

    #2
    Hi Andreano,

    Are you sure those are only two unique orders? You're submitting those orders in OnExecution() so maybe you've coded an endless loop there.

    Best way to track this down is simplify so you can follow code flow. If you're driving orders from OnExecution() it's entirely possible to see this kind of loop.
    Last edited by NinjaTrader_RyanM1; 06-29-2012, 01:00 PM.
    Ryan M.NinjaTrader Customer Service

    Comment


      #3
      I debugged strategy, but saw nothing different from what I gathered from logs.
      Basically here is what happens in the loop:
      Strategy sends sell limit order at 6262.5 for 2 lots to cover previous position and open new.
      It gets filled. When it is filled strategy sends buy limit order for 2 lots(to cover long position and open long) at 6257,5 and sell limit order for 1 lot 6267,5 ( to increase short position).
      Buy limit order at 6257.5 is reported to be filled. Sell limit order is canceled.
      And again sell limit order is sent at 6262.5 (2 lots) and buy limit order is sent at 6252.5. But sell limit order is filled. Here we have got a loop that is repeated countlessly.
      Simulation is playing a ping pong between 2 orders:
      Sell limit at 6262.5 (2 lots)
      Buy limit at 6257.5 (2 lots)
      Yes. I do send them repeatedly. But according to simulation system - they keep being reported filled. This all hapens within 1 minute bar. Which is Open:6265; High:6265; Low:6254; Close:6255.5 . Time 09:30-09:31.
      So it seems that when these 2 orders is within ranges of 1 bar - simulation system will always report order to be filled.
      How exactly is it supposed to act? I would assume that it checks tick data and simulate order fulfillment based on it? But it doesn't seem to be true? At least that is how I expect strategy to work on real time feed.




      Are you sure those are only two unique orders?
      No. I ran strategy to StrategyAnalyzer and found similar problem on other contracts or on FDAX, but in different situation.

      Comment


        #4
        This does not work the same backtest compared to real time. See here for more information about the differences:


        When you run a real time strategy it will first process all historical bars. You've coded a situation where it can't move beyond a particular bar since it's looping the same two orders in OnExecution() until NT is out of memory.

        If this strategy only runs into issues on historical but not real time bars, you can disable processing of Historical bars by adding statement below to top line of OnBarUpdate().
        if (Historical) return;

        Ryan M.NinjaTrader Customer Service

        Comment


          #5
          This does not work the same backtest compared to real time. See here for more information about the differences:
          http://www.ninjatrader.com/support/h...ime_vs_bac.htm
          Thank you for links.
          You've coded a situation where it can't move beyond a particular bar since it's looping the same two orders in OnExecution() until NT is out of memory.
          I would like to understand one important thing: is there anything I could to to avoid this loop(except obvious =amend prices of order, so they would not be both in bar ranges). Should simulation system (in historical mode) act the way it does?
          Whenever order is sent and it's price is within current bar ranges, it will be simulated as filled unconditionally. Is that a correct understanding of how simulation system work(in historical mode)?
          And that is why creation of such loops is possible?

          If this strategy only runs into issues on historical but not real time bars, you can disable processing of Historical bars by adding statement below to top line of OnBarUpdate().
          if (Historical) return;
          There were no problems on real-time.I will probably go this way. But before that I would like to assure that I can't do anything about it. Backtesting is an important aspect of strategy, so I don't want to just ditch it, before clarification of details.

          Comment


            #6
            Yes, this type of behavior is expected with your strategy historically. The main thing contributing here is driving order submission through OnExecution().

            If you want to work historically in bar-by-bar basis, then consider working mainly in OnBarUpdate() to drive order submission for entry signals. There can still be advantages to working in OnExecution() historically. It is recommended only for advanced programmers -- you'll need to take care that you don't code these types of situations.
            Ryan M.NinjaTrader Customer Service

            Comment


              #7
              Ryan,
              Thank you for the feedback.

              Comment

              Latest Posts

              Collapse

              Topics Statistics Last Post
              Started by Geovanny Suaza, 02-11-2026, 06:32 PM
              0 responses
              666 views
              0 likes
              Last Post Geovanny Suaza  
              Started by Geovanny Suaza, 02-11-2026, 05:51 PM
              0 responses
              376 views
              1 like
              Last Post Geovanny Suaza  
              Started by Mindset, 02-09-2026, 11:44 AM
              0 responses
              110 views
              0 likes
              Last Post Mindset
              by Mindset
               
              Started by Geovanny Suaza, 02-02-2026, 12:30 PM
              0 responses
              575 views
              1 like
              Last Post Geovanny Suaza  
              Started by RFrosty, 01-28-2026, 06:49 PM
              0 responses
              580 views
              1 like
              Last Post RFrosty
              by RFrosty
               
              Working...
              X