amibroker

HomeKnowledge Base

Broad market timing in system formulas

Some trading systems may benefit from attempt to time the broad market. A market-wide valuation, such as moving average, sentiment or some other mechanism may be used to tell if we should be in the market or not.

Flexibility of AFL language allows to create rules or indicators, which are based on more than just one symbol. This enables us to introduce additional filters based on wide-market index performance.

For the purpose of reading quotes of another symbol one can use Foreign or SetForeign functions.

The following formula shows how to generate entry signals in individual stocks when S&P500 index is above its 200-period moving average and exit signals when S&P500 is equal or below 200-period average (^GSPC is a ticker for Yahoo Finance data for S&P500)

//
// read S&P 500 values from ^GSPC ticker
//
sp500 Foreign"^GSPC""C" );
//
// market-wide filter should be in "state" form 
// (so it is True all the time when market is up)
//
marketup sp500 MAsp500200 );
marketdown NOT marketup;
//
// sample trading rules (MACD crossovers)
//
BuySignal CrossMACD(), Signal() );
SellSignal CrossSignal(), MACD() );
//
// combine per-symbo signals with broad-market timing
//
Buy BuySignal AND marketup// enter trade only when buy signal AND market is in up trend
Sell SellSignal OR marketdown// exit position if sell signal OR market turns down

A more complex broad-market timing that requires not only closing price of market index can be implemented using SetForeign function. SetForeign replaces all OHLCV data series with that of the “other” security and allows to calculate all kind of indicators that would normally use current security. Broad market timing does not need to be just “all-in” or “all-out” switch. For example one can switch the trading method depending on whenever broad market is trending or sideways.

//
// Switch to S&P symbol to calculate broad-market timing
//
SetForeign"^GSPC" );
//
// now we can calculate any indicator based on SP500 
//
MarketIsTrending ADX40 ) > 20// ADX (40 days) from SP500
//
// now go back to original data (current symbol)
// 
RestorePriceArrays();
//
// you can have different rules that are switched
// depending on what broad market is doing
//
TrendingBuy CrossCMAC30 ) );
TrendingSell CrossMAC30 ), );
//
SidewaysBuy CrossMACD(), Signal() );
SidewaysSell CrossSignal(), MACD() );
//
// switch methods using broad-market timing
//
Buy IIfMarketIsTrendingTrendingBuySidewaysBuy ); 
Sell IIfMarketIsTrendingTrendingSellSidewaysSell ); 

In this simple example we assume that market timing signals change very infrequently so they change much less often than Trending/Sideways Buy/Sell signals are generated. If that is not the case the switching logic would need to be more complex to decide what to do when we are in the “trending” trade and market switches to sideways mode. In such situation, the code above uses SidewaysSell signal to sell the position, which may or may not be what you are after.

Another example is changing position sizing depending on broad market conditions. We can choose to be fully invested when broead market is up and only 30% invested in down market.

//
// Switch to S&P symbol to calculate broad-market timing
//
SetForeign"^GSPC" );
//
// now we can calculate any indicator based on 
// SP500
//
MarketIsUp MAC200 ); // here C represents closing price of SP500
//
// now go back to origiginal data (current symbol)
// 
RestorePriceArrays();
//
// normal rules (in this example they do not chang)
//
Buy CrossMACD(), Signal() );
Sell CrossSignal(), MACD() );
//
// no more than 10 positions open at a time
//
SetOption("MaxOpenPositions"10 );
//
// change position sizing depending on broad market conditions
// in this example we will allocate:
// 10% per position
// if broad market is up (so we can be allocated upto 100% of funds)
// 3% per position 
// if broad market is down (so we can be allocated upto 30% of funds)
// 
SetPositionSizeIIfMarketIsUp10), spsPercentOfEquity );

Comments are closed.