Home > Technology > Example B

EXAMPLE B: Reading from Multiple Data Streams - Creating a Custom Index

There are no restrictions on the number of data sources that can be accessed by a single strategy. This makes possible the calculation of intermarket spreads, custom stock baskets, currency cross rates, and anything else that requires multiple data series.

The following example will demonstrate how strategies:

The following strategy will determine whether energy prices, as measured by a basket of energy related futures contracts (gasoline, crude oil, heating oil), have any predictive qualities for the stock market. The stock market is represented by the SP500 futures contract as traded on the CME.


Strategy s("basket_demo"); //1

 

s.SetPerSideCommission(7.0);   //2

s.SetPerSideSlippage(25.0);    //3

s.SetOrderSizeAs(NUM_UNITS);   //4

s.SetBigPointValue(250.0);     //5

s.SetPyramidingEnabled(false); //6

s.SetUsingSmartLimitOrders(true); //6b

 

Tuple sp500 = IRecord(db, "sp.future.ohlcvoi.daily",

PRICE_MASTER | TIME_MASTER ); //7

 

Tuple crudeOil    = IRecord(db, "cl.future.ohlcvoi.daily"); //8

Tuple heatingOil  = IRecord(db, "ho.future.ohlcvoi.daily"); //9

Tuple gasoline    = IRecord(db, "hu.future.ohlcvoi.daily"); //10

 

List energyBasket = ( crudeOil("close"),

                      heatingOil("close"),

                      gasoline("close")     ); //11 Creating Basket

 

Double energyIndex = BalancedIndex( energyBasket, 100.0, 20); //12  Calculating Index

 

Double energyPercChg = (energyIndex - Prev(energyIndex)) / Prev(energyIndex); //13

 

Bool buySignal = IsFlat() && energyPercChg < 0.0;  //14 buy stocks when energy drops

Bool exitLongSignal = energyPercChg > 0.0;         //15 exit when energy rises

 

LimitOrder(LONG, 5, buySignal, sp500("close"), NEXT_BAR);   //16 long entry

MarketOrder(EXIT_LONG, exitLongSignal, NEXT_OPEN);                  //17 long exit

 

Bool sellSignal = IsFlat() && energyPercChg > 0.0;   //18 sell stocks when energy rises

Bool exitShortSignal = energyPercChg < 0.0;          //19 exit when energy drops

 

LimitOrder(SHORT, 5, sellSignal, sp500("close"), NEXT_BAR);   //20

MarketOrder(EXIT_SHORT, exitShortSignal, NEXT_OPEN);                  //21

 

s.Log( db, TRADES | DRAWDOWNS | TRANSACTIONS); //22

 

s.Evaluate(1983, 2007);               //23

 

s.PrintEquityGraph(LOG_FILE);         //24

s.PrintPerformanceReport(LOG_FILE);   //25

s.PrintTradeReport(LOG_FILE);         //26

s.PrintDrawdownReport(LOG_FILE);      //27




Strategy Properties

This strategy trades futures contracts, that much is apparent merely by looking at the strategy properties!

s.SetPerSideCommission(7.0);   //2

s.SetPerSideSlippage(25.0);    //3 value of 1 tick

s.SetOrderSizeAs(NUM_UNITS);   //4

s.SetBigPointValue(250.0);     //5 Large SP500 contract - 250$ per point

s.SetUsingSmartLimitOrders(true); //6b

The 'big point value', as set in //5 is the dollar gain or loss caused by a 1 point change in the value of the underlying. Normally, for stocks, this number is set to 1. In this case it is set to 250, corresponding to a minimum tick of 0.1 and a tick value of 25 dollars. The per-side slippage is set to 25 dollars, which corresponds to 1 tick. The per-side commission is set to 7 dollars.

Line //4 tells the strategy that the 'size' argument to order functions should be interpreted as 'units' (the default), and not 'cash amounts'.
 

Tuple sp500 = IRecord(db, "sp.future.ohlcvoi.daily",

PRICE_MASTER | TIME_MASTER ); //7


Line //7 reads data records from the table containing historical prices for the SP500, and defines it as PRICE_MASTER and TIME_MASTER, a topic already discussed in the previous example.

Accessing Multiple Data Sources

Where it gets interesting is from line //8 to //11:

Tuple crudeOil    = IRecord(db, "cl.future.ohlcvoi.daily"); //8

Tuple heatingOil  = IRecord(db, "ho.future.ohlcvoi.daily"); //9

Tuple gasoline    = IRecord(db, "hu.future.ohlcvoi.daily"); //10

 

List energyBasket = ( crudeOil("close"),

                      heatingOil("close"),

                      gasoline("close")   ); //11

 

Double energyIndex = BalancedIndex( energyBasket, 100.0, 20); //12


Lines //8 to //10 repeatedly call the IRecord() function to read data from energy related tables. The closing prices of each record are then aggreated as a list called 'energyBasket'. This list is then passed as argument to the BalancedIndex() function, which calcualtes an index, starting at a given number, in this case 100.0, and automatically rebalances exposure to each underlying in the basket at a given interval, in this case every 20 bars. Alternate algorihms could be embodied in a custom component easily.

There is no real limit to the number of time series that the DynamicIndex() function can handle. If a larger number of items, 100 or even 1000 items, needs to be placed in a List object, it makes sense to combine formula code with a C++ loop statement. This would look something like this:

std::vector<string> tableNames;  //a collection of table names

List basket;

for(int i=0; c< tableNames.size(); c++)

basket.Append( IRecord(db, tableNames[c])("close") );

 

Combining C++ statements with formula code in such a way is quite powerful. Doing so is of course possible because, despite the appearances, formula code is executed once only. (see Modeling With Formulas)

Buy and Sell Signals

Bool buySignal = IsFlat() && energyPercChg < 0.0;  //14

Bool exitLongSignal = energyPercChg > 0.0;         //15


The buy signal is quite simple! It signals when the current position is 'flat' and the custom energy index drops in price. The idea is that stocks rise when energy prices fall. The signal to exit the 'long' position occurs when energy prices rise again. While these rules are very simplistic, they are sufficient for the purpose of this example.

Using Limit Orders

Limit orders are very important because they are the only order type which (usually) does not incur slippage. Slippage represents the by far largest part of transaction costs which is why limit orders are the prefered tool for the professional trader. While the use of limit orders may lead to a missed opportunity on occasion, the savings from using them add up quickly!
The only time a limit order may incur slippage is when they are created as 'smart limit orders' (as controlled by the strategy's SetUsingSmartLimitOrders() member in //6 ) and the market gaps accross the limit price (overnight), at which point the limit order is assumed to be converted to a market order and filled at the bar's open price.

 

LimitOrder(LONG, 5, buySignal, sp500("close"), NEXT_BAR);   //16


To keep the strategy code concise, the current bar's closing price was used as limit price. This means that there is a good chance that the open price gaps below the limit price at which point the limit order is evaluated as a market order, and incurs slippage. The system actually keeps track of what percent of transactions and units execute without slippage. These metrics are part of the Performance Report shown below.

Performance

In reality, events that affect energy prices simultaneously also affect stock prices. Trading with a 1 day delay, as with this strategy, is unlikely to produce good results, as can be seen from the equity graph below:

 

   _____________________________________________________________________

  | Net Equity Graph (EOD)                                              |

  |                                                  *    *            *| H: 441512.5

  |                                                 **    **           +|

  |                                                 **    **          **| 296005

  |                                                 **   ****        ***|

  |                                                 **   *******     ***| 212857

  |                                                 ** * * *******  ****|

  |                                                ******* * ***********| 129710

  |                  *  *                          *******   *   *****  |

  |               ***** ****                      ********        **    | 46563

  |              **   *** ***                     ********              |

  |*********----**-----*---*****------------------**--*-----------------| (0.0)

  |       ****  **            ***            *    *                     |

  |         *****               ****         *    *                     | -119732

  |          ****                 ***      * ******                     |

  |            **                   ****  *********                     | -202880

  |                                  ******** *****                     |

  |                                     ***** ***                       | -286027

  |                                      *     **                       |

  |                                            **                       | L: -348387.5

  |03-Jan-1983                                              28-Dec-2007 |

  |_____________________________________________________________________|

 

The strategy was nonetheless profitable, but a closer look at the Performance Report is required!

  _______________________________________________ 

 |                                               |

 |          Strategy Performance Report          |

 |_______________________________________________|

 

   Strategy Name:               'intermarket_demo'

 

   Operational Bar:             3.Jan.1985-00:00:00:000

   Last Bar:                    31.Dec.2007-00:00:00:000

   Bars Processed:              6307

   Simulation Length (Years):   22.99

   Bars per Year:               252

   Last Trade was Open:         false

 

   Risk Free Rate Of Return:    3.5

  _________________________________________________________________________________________

 | SUMMARY                       |        |           ALL |          LONG |         SHORT |

 |_______________________________|________|_______________|_______________|_______________|

 | Net Profit                    |  [ccy] |    389,642.50 |    913,275.00 |   -523,632.50 |

 | Gross Profit                  |  [ccy] |    878,937.50 |  1,148,625.00 |   -269,687.50 |

 | Total Costs                   |  [ccy] |    489,295.00 |    235,350.00 |    253,945.00 |

 |  * Commission                 |  [ccy] |    129,920.00 |     63,350.00 |     66,570.00 |

 |  * Slippage                   |  [ccy] |    359,375.00 |    172,000.00 |    187,375.00 |

 | Winners Net                   |  [ccy] |  8,681,180.00 |  4,700,730.00 |  3,980,450.00 |

 | Losers Net                    |  [ccy] | -8,291,537.50 | -3,787,455.00 | -4,504,082.50 |

 | Profit Factor                 |  [rat] |          1.05 |          1.24 |          0.88 |

 |_______________________________|________|_______________|_______________|_______________|

 | Largest Drawdown              |  [ccy] |   -478,620.00 |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | Number Of Trades              | [trad] |      1,856    |        905    |        951    |

 | Percent Winners               |  [pct] |         48.55 |         53.70 |         43.64 |

 |_______________________________|________|_______________|_______________|_______________|

 | Sum Bars - All Trades         | [bars] |      3,642    |      1,714    |      1,928    |

 | Perc. Bars with Position      |  [pct] |         57.75 |         27.18 |         30.57 |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | RISK / RETURN (ALL TRADES)    |        |     Account A |     Account B |     Account C |

 |_______________________________|________|_______________|_______________|_______________|

 | Start Account Balance         |  [ccy] |    479,100.00 |    958,200.00 |  1,437,300.00 |

 | End  Account Balance          |  [ccy] |    868,742.50 |  1,347,842.50 |  1,826,942.50 |

 | Annualized Rate Of Return     |  [pct] |          2.62 |          1.50 |          1.05 |

 | Annualized Volatility (StDev) |  [pct] |         32.13 |         13.93 |          9.17 |

 | Sharpe Ratio                  |  [rat] |         -0.03 |         -0.14 |         -0.27 |

 |_______________________________|________|_______________|_______________|_______________|

 | Max Account Balance           |  [ccy] |    930,237.50 |  1,409,337.50 |  1,888,437.50 |

 | Min Account Balance           |  [ccy] |    124,677.50 |    603,777.50 |  1,082,877.50 |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | TRADES                        |        |           ALL |          LONG |         SHORT |

 |_______________________________|________|_______________|_______________|_______________|

 | Number Of Trades              | [trad] |      1,856    |        905    |        951    |

 | Ave Net Profit                |  [ccy] |        209.94 |      1,009.14 |       -550.61 |

 | Ave Gross Profit              |  [ccy] |        473.57 |      1,269.20 |       -283.58 |

 | Ave Costs                     |  [ccy] |        263.63 |        260.06 |        267.03 |

 |  * Ave Slippage               |  [ccy] |        193.63 |        190.06 |        197.03 |

 |  * Ave Commission             |  [ccy] |         70.00 |         70.00 |         70.00 |

 | Ave Winner / Ave Loser        |  [rat] |          1.11 |          1.07 |          1.14 |

 | Ave Num Transactions          | [tran] |          2.00 |          2.00 |          2.00 |

 | Ave (Max) Position            | [unit] |          5.00 |          5.00 |          5.00 |

 | Ave Length                    | [bars] |          1.96 |          1.89 |          2.03 |

 | Ave Positive Excursion        |  [ccy] |      9,646.45 |      9,579.28 |      9,710.37 |

 | Ave Negative Excursion        |  [ccy] |     -8,520.10 |     -8,663.33 |     -8,383.81 |

 |_______________________________|________|_______________|_______________|_______________|

 | Max Positive Excursion        |  [ccy] |    133,750.00 |     99,375.00 |    133,750.00 |

 | Max Negative Excursion        |  [ccy] |   -101,875.00 |   -101,875.00 |    -73,750.00 |

 | Max Num Transactions          | [tran] |          2    |          2    |          2    |

 | Max Position Size             | [unit] |          5.00 |          5.00 |          5.00 |

 | StDev Net Profit              |  [ccy] |     15,484.60 |     16,501.63 |     14,409.34 |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | WINNERS vs LOSERS             |        |           ALL |          LONG |         SHORT |

 |_______________________________|________|_______________|_______________|_______________|

 | Number of Winners             | [trad] |        901    |        486    |        415    |

 | Number of Losers              | [trad] |        955    |        419    |        536    |

 | Average Winner                |  [ccy] |      9,635.05 |      9,672.28 |      9,591.45 |

 | Average Loser                 |  [ccy] |     -8,682.24 |     -9,039.27 |     -8,403.14 |

 | Largest Winner                |  [ccy] |    129,180.00 |     95,430.00 |    129,180.00 |

 | Largest Loser                 |  [ccy] |   -102,070.00 |   -102,070.00 |    -52,820.00 |

 | Max Consecutive Winners       | [trad] |          8    |          8    |         16    |

 | Max Consecutive Losers        | [trad] |         10    |          8    |         11    |

 | Ave Winner Length             | [bars] |          2.00 |          1.93 |          2.07 |

 | Ave Loser Length              | [bars] |          1.93 |          1.85 |          2.00 |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | UNITS                         |        |           ALL |          LONG |         SHORT |

 |_______________________________|________|_______________|_______________|_______________|

 | Ave Net Profit                |  [ccy] |       20.9937 |      100.9144 |      -55.0613 |

 | Ave Gross Profit              |  [ccy] |       47.3565 |      126.9199 |      -28.3583 |

 | Ave Costs                     |  [ccy] |       26.3629 |       26.0055 |       26.7029 |

 | Ave Slippage                  |  [ccy] |       19.3629 |       19.0055 |       19.7029 |

 |_______________________________|________|_______________|_______________|_______________|

 | Num Units Traded              | [unit] |     18,560.00 |      9,050.00 |      9,510.00 |

 |  * At-Market                  | [unit] |      9,280.00 |      4,525.00 |      4,755.00 |

 |  * On-Stop                    | [unit] |          0.00 |          0.00 |          0.00 |

 |  * At-Limit                   | [unit] |      9,280.00 |      4,525.00 |      4,755.00 |

 | Perc. Units w/o Slippage      |  [pct] |         22.55 |         23.98 |         21.19 |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | TRANSACTIONS                  |        |           ALL |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | Number of Transactions        | [tran] |       3,712   |               |               |

 |  * At-Market                  | [tran] |       1,856   |               |               |

 |  * On-Stop                    | [tran] |           0   |               |               |

 |  * At-Limit                   | [tran] |       1,856   |               |               |

 |                               |        |               |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | DRAWDOWNS                     |        |           ALL |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 | Largest Drawdown              |  [ccy] |   -478,620.00 |               |               |

 | Longest Drawdown              | [bars] |      2,429    |               |               |

 | Number of Drawdowns           |  [ddn] |         74    |               |               |

 | Ave Length                    | [bars] |         81.12 |               |               |

 | Ave Drawdown                  |  [ccy] |    -33,394.39 |               |               |

 | Current Drawdown              |  [ccy] |   -104,890.00 |               |               |

 |_______________________________|________|_______________|_______________|_______________|

 


While the strategy made money, it made all its money on the 'long' side, which is suspicious considering the stock market has a strong upward bias. It is very possible that almost all of the gains are the result of chance only. This is also apparent from the low 'profit factor' of 1.05 ('winners net' / 'losers net').

What is interesting about this strategy is that it used limit orders to enter a position to save on 'slippage'. The strategy does not book slippage if a limit order is filled at the limit price. The only situation where a long limit order incurs slippage is if the open price gaps below the limit price overnight in which case it is assumed that the limit order is converted to a market order and executed at the open price (since the strategy uses 'smart' limit orders)! The opposite is true for short limit orders. 'Smart' limit orders, as used here, should only be used with 'end of day' systems, where there exists a time gap between the close of one bar and the open of the next bar. 'Smart' limit orders can help a strategy perform more realistically, since executing always at the limit price would seriously understate performance!

The system keeps track of how many orders of each type were filled, as well as what percentage of orders were filled without slippage. Consider the following extract from the strategy performance report below:

 |_______________________________|________|_______________|_______________|_______________|

 | Number of Transactions        | [tran] |       3,712   |               |               |

 |  * At-Market                  | [tran] |       1,856   |               |               |

 |  * On-Stop                    | [tran] |           0   |               |               |

 |  * At-Limit                   | [tran] |       1,856   |               |               |

 |                               |        |               |               |               |


There were 3712 transactions in total, of which 1856 were market orders and an identical number of limit orders.

 

 |_______________________________|________|_______________|_______________|_______________|

 | Num Units Traded              | [unit] |     18,560.00 |      9,050.00 |      9,510.00 |

 |  * At-Market                  | [unit] |      9,280.00 |      4,525.00 |      4,755.00 |

 |  * On-Stop                    | [unit] |          0.00 |          0.00 |          0.00 |

 |  * At-Limit                   | [unit] |      9,280.00 |      4,525.00 |      4,755.00 |

 | Perc. Units w/o Slippage      |  [pct] |         22.55 |         23.98 |         21.19 |

 

 

 Since the order size was always 5 units (contracts), the number of units traded comes to a total of 3712 * 5 = 18560. What is interesting is that although half the orders were limit orders, only 22.05 percent of all units were filled without slippage. This is because of how the limit price was set for each order.

LimitOrder(LONG, 5, buySignal, sp500("close"), NEXT_BAR);   //16

Recall that the previous bar's closing price was used as limit price for execution on the NEXT_BAR. The likelyhood that the next bar's open is below the limit price is thus quite high (about 50%), which is why only about half the limit orders were filled without slippage. The other half was executed 'at market' with a price better than the limit price!


     Copyright (c) 2008 PERITECH. All Rights Reserved.