Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Question about using AtmStrategyCreate(). How to create multiple orders?

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

    Question about using AtmStrategyCreate(). How to create multiple orders?

    Howdy.

    I am new to attempting to use ATM strategies.

    I have been working with the "sampleATMstrategy" that ships with NT.

    I also recreated THIS example, and have attached it below(not necessary to download), and is called "TestBed." It will reside in a folder in Strategies called "MaMS". The primary difference between the example linked above, and the one attached, is that I have changed it to a limit order, and changed the way it initially finds a trade(by checking the orderid length).

    This brings me to MY problem.

    I want to create an ATM strategy, that places a grid of orders. The number of orders and the prices will be a user input. The number of levels and the spacing could vary. I am attaching an IMAGE of what that looks like. You can see, it simply places 5 buy limits below the current price. These orders have been done by an atm strategy I created. This is also attached, and it is called, "orderPlaceReplace."

    Also of note, is that I want to orders to continually be replaced(user input option), if it goes on to hit its profit target. But initially, I am just attempting to get the order placement working properly.

    My solution to this, was to create a List/Array, and store the price levels and other necessary items, and put the necessary info there. This MOSTLY works now.

    The problem is within the callback function. I am wondering if there is a problem with putting List elements into the callback function?

    For example, THIS below works fine:
    Code:
    AtmStrategyCreate(OrderAction.Buy, OrderType.Limit, Low[0], Low[0]-20*myPipSize, TimeInForce.Gtc,
        atmStrategyOrderId, "AtmStrategyTemplate", atmStrategyId, (atmCallbackErrorCode, atmCallbackId) => {
    
       // checks that the call back is returned for the current atmStrategyId stored
       if (atmCallbackId == atmStrategyId && atmCallbackErrorCode == Cbi.ErrorCode.NoError)
       {
          isAtmStrategyCreated = true;
       }
    });

    But this does NOT work as expected. In this snipped, the "i" is used, as this is in a loop that cycles through each of the price levels.
    Code:
    AtmStrategyCreate(OrderAction.Buy, OrderType.Limit, _price[i], _stopPrice[i], TimeInForce.Gtc,
       _orderId[i], "AtmStrategyTemplate", _atmStrategyId[i], (atmCallbackErrorCode, atmCallBackId) => {
    
       if (atmCallbackErrorCode == ErrorCode.NoError  &&  atmCallBackId == _atmStrategyId[i] /**/)
       {
          _isAtmStrategyCreated[i] = true;
       }
    });

    Again, the above actually does place the orders on the chart in the way that I want. But, my solution does not seem to generate the proper Id(atmCallBackId) that matches the strategyId generated(atmStrategyId[i]). As such, the right side of that if statement inside AtmStrategyCreate() never evaluates to true.

    So the questions,
    • are there any issues with using List values IN the AtmStrategyCreate() method?
    • does my logic of creating a list of price levels, then looping through that list and individually creating each order make sense?

    THanks,
    FP
    Attached Files
    Last edited by forrestang; 04-11-2022, 10:03 AM.

    #2
    Also, to avoid having to download the entire strategy, here is what that loop looks like, so the context may be more seen.

    Code:
    for (int i=0; i < _price.Count; i++)
    {
       if (_orderId[i].Length == 0 && _atmStrategyId[i].Length == 0 && Close[0] > _price[i])
       {
          // _isAtmStrategyCreated[i] =false; //reset atm strat, so we can check later
          _atmStrategyId[i] =GetAtmStrategyUniqueId();
          _orderId[i] =GetAtmStrategyUniqueId();
    
          AtmStrategyCreate(OrderAction.Buy, OrderType.Limit, _price[i], _stopPrice[i], TimeInForce.Gtc,
             _orderId[i], "AtmStrategyTemplate", _atmStrategyId[i], (atmCallbackErrorCode, atmCallBackId) => {
    
             if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == _atmStrategyId[i] /**/)
             {
                _isAtmStrategyCreated[i] = true;
             }
          });
       }
    }

    Comment


      #3
      Hi forrestang, thanks for posting. My test works. I attached it to this post. After you run your script, check the Log tab of the Control Center for any errors. There is something wrong with your script in either the array set up or the prices you are giving the limit orders.

      Kind regards,
      -ChrisL
      Attached Files

      Comment


        #4
        On your end, if you check the List value named, "isAtmStrategyCreated[i]"

        Does this value ever evaluate to true on your end?

        I added it near the bottom of the script you posted, and it is always false. Here is the onBarUpdate() I've changed on yours, which is just to add the print stuff near the bottom.

        Code:
        protected override void OnBarUpdate()
        {
            if(State == State.Historical)
                return;
        
        ​​​​​​​    if(!generate)
        ​​​​​​​    {
        ​​​​​​​    ​​​​​​​    for(int i = 0; i < 3; i++)
        ​​​​​​​    ​​​​​​​    {
        ​​​​​​​    ​​​​​​​    ​​​​​​​    isAtmStrategyCreated.Add(false);
        ​​​​​​​    ​​​​​​​    ​​​​​​​    atmStrategyId.Add(GetAtmStrategyUniqueId());
        ​​​​​​​    ​​​​​​​    ​​​​​​​    orderId.Add(GetAtmStrategyUniqueId());
        
        ​​​​​​​    ​​​​​​​    ​​​​​​​    AtmStrategyCreate(OrderAction.Buy, OrderType.Limit, Low[0]-(TickSize*((i+1)*10)), 0, TimeInForce.Day, orderId[i], "AtmStrategyTemplate", atmStrategyId[i], ​​​​​​​    ​​​​​​​    ​​​​​​​    ​​​​​​​    (atmCallbackErrorCode, atmCallBackId) => {
        ​​​​​​​    ​​​​​​​    ​​​​​​​    //check that the atm strategy create did not result in error, and that the requested atm strategy matches the id in callback
        ​​​​​​​    ​​​​​​​    ​​​​​​​    ​​​​​​​    if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == atmStrategyId[i])
        ​​​​​​​    ​​​​​​​    ​​​​​​​    ​​​​​​​    ​​​​​​​    isAtmStrategyCreated[i] = true;
        ​​​​​​​    ​​​​​​​    ​​​​​​​    });
        ​​​​​​​    ​​​​​​​    }
        
        ​​​​​​​    ​​​​​​​    generate = true;
        ​​​​​​​    ​​​​​​​    Print(" _ " +atmStrategyId[0]+" _ " +isAtmStrategyCreated[0]+" _ " +" _ " +orderId[0]);
        ​​​​​​​    ​​​​​​​    Print(" _ " +atmStrategyId[1]+" _ " +isAtmStrategyCreated[1]+" _ " +" _ " +orderId[1]);
        ​​​​​​​    ​​​​​​​    Print(" _ " +atmStrategyId[2]+" _ " +isAtmStrategyCreated[2]+" _ " +" _ " +orderId[2]);
        ​​​​​​​    }
        }

        Comment


          #5
          Hi forrestang, its happening because of the for loop processing faster than the callback method. I'm still working on a solution for it. Ill follow up tomorrow with more details on how to fix it.

          Kind regards,
          -ChrisL

          Comment


            #6
            Originally posted by NinjaTrader_ChrisL View Post
            Hi forrestang, its happening because of the for loop processing faster than the callback method. I'm still working on a solution for it. Ill follow up tomorrow with more details on how to fix it.

            Kind regards,
            -ChrisL
            Thanks a ton, as I'd have NEVER figured that out.

            Comment


              #7
              I am sure there is something better than this, but I was able to stick this at the very bottom of the loop, and it will seems to function properly, in that it stops the loop for long enough to allow the async function to get whatever it is getting.

              I'm not sure how reliable this is. I was trying different values, and it seems to work with a delay of 50ms but not 40ms. I am not sure if this would ever very, or what?

              I put this in my other script, and it works fine, but I had to use a 200ms delay, so it appears its not consistent.

              It seems there must be some way to check when the method has done what it needs to do, instead of using a fixed amount of time?

              Attaching a screenshot of what I mean.

              Code:
              Task.Delay(50).Wait(); //40 did not work, 50 did
              Attached Files
              Last edited by forrestang; 04-11-2022, 10:21 PM.

              Comment


                #8
                Hi forrestang, you will notice in the original script they return if the AtmStrategyCreated variable is true. So I replicated the same thing. Please see the attached file.

                Kind regards,
                -ChrisL
                Attached Files

                Comment


                  #9
                  Thanks.

                  Can you help me understand why this latest script you posted seems to evaluate to true? I'm not really seeing why this one works, but the other one didn't?

                  Comment


                    #10
                    Hi forrestang, It returns from OnBarUpdate if any of the ATMStrategyCreated booleans are false. Then it continues and prints out the boolean once they become true. Notice how this same thing is done in the original ATM script:

                    // Check that atm strategy was created before checking other properties
                    if (!isAtmStrategyCreated)
                    return;

                    Comment


                      #11
                      So sorry to keep on this topic, but I still dont see why this one works.

                      It seems like the dictionary value just works differently than the List value for some reason?

                      See the attached image....

                      The "isAtmStrategyCreated[i]" list value was unused in your script, so I used it here.

                      You can see, I initialized that value to false at the start of the loop, then I assigned it AT THE SAME TIME the dictionary value was assigned.

                      Then, I plot out those values on eachbar, to see if they ever become true.

                      You can see, the dictionary value eventually evaluates to true(happens after about 4 onbar updates), but the List value NEVER evaluates to true.

                      Is there something I'm missing in understanding this?

                      Attached Files

                      Comment


                        #12
                        Originally posted by NinjaTrader_ChrisL View Post
                        Hi forrestang, It returns from OnBarUpdate if any of the ATMStrategyCreated booleans are false. Then it continues and prints out the boolean once they become true. Notice how this same thing is done in the original ATM script:

                        // Check that atm strategy was created before checking other properties
                        if (!isAtmStrategyCreated)
                        return;
                        I think I mostly understand THIS part.

                        I.e., in my ORIGINAL script that didn't work, if I add in that delay, or the boolean check above, it works fine. The issue with the attached image, is that it is somewhat SLOW. As in, it takes a few seconds for each order to be placed.

                        But I put that boolean check in my code as shown in the attached image, in the same way the sameATMStrategy() example. See image below.
                        Attached Files

                        Comment


                          #13
                          Hi forrestang, I used the Dictionary in place of the list because when you use the i variable within the callback it doesn't sync up with the for loop. Try printing out the value of i within the callback and it will be 3 every time because the for loop finishes before the callbacks. This is why I used the dictionary, it works by saving the ATM ID that we generated rather than relying on the indexer of the For loop.

                          Kind regards,
                          -ChrisL

                          Comment


                            #14
                            Originally posted by NinjaTrader_ChrisL View Post
                            ...Try printing out the value of i within the callback and it will be 3 every time because the for loop finishes before the callbacks.
                            Thank you, this was a very helpful exercise. I at least understand what is happening here.

                            Comment


                              #15
                              Just an update in the case someone else searches for this problem in the future.

                              As I see how its working, I was able to still use the list I wanted instead of the dictionary.

                              Only doing this for consistency's sake, and I've more or less always used lists for storage.

                              Since I see that the index loop is unreliable, was able to index into the list in the same way NinjaTrader_ChrisL did with the dictionary value.
                              Attached Files

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by NullPointStrategies, Yesterday, 05:17 AM
                              0 responses
                              56 views
                              0 likes
                              Last Post NullPointStrategies  
                              Started by argusthome, 03-08-2026, 10:06 AM
                              0 responses
                              133 views
                              0 likes
                              Last Post argusthome  
                              Started by NabilKhattabi, 03-06-2026, 11:18 AM
                              0 responses
                              73 views
                              0 likes
                              Last Post NabilKhattabi  
                              Started by Deep42, 03-06-2026, 12:28 AM
                              0 responses
                              45 views
                              0 likes
                              Last Post Deep42
                              by Deep42
                               
                              Started by TheRealMorford, 03-05-2026, 06:15 PM
                              0 responses
                              49 views
                              0 likes
                              Last Post TheRealMorford  
                              Working...
                              X