< All Topics

MultiWalk, EasyLanguage and Good Strategy Development Practices

Over the years there are some good practices that I have adopted that help avoid some of the pitfalls, bugs or logic issues when writing strategies in TradeStation or running lengthy MultiWalk projects. I detail several below.

MultiWalk Projects

MultiWalk projects can be take a long time to run, but there are some things you can do to help minimize run times and maximize results.

Don’t use LIBB on initial, large runs

TradeStation’s Look-Inside-Bar Backtesting option adds a critical component to the backtest simulation. It gives a better estimate of a trade’s fill price that cannot always be derived from the strategy’s open/high/low/close bar values. However, this comes as a huge performance cost, both in terms of memory consumption and computational time. It can double to triple the amount of time it takes a project to optimize. For this reason I do NOT use LIBB for large, initial MultiWalk projects. But once I identify a smaller set of results that I want to analyze, I will create a new project with just those symbols and bar intervals and then use LIBB to further refine the results.

Kevin doesn’t use LIBB at all since all this strategies use market orders.  All his entries are market orders.  His exits use the following EasyLanguage code instead of SetStopLoss and SetProfitTarget:

If openpositionprofit>(prof) then begin
    Sell next bar at market ;
    Buytocover next bar at market;
end;

If openpositionprofit<-stopl then begin
    Sell next bar at market ;
    Buytocover next bar at market;
end;

The drawback are potentially larger drawdowns than anticipated, especially with big bar sizes, but the need for LIBB does goes away.

Computer/CPU Power

MultiWalk is “resource heavy” and requires a certain amount of computer power. See this article for minimum recommended hardware configurations.

Development Computer vs Trading Computer

Since MultiWalk is “resource heavy”, do not run MultiWalk on the same computer that is trading strategies (either sim or live). Best practice is to dedicate your trading to a separate machine or VPS. If you run MultiWalk on the same computer as trading, it is likely that you will miss trades or lock up the strategies as both MultiWalk and the strategies will be competing for TradeStation’s ORCAL process. The ORCAL process serves data to all TradeStation charts and Trading Apps and multiple charts accessing it is enough strain on TradeStation without adding MultiWalk to the mix!

Use Limited Feasibility Testing as an optimization pre-filter

MultiWalk implements Kevin Davey’s limited feasibility testing methodology as a pre-filter to skip worthless symbols/bar interval results.  Do not disable this option unless you have good reason:

The optimization phase takes the most time in a MultiWalk project, so anything we can do to limit the amount of time spent optimizing is worthwhile. It means better and faster results rather than wasting time on symbol and bar combinations that would probably not be profitable. This is a critical time-saver in MultiWalk.

Run Multiple MultiWalk Instances

Due to limitations within TradeStation’s design, there are no speed gains setting the number of threads greater than 8.  See this article for more information.

However, you can get around this limitation by running multiple instances of MultiWalk or MultiWalk Trader simultaneously.  Either run different projects in tandem, or break your project into smaller projects.

For example, you can divide your project up into two or three MultiWalk projects (such as giving each a set of different symbols), and thereby maximize the run time by running multiple MultiWalk projects simultaneously.  As a rule-of-thumb, divide the number of threads of your CPU by the number of projects you want to run simultaneously, but do not exceed 8 threads per project.  If in doubt, simply set each project to 4 threads, which seems to be the “sweet spot” of efficiency for TradeStation.

Also see this related article on managing large MultiWalk projects.

Running multiple projects will compound the amount of memory (RAM) used, so care must be taken not to exceed TradeStation’s 32-bit memory limit.  If this occurs, you will receive a warning from MultiWalk.  Simply decrease the number of threads and resume your project(s).

Restart TradeStation after long MultiWalk runs

Some MultiWalk projects can take hours to days to run.  There are a variety of ways that these run times can be reduced, such as explained above, but long run times are inevitable due to the massive number of backtest simulations and number crunching that needs to occur across multiple symbols and bar intervals.  TradeStation tends to become less and less stable as it is pushed hard during these long project runs.  Even if you do not experience instability issues within TradeStation after a long run, it is a good practice to save your work and completely exit TradeStation, run my kill program (or reboot your computer) and restart TradeStation.  This ensures that you are starting with a fresh instance of TradeStation.

Do not use cloud based storage devices

Quite a while ago I had the great idea to put my TradeStation work folders into Sync, my cloud-based drive service, so that I could easily go back and forth between my desktop and laptop when working on strategies or MultiWalk.  I found out the hard way that this is a bad idea.  I quickly corrupted the entire TS EasyLanguage database when I tried to mirror my TradeStation user documents folder using my sync.com account.  I had to perform a complete restore from a recent backup.  The same thing happened with DropBox, OneDrive or any other cloud sharing service.  See this article for more information.

This is also true when running MultiWalk projects.  Using a drive or folder that is being monitored by a cloud-based file sharing service could corrupt the MultiWalk project, so for me, it’s not worth the risk.

Backup your files!

Enable TradeStation’s backup feature.  You never know when you might have to restore your work!

EasyLanguage
Use The Dictionary

TradeStation includes a pretty comprehensive dictionary in the TradeStation Development Environment that describes all the EasyLanguage keywords and functions.

Do Not Use Built-in Variables Value1-99 and Condition1-99

Never use EasyLanguage’s built-in variables Value1-99 or Condition1-99.  From a programming professional point-of-view, these should have never been included in EasyLanguage.  There are two primary reasons to avoid using these keywords:

Confusion and errors

I ran into situations where a strategy used Value1 and then included a piece of code another strategy that also used Value1.  The result was a very confusing mess trying to determine why the strategy results were incorrect, only to find that the cuprit was Value1 being used for two different reasons.

Lack of meaning

When I am reading someone elese’s code, Value1 has no meaning. What is Value1? What is the purpose of the calculation? But creating and using your own descriptive variable names, such as ‘BreakoutPrice’ or ‘DayCounter’ gives context and meaning to the variable’s usage. SO much better than Value1!

Document Your Code

Always document your code.  Why are you performing a calculation?  Why did you include the logic in your code?  What was the source of your idea?

Describe, describe, describe.  If not for your own sanity when you return to the code months later and wonder why you did something, but also for others if you share the code in the Strategy Factory Club.

Don’t Use Functions Over And Over Again

In the following example, the exact RSI calculation is called twice:

if ( RSI(Close,2) < 20 and MarketPosition <> 1 ) then buy next bar at market;
if ( RSI(Close,2) > 80 and MarketPosition <> -1 ) then sellshort next bar at market;

Since the parameters are the same in both RSI function calls, TradeStation will redundantly call the RSI function and receive the same results for each. This causes unnecessary strain on TS (especially when running many strategies real-time) and creates more processing time (which is especially important when running strategies through MultiWalk that will compound those calculations hundreds and thousands of times!)

Instead, call functions ONE TIME by assigning the result to a variable and then using that variable in your code:

RSIValue = RSI( Close, 2 );

if ( RSIValue < 20 and MarketPosition <> 1 ) then buy next bar at market;
if ( RSIValue > 80 and MarketPosition <> -1 ) then sellshort next bar at market;
Strategies
CurrentBar and Walkforward Strategy

Be careful using CurrentBar or BarNumber if your strategies.  When MultiWalk performs an optimization, the entire strategy is optimized starting at bar number 1.  However, when you run a walkforward strategy, it will start the date AFTER your in-sample optimized time period.  For example, the following strategy code works fine during the optimization phase in MultiWalk since the optimization starts at bar 1.

if ( CurrentBar = 1 ) then
begin
    [your code here]
end;

However, the same code, when used in the walkforward version of the strategy, will NOT work. The strategy starts on bar number 1, but the strategy logic does not. The buy/sell logic of the strategy will start AFTER the first optimized in-sample period.

Instead, consider using some other method to initialize startup code or variables, such as “once-blocks” or set a boolean variable to test first time runs:

once begin
    [your code here]
end;

or

vars:
    bool FirstTime(true);

if ( FirstTime ) then
begin
    FirstTime = false;
    [your code here]
end;
TradeStation and Trade Orders

The rule-of-thumb I apply to all buy/sell/sellshort stop and/or limit orders is to never assume that the orders are going to execute the way that you think they will and never assume that TradeStation will somehow compensate for unclear trade orders in your strategy.

Entry Orders

Assuming that we are following the Strategy Factory Club protocol and only trading N contracts at a time, then we could simply write the following code for long or short market entries as:

if ( RSI(Close,2) < 20 ) then buy next bar at market;
if ( RSI(Close,2) > 80 ) then sellshort next bar at market;

However, there are conflicting results when using LIBB (Look-inside-bar backtesting) or not. Using LIBB, TradeStation’s backtest engine will exit a stop and then immediately enter the trade again in the same direction. In a sense it is like not having a stop at all. If you do not use LIBB, then the trade is stopped out as expected and the position is not re-entered. Kevin reported this bug to TS in this post and Elihay, A TS forum member and Strategy Factory member, found a solution by qualifying the entry like this:

if ( RSI(Close,2) < 20 and MarketPosition <> 1  ) then buy next bar at market;
if ( RSI(Close,2) > 80 and MarketPosition <> -1 ) then sellshort next bar at market;

Now the trade results are the same whether using LIBB or not.

Exit Market Orders

In a related subject for exits, we could simply write the following code to exit any short or long positions:

if ( some_exit_criteria ) then
begin
   sell next bar at market;
   buytocover next bar at market;
end;

However, I have found that, for exiting positions, that the above code will sometimes cause unexpected interactions with other orders and cause a “hiccup” in the order flow by placing an additional order that results in an immediate entry and exit. While this will cause an extra commission/slippage cost (granted a minimal concern in the scheme of things), my primary concern is possible order confusion, either from the backtest engine or at the order desk.  I call this the “same entry/exit” (TradeSameEntryExit)  issue and write in more detail about it in this article.

This order situation can be avoided by adding this simple qualification:

if ( some_exit_criteria ) then
begin
   if ( MarketPosition = 1  ) then sell next bar at market;
   if ( MarketPosition = -1 ) then buytocover next bar at market;
end;

Entry or Exit Stop Orders

Stop orders are a bit of a different situation.

Instead of this:

sell ("MW StopLoss-L") next bar at longprice stop; 
buytocover ("MW StopLoss-S") next bar at shortprice stop; 

You could do this:

if ( MarketPosition = 0 or MarketPosition = 1 ) then
    sell ("MW StopLoss-L") next bar at longprice stop; 

if ( MarketPosition = 0 or MarketPosition = -1 ) then
    buytocover ("MW StopLoss-S") next bar at shortprice stop; 

Some strategies, such as breakout strategies using stop orders, may backtest more profitably with this unusual order situation since the strategy may immediately jump back into a position if the breakout conditions are still met.  This would result in the “phantom” SameEntryExit order and then another order that re-enteres a position based on the other active stop.  For example, if a profit target stop was hit and the entry conditions still exist for the other active stop, then the other active stop order will immediately re-enter the position again, resulting in both the “phantom” order trade and the stop order trade.

Deciding to use or not use this qualification is a matter of personal preference.  I don’t think there is a true “right’ or “wrong” answer in this situation.  Some traders would prefer the possible boost in profit despite the additional “phantom” SameEntryExit trade.  I perfer to keep the strategy behavior and orders clear and simple, even if it trades with a little less profit. If I want a “jump back in” behavior, then I’ll program for it.  But, do your own testing to decide which form suits your own trading style, risk levels and objectives.

Intraday Strategies: Limit Number Of Trades Per Day

Since MultiWalk can take an intraday strategy and apply it against many different symbols and bar intervals, the results can often be surprising and, depending on the strategy, produce a HUGE number of trades (hundreds of thousands) per optimization.  These strategy results will not be tradable and waste both precious run-time and memory resources.  Therefore, decide the maximum number of trades you are willing to have the strategy trade per day and use EntriesToday(date) to limit number of trades on each day. So, for example, place this IF statement around your buy/sell orders:

if ( EntriesToday(date) <= 0 ) then
begin
   buy/sell/etc.
end;

This would limit the trades to one per day.  That might not work if you have (and want) several reversals in one day.  Simply make the trade count per day whatever makes sense for your strategy.

Do Not Use SetExitOnClose

Quite simply, it does not work correctly in some situations and has minimal value when trading real-time. See this article for a better solution.

Avoid Two Critical TradeStation Bugs

There are two crtical TradeStation bugs that we need to avoid in our strategies. It has been years and they still remain unresolved. Kevin and I have both created different workarounds for these bugs. For an explanation and the workarounds, see the followoing article:

https://multiwalk.net/knowledge-base/ts-bugs


Table of Contents