Sunday 19 July 2015

Quantopian Algorithmic Trading Strategy: Portfolio allocation, Sell high, Buy low

This below algorithm should trade with the portfolio in the earlier post. In this situation we have $1 000 000 invested and no single stock has more than $350 000 invested in it. This is a trading guard as it would otherwise indicate a riskier portfolio. There is also a trailing stop at 20%. Our target is to have rather equal weights in all the stocks, and sell when it hits a maximum and go long when it reaches minimum. The maximum and minimum is determined by refreshing once a day to find the highest/lowest price in the last 7 trading days.

def initialize(context):
    set_benchmark(context.stocks)
    context.stocks = symbols(‘ANZ’, ‘MFG’, ‘NAB’,‘MFG’, ‘NAB’, ‘WBC’, ‘PNC’, ‘FLT’, ‘AGI’, ‘NCK’, ‘TRS’, ‘DSH’, ‘SOL’, ‘TLS’, ‘CCP’, ‘WOW’, ‘S32’, ‘JHC’, ‘CSL', 'NAN', 'SOM', 'SMX', 'SMA', 'MYOB', 'EPD', 'MLB')
    context.bet_amount = 1000000
    context.long = 0
    set_max_position_size(max_notional = 350000)
    context.stop_price = 0

    context.stop_pct = 0.2
 
def handle_data(context, data):
    set_trailing_stop(context, data)
         if data[context.stock].price < context.stop_price:
               order_target(context.stock, 0)

               context.stop_price = 0
    record(price=data[context.stock].price, stop=context.stop_price)

    order_target_percent(context.stocks[0], .05)
    order_target_percent(context.stocks[1], .05)
    order_target_percent(context.stocks[2], .05)
    order_target_percent(context.stocks[3], .05)
    order_target_percent(context.stocks[4], .05)
    order_target_percent(context.stocks[5], .05)
    order_target_percent(context.stocks[6], .05)
    order_target_percent(context.stocks[7], .10)
    order_target_percent(context.stocks[8], .10)
    order_target_percent(context.stocks[9], .05)
    order_target_percent(context.stocks[10], .05)
    order_target_percent(context.stocks[11], .05)
    order_target_percent(context.stocks[13], .05)
    order_target_percent(context.stocks[14], .05)
    order_target_percent(context.stocks[15], .05)
    order_target_percent(context.stocks[16], .05)
    order_target_percent(context.stocks[17], .05)
    order_target_percent(context.stocks[18], .05)

    pv = float(context.portfolio.portfolio_value)
    portfolio_allocations = []
    for stock in context.stocks:
        pos = context.portfolio.positions[stock]
        portfolio_allocations.append(
            pos.last_sale_price * pos.amount / pv * 100
        )

    record(perc_stock_0=portfolio_allocations[0],
        perc_stock_1=portfolio_allocations[1],
        perc_stock_2=portfolio_allocations[2],
        perc_stock_3=portfolio_allocations[3],
        perc_stock_4=portfolio_allocations[4],
        perc_stock_5=portfolio_allocations[5],
        perc_stock_6=portfolio_allocations[6],
        perc_stock_7=portfolio_allocations[7],
        perc_stock_8=portfolio_allocations[8],
        perc_stock_9=portfolio_allocations[9],
        perc_stock_10=portfolio_allocations[10],
        perc_stock_11=portfolio_allocations[11],
        perc_stock_12=portfolio_allocations[12],
        perc_stock_13=portfolio_allocations[13],
        perc_stock_14=portfolio_allocations[14],
        perc_stock_15=portfolio_allocations[15],
        perc_stock_16=portfolio_allocations[16],
        perc_stock_17=portfolio_allocations[17],
        perc_stock_18=portfolio_allocations[18])

def set_trailing_stop(context, data):
    if context.portfolio.positions[context.stock].amount:
        price = data[context.stock].price
        context.stop_price = max(context.stop_price, context.stop_pct * price)

def handle_data(context, data):
    rval = minmax(data)
    if rval is None:
        return
    maximums, minimums = rval
    for stock in context.stocks:
        current_max = maximums[stock]
        current_min = minimums[stock]
        current_price = data[stock].price
        current_position = context.portfolio.positions[stock]
        order_direction = calculate_direction(stock, current_min, current_max, current_price, current_position)
        order_amount = calculate_order_amount(context, stock, order_direction, current_price)
    order(stock, order_amount)

def calculate_direction(stock, current_min, current_max, current_price, current_position):
    if current_max is not None and current_position.amount <= 0 and current_price >= current_max:
        return -1
    elif current_min is not None and current_position.amount >= 0 and current_price <= current_min:
        return 1
    else
        return 0

def calculate_order_amount(context, stock, signal_val, current_price):
    current_amount = context.portfolio.positions[stock].amount
    abs_order_amount = int(context.bet_amount / current_price)
    if signal_val == -1:
        return (-1 * abs_order_amount) – current_amount
    elif signal_val == 1:
        return (1 * abs_order_amount) – current_amount
    else:
        return 0

@batch_transform(refresh_period = 1, window_length = 7)
def minmax(datapanel):
    prices_df = datapanel[‘price’]
    min_price = prices_df.min()
    max_price = prices_df.max()
    if min_price is not None and max_price is not None:
        return (max_price, min_price)
    else:
        return None

No comments:

Post a Comment