Asset Allocation with Quantiacs

September, 23 2020

Most trading backtester are event- or order-based. The developer of the trading system has normally to define the set of assets which should be bought or sold and the number of contracts for a specific asset which should be bought or sold.

Quantiacs uses a different approach to the simulation and bases its engine on the concept of asset exposure: instead of defining events (or orders), the developer should decide on a daily basis how the available capital should be allocated to the assets. The Quantiacs backtester takes care of translating exposure (or allocation) to assets into discrete orders. The advantage for the developer is clear, as it is possible to focus on the idea behind the trading strategy without spending time on the details.

Here we show a simple passive trading system which allocates equal weights to four futures contracts: Gold, Crude Oil, the S&P500 Index and the 10-Year US Treasury Note.

Each system should have a ‘mySettings’ function which in this case will simply take care of defining the four assets:
 

def mySettings():
    '''Settings for assets to be traded.'''   
 
    settings = {}    
    # Futures contracts we trade:
    settings['markets'] = ['CASH', 'F_GC', 'F_CL', 'F_ES', 'F_TY']    
    settings['lookback'] = 504
    settings['budget']   = 10**6
    settings['slippage'] = 0.05
    
    return settings

The set of available assets for Quantiacs can be found on our page. Quantiacs uses a CASH artificial asset which can be used for reducing overall exposure. In this case we will have no CASH exposure and be fully invested.

The trading system allocates fixed weights to the four assets as follows:

def myTradingSystem(DATE, OPEN, HIGH, LOW, CLOSE, VOL, exposure, equity, settings):
    '''This system assigns fixed allocation weights.''' 
   
    # 1st step: inititalize a list for the 5 assets
    pos = numpy.zeros(5)    

    # 2nd step: set fixed allocation weights. The order of the markets in the list defined in mySettings matters, so indices are:
    # 0: CASH
    # 1: F_GC (Gold)
    # 2: F_CL (Crude Oil)
    # 3: F_ES (S&P500)
    # 4: F_TY (10-Year US Treasury Note)    

    # we decide to be fully invested (no CASH), and assign:
    pos[0] = 0   # CASH
    pos[1] = 0.25 # Gold
    pos[2] = 0.25 # Crude Oil
    pos[3] = 0.25 # S&P500
    pos[4] = 0.25 # 10-Year US Treasury Note    
    weights = pos/numpy.nansum(abs(pos)) # normalize weights
    
    return weights, settings

This simple rule can be made dynamic by using an if…else structure and defining different allocations according to different events:

if [condition A]:
    pos[0] = 0    # CASH
    pos[1] = 0.25 # Gold
    pos[2] = 0.25 # Crude Oil
    pos[3] = 0.25 # S&P500
    pos[4] = 0.25 # 10-Year US Treasury Note
elif [condition B]:
    pos[0] = 0    # CASH
    pos[1] = 0    # Gold
    pos[2] = 0    # Crude Oil
    pos[3] = 0.5  # S&P500
    pos[4] = 0.5  # 10-Year US Treasury Note
else:
    pos[0] = 0    # CASH
    pos[1] = 0.5  # Gold
    pos[2] = 0.5  # Crude Oil
    pos[3] = 0    # S&P500
    pos[4] = 0    # 10-Year US Treasury Note

The Quantiacs backtester takes then care of rebalancing weights on a daily basis ensuring that we are always fully investing the available capital.

If you have some simple ideas on asset allocation, try them taking part to our Q14 contest. Deadline for submissions is December 31st, 2020, and 2.25 M USD will be allocated to winning systems.

Do not forget to subscribe to our YouTube channel where you will find useful material!


The Full Strategy

 

import numpy

def myTradingSystem(DATE, OPEN, HIGH, LOW, CLOSE, VOL, exposure, equity, settings): 
   
    pos = numpy.zeros(5)    
    pos[0] = 0    # CASH
    pos[1] = 0.25 # Gold
    pos[2] = 0.25 # Crude Oil
    pos[3] = 0.25 # S&P500
    pos[4] = 0.25 # 10-Year US Treasury Note    
    weights = pos/numpy.nansum(abs(pos)) 
    
    return weights, settings

def mySettings():    

    settings = {}
    settings['markets']  = ['CASH', 'F_GC', 'F_CL', 'F_ES', 'F_TY']
    settings['lookback'] = 504
    settings['budget']   = 10**6
    settings['slippage'] = 0.05    

    return settings

if __name__ == '__main__':
    from quantiacsToolbox.quantiacsToolbox import runts, optimize    
    results = runts(__file__)