Back to Community
ASDASDS

ASDASDASD

4 responses

what issue caused the algo got poor performance between 2009,?

Clone Algorithm
20
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 Classification Example
# Derek M Tishler <[email protected]>
# Uses scikit-learn machine learning to forecast the day's close price

import pandas as pd
import numpy as np
from scipy import stats
from sklearn.svm import SVC
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))
    
    # Use dicts to store items for plotting or comparison
    context.next_pred_price = {} # Current cycles prediction
    context.perform_flip = {}
    
    #Change us!
    context.history_len              = 45    # How many days in price history for training set
    context.stop_limit_percent       = 0.75  # If our cost_basis vs current price (percent diff) falls below this percentage, exit

# 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)
    
    #Perform risk management
    #risk_mgmt(context, data)
    
    # If needed, #Perform a desired flip now that the previous order is complete(intraday)
    for stock in data:
        if stock.symbol in context.perform_flip:
            if context.perform_flip[stock.symbol]:
                if check_if_no_conflicting_orders(stock):
                    #Perform a desired flip now that the previous order is complete
                    enter_position(context, data, stock)
                    context.perform_flip[stock.symbol] = False

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:
        
        #Should only occur after this function is ran, so refresh it daily
        context.perform_flip[stock.symbol] = False
        
        # Make sure this stock has no existing orders or positions to simplify our portfolio handling.
        if check_if_no_conflicting_orders(stock):
            
            """ 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]
            
            # CLassify difference based on BUY, SELL, STAY(optional)
            tempTV = np.copy(targetValues)
            stayLimit = 0.075 # You can play with a third class, STAY
            targetValues[np.where(tempTV > stayLimit)]  =  1
            targetValues[np.where(tempTV < -stayLimit)]  = -1  
            targetValues[np.where(np.logical_and(tempTV >= -stayLimit , tempTV <= stayLimit))] = 0 # You can play with a third class, STAY
            targetValues = np.array(targetValues, dtype=int)
            
            # 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 """
            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, 500], 'gamma': np.logspace(-2, 1, 4)} #'kernel':('linear', 'rbf'),
            SVC_model     = SVC()
            clf           = grid_search.GridSearchCV(SVC_model, parameters)
            clf.fit(trainingVectors, targetValues)
            
            """ Forecast next close price """
            SVC_model     = SVC(C=clf.best_params_["C"], gamma=clf.best_params_["gamma"]) #kernel=clf.best_params_["kernel"]
            SVC_model.fit(trainingVectors, targetValues, weight_training)
            y_predSVC     = SVC_model.predict(testSamples)[0]
            
            if len(data) == 1:
                record(classifiedForecast = y_predSVC)#,Clog=np.log(clf.best_params_["C"]), Gamma = clf.best_params_["gamma"], Score=clf.best_score_)
            context.next_pred_price[stock.symbol] = y_predSVC

    # Count number of trades so we can split the availible cash properly
    context.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 stock.symbol in context.next_pred_price:
                # If we plan to move on this stock, take count of it(explained more in actual buy statement below)(Make sure these match both buy statements.
                if  (context.next_pred_price[stock.symbol] == 1 and (context.portfolio.positions[stock.sid].amount == 0 or context.portfolio.positions[stock.sid].amount < 0)) or \
                    (context.next_pred_price[stock.symbol] == -1 and (context.portfolio.positions[stock.sid].amount == 0 or context.portfolio.positions[stock.sid].amount > 0)):
                    context.number_of_trades_today += 1
    #

    #Lets use record to plot how  many securities are traded on each day.       
    if len(data) >= 2:
        record(number_of_stocks_traded=context.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 stock.symbol in context.next_pred_price:
            
            if context.portfolio.positions[stock.sid].amount == 0:
                # We have no positons, buy, short, or stay
                if context.next_pred_price[stock.symbol] == -1 or context.next_pred_price[stock.symbol] == 1:
                    enter_position(context, data, stock)
                    
            elif context.portfolio.positions[stock.sid].amount > 0:
                # We are Long, short(exit then short) or stay
                
                if context.next_pred_price[stock.symbol] == -1:
                    exit_position(context, data, stock)
                    context.perform_flip[stock.symbol] = True
                
            elif context.portfolio.positions[stock.sid].amount < 0:
                # We are short, buy(Exit then buy) or stay
                if context.next_pred_price[stock.symbol] == 1:
                    exit_position(context, data, stock)
                    context.perform_flip[stock.symbol] = True
                    
def enter_position(context, data, stock):
    #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] == 1:
       #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/context.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] == -1:
         #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/context.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))
        
def exit_position(context, data, stock):
    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))
    
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. 
            
                
#################################################################################################################################################

# 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(security.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.

How do you deal with data-mining bias? This guy says that machine learning is a scheme of the 1980s that failed.

Sol,

Machine learning has changed immensely since the 80s. The general 'failed' experiments pertain mostly to perceptron learning, there have been many developments since. As for the blog post I wouldn't listen to anything that guy says, poking around, he says in one post:

"Anyone who claims to have a program that can automatically generate final systems that are profitable and robust under actual trading conditions and sells it to the public is in the best case economically non-rational."

While trying to sell you algo's made with PAL on another part of his site for $8,000. I had a good laugh at that.