Back to Community
ASDASDASD

ASDASD

1 response

why backtest from 2005 will got the performance?

Clone Algorithm
10
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Machine Learning - Support Vector Regression Example
# Derek M Tishler <[email protected]>
# Uses scikit-learn machine learning to forecast the day's close price,
# exit any positions at end of day, or if stop_limit exceeded on cost basis

import pandas as pd
import numpy as np
from scipy import stats
from sklearn.svm import SVR
from sklearn import grid_search
from sklearn import preprocessing
from datetime import timedelta

def initialize(context):
    # Let's set a look up date inside our backtest to ensure we grab the correct security
    set_symbol_lookup_date('2015-01-01')
    
    # Use a very liquid set of stocks for quick order fills
    #set_universe(universe.DollarVolumeUniverse(99.75, 100))
    context.stocks = symbols('SPY')
    set_benchmark(symbol('SPY'))
    
    # set a more realistic commission for IB, remove both this and slippage when live trading in IB
    set_commission(commission.PerShare(cost=0.014, min_trade_cost=1.4))
    
    # Default slippage values, but here to mess with for fun.
    set_slippage(slippage.VolumeShareSlippage(volume_limit=0.25, price_impact=0.1))
        
    # Perform forecast in the morning and take positions if needed.
    schedule_function(svr_trading, date_rules.every_day(), time_rules.market_open(minutes=5))
    #Only needed in testing/debugging to ensure orders are closed like in IB
    schedule_function(end_of_day, date_rules.every_day(), time_rules.market_close(minutes=1))
    # Sell everything at the end of the day, leave time for orders to close, rely on large volume.
    schedule_function(fire_sale,  date_rules.every_day(), time_rules.market_close(minutes=5))
    
    # Use dicts to store items for plotting or comparison
    context.next_pred_price = {} # Current cycles prediction
    
    # How many days in price history for training set
    context.history_len              = 150    
    # If our cost_basis vs current price (percent diff) falls below this percentage, exit
    context.stop_limit_percent       = 1.0   

# Will be called on every trade event for the securities you specify. 
def handle_data(context, data):
    #Get EST Time every cycle, used for logging
    context.exchange_time  = pd.Timestamp(get_datetime()).tz_convert('US/Eastern')

    #Check that our portfolio does not  contain any invalid/external positions/securities
    check_invalid_positions(context, data)
    
    #Prevent diversion from cost basis to avoid huge loses
    risk_mgmt(context, data)

def risk_mgmt(context, data):
    if len(data) == 1:
        show_spacer = False
    
    # Dont rely on a single price point in case of noise, spike, or bottom of bar
    xminprice = history(bar_count=5, frequency='1m', field='open_price').mean()
    
    # Very limited Risk Management, please suggest more!
    
    # Set a stop limit(But not an actual stop limit order since I simplify order tracking to binary(yes or no position)
    # We are doing this every minute for every stock. Need to map or something for speed?
    for stock in data:
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling. LONG Positions
        if check_if_no_conflicting_orders(stock) and context.portfolio.positions[stock.sid].amount > 0:
            #Check the cost basis of our stock vs the current price, abandon of over the loss limit
            if percent_change(xminprice[stock], context.portfolio.positions[stock.sid].cost_basis) <= -context.stop_limit_percent:
                order_target(stock, 0.0)
                value_of_open_orders(context, data)
                availibleCash = context.portfolio.cash-context.cashCommitedToBuy-context.cashCommitedToSell
                log.info("  ! SL-Exit {0:,d} of {1:s} at ${2:,.2f} for ${3:,.2f} / ${4:,.2f} @ {5:d}:{6:d}"\
                             .format(int(context.portfolio.positions[stock.sid].amount),
                                     stock.symbol,
                                     data[stock]['price'],
                                     data[stock]['price']*context.portfolio.positions[stock.sid].amount,
                                     availibleCash,
                                     context.exchange_time.hour,
                                     context.exchange_time.minute))
                if len(data) == 1:
                    show_spacer = True
                
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling. SHORT Positions
        elif check_if_no_conflicting_orders(stock) and context.portfolio.positions[stock.sid].amount < 0:
            #Check the cost basis of our stock vs the current price, abandon of over the loss limit
            if percent_change(data[stock]['price'], context.portfolio.positions[stock.sid].cost_basis) >= context.stop_limit_percent:
                order_target(stock, 0.0)
                value_of_open_orders(context, data)
                availibleCash = context.portfolio.cash-context.cashCommitedToBuy-context.cashCommitedToSell
                log.info("  ! SL-Exit {0:,d} of {1:s} at ${2:,.2f} for ${3:,.2f} / ${4:,.2f} @ {5:d}:{6:d}"\
                             .format(int(context.portfolio.positions[stock.sid].amount),
                                     stock.symbol,
                                     data[stock]['price'],
                                     data[stock]['price']*context.portfolio.positions[stock.sid].amount,
                                     availibleCash,
                                     context.exchange_time.hour,
                                     context.exchange_time.minute))
                if len(data) == 1:
                    show_spacer = True
                
    if len(data) == 1:
        if show_spacer:
            log.info('') #This just gives us a space to make reading the 'daily' log sections more easily. 
            
def svr_trading(context, data):

    # Historical data, lets get the past days close prices for. 
    # +3(throw away todays partial data, use yesterday as test sample, offset training by 1 day for target values)
    history_open   = history(bar_count=context.history_len+3, frequency='1d', field='open_price')
    history_close  = history(bar_count=context.history_len+3, frequency='1d', field='close_price')
    history_high   = history(bar_count=context.history_len+3, frequency='1d', field='high')
    history_low    = history(bar_count=context.history_len+3, frequency='1d', field='low')
    history_volume = history(bar_count=context.history_len+3, frequency='1d', field='volume')

    # Make predictions on universe
    for stock in data:
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling.
        if check_if_no_conflicting_orders(stock) and context.portfolio.positions[stock.sid].amount == 0:
            
            """ Data Configuration & Preprocessing """
            # What features does our model have? We can pick from the bar(open, close, high, low, volume)
            trainingVectors       = np.zeros((context.history_len, 5),dtype=np.float32)
            trainingVectors[:, 0] = np.array(history_open[stock].values)[:-3]
            trainingVectors[:, 1] = np.array(history_close[stock].values)[:-3]
            trainingVectors[:, 2] = np.array(history_high[stock].values)[:-3]
            trainingVectors[:, 3] = np.array(history_low[stock].values)[:-3]
            trainingVectors[:, 4] = np.array(history_volume[stock].values)[:-3]
            
            # Do a quick nan/inf check on all the features to ensure there is no bad data to crash the SVM
            if np.isnan(trainingVectors).any() or np.isinf(trainingVectors).any():
                log.debug("{0:s} had Nan or Inf in features, skipping for today.".format(stock.symbol))
                # Remove from dict to prevent actions on a skipped stock
                if stock.symbol in context.next_pred_price:
                    del context.next_pred_price[stock.symbol]
                #Continue the for loop to the next stock
                continue
                
            # create our scaling transformer to achieve a zero mean and unit variance(std=1). Scale the training data with it.    
            scaler0               = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(trainingVectors[:, 0])
            scaler1               = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(trainingVectors[:, 1])
            scaler2               = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(trainingVectors[:, 2])
            scaler3               = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(trainingVectors[:, 3])
            scaler4               = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(trainingVectors[:, 4])
            
            # Apply the scale transform
            trainingVectors[:, 0] = scaler0.transform(trainingVectors[:, 0])
            trainingVectors[:, 1] = scaler1.transform(trainingVectors[:, 1])
            trainingVectors[:, 2] = scaler2.transform(trainingVectors[:, 2])
            trainingVectors[:, 3] = scaler3.transform(trainingVectors[:, 3])
            trainingVectors[:, 4] = scaler4.transform(trainingVectors[:, 4])

            # Target values, we want to use ^ yesterdays bar to predict this day's close price. Use close scaler????????
            targetValues          = np.zeros((context.history_len, ),dtype=np.float32)
            targetValues          = np.array(history_close[stock].values)[1:-2] - np.array(history_open[stock].values)[1:-2]
            scalerTarget          = preprocessing.MinMaxScaler(feature_range=(-1, 1)).fit(targetValues)
            targetValues          = scalerTarget.transform(targetValues)
            
            # Test Samples, scaled using the feature training scaler
            testSamples           = np.zeros((1, 5), dtype=np.float32)
            testSamples[:, 0]     = np.array(history_open[stock].values)[-2]
            testSamples[:, 0]     = scaler0.transform(testSamples[:, 0])
            testSamples[:, 1]     = np.array(history_close[stock].values)[-2]
            testSamples[:, 1]     = scaler1.transform(testSamples[:, 1])
            testSamples[:, 2]     = np.array(history_high[stock].values)[-2]
            testSamples[:, 2]     = scaler2.transform(testSamples[:, 2])
            testSamples[:, 3]     = np.array(history_low[stock].values)[-2]
            testSamples[:, 3]     = scaler3.transform(testSamples[:, 3])
            testSamples[:, 4]     = np.array(history_volume[stock].values)[-2]
            testSamples[:, 4]     = scaler4.transform(testSamples[:, 4])
            
            """ Training Weight """
            # Apply x^POWER to (~0 -> 1)
            weight_training = np.power(np.arange(1, targetValues.shape[0]+1,dtype=float), 1)/ \
                              np.power(np.arange(1, targetValues.shape[0]+1,dtype=float), 1).max()
            
            """ Model Optommization """
            parameters    = {'kernel':('linear', 'rbf'),'C':[1, 10, 100, 1000], 'gamma': np.logspace(-2, 1, 4)} #'kernel':('linear', 'rbf'),
            SVR_model     = SVR()
            clf           = grid_search.GridSearchCV(SVR_model, parameters)
            clf.fit(trainingVectors, targetValues)
            
            """ Forecast next close price """
            SVR_model     = SVR(C=clf.best_params_["C"], gamma=clf.best_params_["gamma"]) #kernel=clf.best_params_["kernel"]
            SVR_model.fit(trainingVectors, targetValues, weight_training)
            y_predSVR     = scalerTarget.inverse_transform(SVR_model.predict(testSamples))[0]
            
            if len(data) == 1:
                record(regressionOCDelta = y_predSVR)#,Clog=np.log(clf.best_params_["C"]), Gamma = clf.best_params_["gamma"], Score=clf.best_score_)
            context.next_pred_price[stock.symbol] = y_predSVR

    # Count number of trades so we can split the availible cash properly
    number_of_trades_today = 0
    for stock in data:
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling
        # Also check that we have a prediction stored in the dict
        if check_if_no_conflicting_orders(stock) and \
           context.portfolio.positions[stock.sid].amount == 0 and \
           stock.symbol in context.next_pred_price:
                # Our buy/sell condition, matches below, just here for counting.
                if  context.next_pred_price[stock.symbol] >= 0.0 or \
                    context.next_pred_price[stock.symbol] < 0.0:
                    number_of_trades_today += 1
    #

    #For the case of a multi stock universe, let's use record to plot how  many securities are traded on each day.       
    if len(data) >= 2:
        record(number_of_stocks_traded=number_of_trades_today)

    #Make buys and shorts if the predicted close change is bigger than our tollerance, same with current price to avoid opening gaps.
    for stock in data:
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling
        # Also check that we have a prediction stored in the dict
        if check_if_no_conflicting_orders(stock) and context.portfolio.positions[stock.sid].amount == 0 and stock.symbol in context.next_pred_price:

            #Go long if we predict the close price will change more(upward) than our tollerance, 
            # apply same filter against current price vs predicted close in case of gap up/down.
            if context.next_pred_price[stock.symbol] >= 0:
               #percent_change(context.next_pred_price[stock.symbol], data[stock]['price']) >= context.action_to_move_percent:

                # Place an order, and store the ID to fetch order info
                orderId    = order_target_percent(stock, 1.0/number_of_trades_today)
                # How many shares did we just order, since we used target percent of availible cash to place order not share count.
                shareCount = get_order(orderId).amount

                # We can add a timeout time on the order.
                #context.duration[orderId] = exchange_time + timedelta(minutes=5)

                # We need to calculate our own inter cycle portfolio snapshot as its not updated till next cycle.
                value_of_open_orders(context, data)
                availibleCash = context.portfolio.cash-context.cashCommitedToBuy-context.cashCommitedToSell

                log.info("+ BUY {0:,d} of {1:s} at ${2:,.2f} for ${3:,.2f} / ${4:,.2f} @ {5:d}:{6:d}"\
                         .format(shareCount,
                                 stock.symbol,data[stock]['price'],
                                 data[stock]['price']*shareCount, 
                                 availibleCash,
                                 context.exchange_time.hour,
                                 context.exchange_time.minute))

            #Go short if we predict the close price will change more(downward) than our tollerance, 
            # apply same filter against current price vs predicted close incase of gap up/down.
            elif context.next_pred_price[stock.symbol] <= 0:
                 #percent_change(context.next_pred_price[stock.symbol], data[stock]['price']) <= -context.action_to_move_percent:

                #orderId    = order_target_percent(stock, -1.0/len(data))
                orderId    = order_target_percent(stock, -1.0/number_of_trades_today)
                # How many shares did we just order, since we used target percent of availible cash to place order not share count.
                shareCount = get_order(orderId).amount

                # We can add a timeout time on the order.
                #context.duration[orderId] = exchange_time + timedelta(minutes=5)

                # We need to calculate our own inter cycle portfolio snapshot as its not updated till next cycle.
                value_of_open_orders(context, data)
                availibleCash = context.portfolio.cash-context.cashCommitedToBuy+context.cashCommitedToSell

                log.info("- SHORT {0:,d} of {1:s} at ${2:,.2f} for ${3:,.2f} / ${4:,.2f} @ {5:d}:{6:d}"\
                         .format(shareCount,
                                 stock.symbol,data[stock]['price'],
                                 data[stock]['price']*shareCount, 
                                 availibleCash,
                                 context.exchange_time.hour,
                                 context.exchange_time.minute))
        
#################################################################################################################################################

# Helper functions, allot of which is taken from the Quantopian documentation and forums(thanks Quantopian team for the great examples).
# Thread on these helper functions here: https://www.quantopian.com/posts/helper-functions-getting-started-on-quantopian
# This code has allot of room for optomization! You should! Check the thread above with tips from the Quantopian team!

def check_if_no_conflicting_orders(stock):
    # Check that we are not already trying to move this stock
    open_orders = get_open_orders()
    safeToMove  = True
    if open_orders:
        for security, orders in open_orders.iteritems():
            for oo in orders:
                if oo.sid == stock.sid:
                    if oo.amount != 0:
                        safeToMove = False
    return safeToMove
    #

def check_invalid_positions(context, securities):
    # Check that the portfolio does not contain any broken positions
    # or external securities
    for sid, position in context.portfolio.positions.iteritems():
        if sid not in securities and position.amount != 0:
            errmsg = \
                "Invalid position found: {sid} amount = {amt} on {date}"\
                .format(sid=position.sid,
                        amt=position.amount,
                        date=get_datetime())
            raise Exception(errmsg)
            
def end_of_day(context, data):
    # cancle any order at the end of day. Do it ourselves so we can see slow moving stocks.
    open_orders = get_open_orders()
    
    if open_orders or context.portfolio.positions_value > 0.:
        #log.info("")
        log.info("*** EOD: Stoping Orders & Printing Held ***")

    # Print what positions we are holding overnight
    for stock in data:
        if context.portfolio.positions[stock.sid].amount != 0:
            log.info("{0:s} has remaining {1:,d} Positions worth ${2:,.2f}"\
                     .format(stock.symbol,
                             context.portfolio.positions[stock.sid].amount,
                             context.portfolio.positions[stock.sid].cost_basis\
                             *context.portfolio.positions[stock.sid].amount))
    # Cancle any open orders ourselves(In live trading this would be done for us, soon in backtest too)
    if open_orders:  
        # Cancle any open orders ourselves(In live trading this would be done for us, soon in backtest too)
        for security, orders in open_orders.iteritems():
            for oo in orders:
                log.info("X CANCLED {0:s} with {1:,d} / {2:,d} filled"\
                                     .format(stock.symbol,
                                             oo.filled,
                                             oo.amount))
                cancel_order(oo)
    #

def fire_sale(context, data):
    # Sell everything in the portfolio, at market price
    show_spacer = False
    for stock in data:
        if context.portfolio.positions[stock.sid].amount != 0:
            order_target(stock, 0.0)
            value_of_open_orders(context, data)
            availibleCash = context.portfolio.cash-context.cashCommitedToBuy-context.cashCommitedToSell
            log.info("  * Exit {0:,d} of {1:s} at ${2:,.2f} for ${3:,.2f} / ${4:,.2f}  @ {5:d}:{6:d}"\
                         .format(int(context.portfolio.positions[stock.sid].amount),
                                 stock.symbol,
                                 data[stock]['price'],
                                 data[stock]['price']*context.portfolio.positions[stock.sid].amount,
                                 availibleCash,
                                 context.exchange_time.hour,
                                 context.exchange_time.minute))
            show_spacer = True
    if show_spacer:
        log.info('') #This just gives us a space to make reading the 'daily' log sections more easily 
    # 

def percent_change(new, old):
    return ((new-old)/old)*100.0
    
def value_of_open_orders(context, data):
    # Current cash commited to open orders, bit of an estimation for logging only
    context.currentCash = context.portfolio.cash
    open_orders = get_open_orders()
    context.cashCommitedToBuy  = 0.0
    context.cashCommitedToSell = 0.0
    if open_orders:
        for security, orders in open_orders.iteritems():
            for oo in orders:
                # Estimate value of existing order with current price, best to use order conditons?
                if(oo.amount>0):
                    context.cashCommitedToBuy  += oo.amount * data[oo.sid]['price']
                elif(oo.amount<0):
                    context.cashCommitedToSell += oo.amount * data[oo.sid]['price']
    #
There was a runtime error.