< All Topics

Do not use SetExitOnClose in Strategies

EDIT: As of TradeStation 10 Update 73, the below bug has been almost resolved.  The discrepency between optimized vs. chart still exists, but is much less.  While this is encouraging, it is not a true fix as the trades should be identical in both.  My advice not to use SetExitOnClose remains the same.

There is a bug in TradeStation that generates different trade results when optimizing on a TS chart vs optimizing using the TS Optimization API.  TS will periodically skip end-of-session bars on the chart whereas it does not using the Optimization API.  This yields inconsistent results when trying to create trade and equity curve results that match between the two optimization methods.  MultiWalk uses TS’s Optimziation API.  Therefore, SetExitOnClose cannot be used in strategies using MultiWalk, whether in testing or real-time trading.

See my following bug report post on TS user forum: https://community.tradestation.com/Discussions/Topic.aspx?Topic_ID=218772

Do not use of SetExitOnClose even in testing because (1) of the above bug and (2) it cannot be used in real-time trading without a custom session that ends before the actual end of the session.

MultiWalkGetRegularSessionBarTime

As a workaround, I created the function MultiWalkGetRegularSessionBarTime.  This function can determine the closing time of any bar within the regular session.  To determine a bar closing time from the beginning of the regular session, use positive numbers.  To determine a bar closing time from the end of the session, use negative numbers.  “1” would be the first bar.  “-1” would be the last bar.  In order to place a trade at the open of the last bar of the regular sessions, simply indicate “-2” (i.e., two bars back from the end).  Using “-2” gives you the ability to place a trade at the close of the next-to-last bar so that the trade will go in at the open of the last bar.

The following code can be used to replace SetExitOnClose.  It won’t exit the trade right before the end of the session, but rather the open of the last bar of the session.

    if ( time = MultiWalkGetRegularSessionBarTime(-2) ) then
    begin
        if ( MarketPosition = 1 ) then sell ("EOD-L") next bar at market;
        if ( MarketPosition = -1 ) then buytocover ("EOD-S") next bar at market;
    end;

Please note that neither the above code or SetExitOnClose will account for partial trading hours on holidays.

MultiWalkGetRegularSessionBarTime is included in MultiWalk. The following are the header notes from the MultiWalkGetRegularSessionBarTime function itself:

// FUNCTION
//    MultiWalkGetSessionBarTime
//
//    MultiWalkGetSessionBarTime() makes it possible to determine the actual bar times in a session, regardless of BarInterval or 
//    time zone.  This is particular helpful trying to determine the next-to-last bar of a session, which cannot always be determine 
//    by simple math using CalcTime() and SessionEndTime() if the bar size or session end time does not fall on evenly divisable intervals.
//
// PARAMETERS
//    WantedBarNumber
//
//    This is the number of the bar within the session that you want the bar time.  The first bar of the session = 1, second bar = 2, etc.
//    Use NEGATIVE numbers to get bars from the end of the session.  The last bar of the session = -1, the second-to-last = -2, etc.
//
// RETURN
//    Returns the 24-hour clock integer time of the bar number indicated (WantedBarNumber)
//
// NOTES
//    This function uses the regular session from SessionStartTime and SessionEndTime.  It assumes that the session times are the same for
//    each day of the week.
//
// AUTHOR
//    Dave Fisher, dave@multiwalk.net
//
// EXAMPLES
//    vars:
//        int FirstBarTime(0),
//        int NextToLastBarTime(0),
//        int LastBarTimeOfSession(0);
//
//        FirstBarTime = MultiWalkGetSessionBarTime(1);
//        NextToLastBarTime = MultiWalkGetSessionBarTime(-2);
//        LastBarTimeOfSession = MultiWalkGetSessionBarTime(-1);
//
// EXPLANATION
//    Using CalcTime to determine the second-to-last bar of a session will not always work correctly depending on the bar interval and session
//    end time.  For example, this seems to be generally correct:
//
//      SessEndTime = CalcTime( SessionEndTime(1,1), -BarInterval );
//
//    However, as the below examples demonstrate, the CalcTime calculation will not return the actual, correct bar of the session.  This is not
//    a failing of CalcTime, but because bar time computation must take into acount both the bar size and the begin time of the session.  Bar
//    time computation must always begin at the start time of the session in order to arrive at the correct bar time later in the day.
//
// @ES, bar interval = 59 minutes
//    Exchange session end time: 1600
//    Simple math to compute last bar: CalcTime( 1600, -59 ) = 1501 (this is NOT the time of the last bar)
//    Actual bar-before-last = 1537 (this is the time the last bar should be)
//    Bars using MultiWalkGetSessionBarTime:
//      BarInterval = 59 | BeginDateTime = 1/4/2023 5:00:00 PM | EndDateTime = 1/5/2023 4:00:00 PM
//      Bar 1 = 1700
//      Bar 2 = 1759
//      Bar 3 = 1858
//      Bar 4 = 1957
//      Bar 5 = 2056
//      Bar 6 = 2155
//      Bar 7 = 2254
//      Bar 8 = 2353
//      Bar 9 = 52
//      Bar 10 = 151
//      Bar 11 = 250
//      Bar 12 = 349
//      Bar 13 = 448
//      Bar 14 = 547
//      Bar 15 = 646
//      Bar 16 = 745
//      Bar 17 = 844
//      Bar 18 = 943
//      Bar 19 = 1042
//      Bar 20 = 1141
//      Bar 21 = 1240
//      Bar 22 = 1339
//      Bar 23 = 1438
//      Bar 24 = 1537   <-- next to last bar (use WantedBarNumber = -2 to retrieve)
//      Bar 25 = 1600
//
// @LH, bar interval = 120 minutes
//    Exchange session start time: 830
//    Exchange session end time: 1305
//    Simple math to compute last bar: CalcTime( 1305, -120 ) = 1105
//    Actual bar-before-last = 1230 (this is the time the last bar should be)
//    Bars using MultiWalkGetSessionBarTime:
//      BarInterval = 120 | BeginDateTime = 1/26/2023 8:30:00 AM | EndDateTime = 1/26/2023 1:05:00 PM
//      Bar 1 = 830
//      Bar 2 = 1030
//      Bar 3 = 1230   <-- next to last bar (use WantedBarNumber = -2 to retrieve)
//      Bar 4 = 1305
Table of Contents