Coding the largest strategy ever

Recently I got a quite unusual job: Here’s a trading system for the TradeStation platform. It’s a bit oversized – about 3000 lines of EasyLanguage code. Please replicate that monster in C++ so that it runs on Zorro, but still produces the same trades as on TS. While you’re at it, fix any bugs that you encounter in the EasyLanguage code. You have 2 weeks. Good luck.

The strategy in question is arguably the largest trading script ever written. At least it’s the largest I’ve ever seen. The system was created by a famous trader, and is said to produce immense annual returns. It had to be now migrated to Zorro. It’s not a single strategy, but a combination of multiple algorithms, similar to Zorro’s Z12 system. However unlike Z12, it is not divided into separate algos that trade simultaneously. Rather, its many indicators, filters, entry and exit conditions can be combined in multiple ways for creating the ultimate strategy. What is this magic combination? I don’t know, but if you buy the system, you can maybe find out.

It turned out that coding the system in C++ was the easiest part of the job. The code was large, but not very complex. Using C++ and the Zorro function library reduced the code size by 50%, and I guess some of its functions are now more reliable. The challenging part was not the code conversion, but exactly replicating the trade behavior of TS. And that is the main topic of this article.

When you convert an EasyLanguage script to Zorro, you’ll face the problem that TS opens positions – or not – in a way you normally won’t expect. The usual command for entering a long position with an entry limit looks like this:

TS:  Buy N Contracts Next Bar at MyEntry Limit;
Zorro:  enterLong(N,MyEntry);

Zorro would then just open a pending trade on the next bar, but what TS does depends on the context. This is only partially documented, so I had to find out by experiment. Here are the rules by which TS appears to trade and fill positions (unless ‘pyramiding’ is enabled):

  • If another buy or sell command was given immediately before in the same bar, the new command is ignored.
  • If a position in the same direction was already open, the command is ignored.
  • If a position in the opposite direction was already open, the command is executed and closes the opposite position when filled.
  • If a position in the same direction is currently pending, and if no other buy or sell short command was already given on the current bar, the entry limit of the pending position is set to the current entry limit.
  • If none of the above conditions is fulfilled, a pending position is opened at the given entry limit.
  • If several pending positions hit their entry limits during the same bar, only the first one is filled.
  • If a position is filled, the fill price is the given entry limit with no slippage, but 1 PIP fixed penalty.

Similar rules apply for closing a position.

For replicating the TS behavior, you need to set up Zorro’s trading parameters in this way:

void emulateTS()
{
  setf(TradeMode,TR_EXTEND); // update pending trades
  MaxLong = MaxShort = 1; // only 1 open position
  Hedge = 1; // close opposite positions
  Fill = 3; // next bar, optimistic mode
  Penalty = 0.01; // 1 pip = 1 cent
  Slippage = 0; // don’t simulate slippage
  Interest = 0; // don’t calculate margin interest
}

When an entry limit is hit, you must check whether it’s the first hit of the current bar or not. If not, don’t enter. You need a trade management function for this:

#define LastEntryBar AssetInt[0] 
int manage() // fill only the first pending position at any bar
{
  if(TradeIsEntry) {
    if (Bar == LastEntryBar)
      return 1; // don’t open it
    LastEntryBar = Bar;
  }
  return 16;
}

Adjust the entry and stop limits of open positions only if no other buy/sell command was given before on the same bar:

#define LastBarLong AssetInt[1]; 
void buyNextBar(var AtEntry)
{
  if(Bar != LastBarLong) { // first command of the bar?
    setf(TradeMode,TR_ANYLIMIT|TR_ANYSTOP);
    LastBarLong = Bar;
  } else // don’t set stop and entry limit
    resf(TradeMode,TR_ANYLIMIT|TR_ANYSTOP);
  enterLong(Lots,AtEntry);
}

#define LastBarShort AssetInt[2]; 
void sellShortNextBar(var AtEntry) 
{
  if(Bar != LastBarShort) { // first command of the bar?
    setf(TradeMode,TR_ANYLIMIT|TR_ANYSTOP);
    LastBarShort = Bar;
  } else // don’t set stop and entry limit
    resf(TradeMode,TR_ANYLIMIT|TR_ANYSTOP);
  enterShort(Lots,AtEntry);
}

I do not recommend using this code for other purposes than for emulating TradeStation. But the monster strategy with this trading code opened exactly the same positions at exactly the same entry prices as the original system on TS.  Only exceptions were a few differences by rounding or by fixing bugs of the original code.

By the way, here are some code lines to replicate some often-used TradeStation parameters in C/C++:

int MarketPosition = sign(NumOpenLong-NumOpenShort); 
var PriceScale = 100; // always 100 for stocks and futures 
var MinMove = PIP * PriceScale; // Stock: 0.01 * 100, Emini: 0.25 * 100 
var PointValue = LotAmount / PriceScale; // Stock: 0.01, Emini: 0.50 
var BigPointValue = LotAmount; 
var EntryPrice = 0; 
for(current_trades) if(TradeIsOpen) EntryPrice = TradeFill;

I hope this helps anyone who happens to get the task of replicating a large TradeStation system. Good luck!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.