Just trying to implement a simple EMA crossover exit strategy where when a 13d EMA crosses over a 50d EMA to the downside for a given stock in a portfolio, the algo exits the position. This is on top of an existing rebalance function that also exits the position if a stock in the portfolio doesn't make it through the screener. I've run the backtest and it seems like the results are the same regardless of the EMA crossover exit strategy so I'm assuming it's not running properly despite no error msgs being thrown. Here's the code. Any help would be awesome. Thanks!
The bit of code I added for the EMA crossover is:
schedule_function(close_out, date_rules.every_day(), time_rules.market_open(minutes=30))
def close_out(context, data):
for stock in context.portfolio.positions:
#last_price = context.portfolio.positions[stock].last_sale_price
my_stock_series = data.history(stock, "price", bar_count=30, frequency="1d")
mavg_short = talib.EMA(my_stock_series, timeperiod=13)
mavg_long = talib.EMA(my_stock_series, timeperiod=50)
#print 'symbol: ', stock.symbol
#print 'last price: ', last_price
if (mavg_short[-1] < mavg_long[-1]) and (mavg_short[-2] > mavg_long[-2]):
order_target_percent(stock, 0)
import pandas as pd
import numpy as np
import talib
def initialize(context):
# Dictionary of stocks and their respective weights
context.stock_weights = {}
# Count of days before rebalancing
context.days = 0
# Number of sectors to go long in
context.sect_numb = 2
# Sector mappings
context.sector_mappings = {
101.0: "Basic Materials",
102.0: "Consumer Cyclical",
103.0: "Financial Services",
104.0: "Real Estate",
205.0: "Consumer Defensive",
206.0: "Healthcare",
207.0: "Utilites",
308.0: "Communication Services",
309.0: "Energy",
310.0: "Industrials",
311.0: "Technology"
}
# Rebalance monthly on the first day of the month at market open
schedule_function(close_out, date_rules.every_day(), time_rules.market_open(minutes=30))
schedule_function(rebalance, date_rules.every_day(), time_rules.market_open(minutes=30))
def close_out(context, data):
for stock in context.portfolio.positions:
#last_price = context.portfolio.positions[stock].last_sale_price
my_stock_series = data.history(stock, "price", bar_count=30, frequency="1d")
mavg_short = talib.EMA(my_stock_series, timeperiod=13)
mavg_long = talib.EMA(my_stock_series, timeperiod=50)
#print 'symbol: ', stock.symbol
#print 'last price: ', last_price
if (mavg_short[-1] < mavg_long[-1]) and (mavg_short[-2] > mavg_long[-2]):
order_target_percent(stock, 0)
def rebalance(context, data):
# Exit all positions before starting new ones
for stock in context.portfolio.positions:
if stock not in context.fundamental_df:
order_target_percent(stock, 0)
log.info("The two sectors we are ordering today are %r" % context.sectors)
# Create weights for each stock
weight = create_weights(context, context.stocks)
# Rebalance all stocks to target weights
for stock in context.fundamental_df:
if weight != 0:
log.info("Ordering %0.0f%% percent of %s in %s"
% (weight * 100,
stock.symbol,
context.sector_mappings[context.fundamental_df[stock]['morningstar_sector_code']]))
if data.can_trade(stock) == True:
order_target_percent(stock, weight)
# track how many positions we're holding
#record(num_positions = len(context.fundamental_df))
record(num_positions = len(context.portfolio.positions))
record(leverage = context.account.leverage)
def before_trading_start(context, data):
"""
Called before the start of each trading day.
It updates our universe with the
securities and values found from fetch_fundamentals.
"""
num_stocks = 50
# Setup SQLAlchemy query to screen stocks based on PE ration
# and industry sector. Then filter results based on
# market cap and shares outstanding.
# We limit the number of results to num_stocks and return the data
# in descending order.
fundamental_df = get_fundamentals(
query(
# put your query in here by typing "fundamentals."
fundamentals.valuation_ratios.pe_ratio,
fundamentals.valuation_ratios.peg_ratio,
fundamentals.valuation_ratios.pb_ratio,
fundamentals.earnings_report.diluted_eps,
fundamentals.valuation_ratios.book_value_per_share,
fundamentals.asset_classification.morningstar_sector_code
)
.filter(fundamentals.valuation.market_cap >= 100e6)
.filter(fundamentals.valuation.shares_outstanding != None)
.filter(fundamentals.valuation_ratios.fcf_yield >= .03)
.filter(fundamentals.valuation_ratios.ev_to_ebitda <= 20.0)
.filter(fundamentals.operation_ratios.roic >= .04)
#.filter(fundamentals.valuation_ratios.peg_ratio < 1.5)
.order_by(fundamentals.valuation.market_cap.desc())
.limit(num_stocks)
)
# Find sectors with the highest average PE
sector_pe_dict = {}
for stock in fundamental_df:
sector = fundamental_df[stock]['morningstar_sector_code']
pe = fundamental_df[stock]['pe_ratio']
# peg = fundamental_df[stock]['peg_ratio']
# pb = fundamental_df[stock]['pb_ratio']
# bvps = fundamental_df[stock]['book_value_per_share']
# eps = fundamental_df[stock]['diluted_eps']
# if fundamental_df[stock]['morningstar_sector_code'] = 103:
# graham_number = sqrt(15 * eps * bvps)
# else:
# graham_number = sqrt(22.5 * eps * bvps)
#
# graham_margin_of_safety = price / graham number
# If it exists add our pe to the existing list.
# Otherwise don't add it.
if sector in sector_pe_dict:
sector_pe_dict[sector].append(pe)
# sector_pe_dict[sector].append(peg)
# sector_pe_dict[sector].append(pb)
# sector_pe_dict[sector].append(bvps)
# sector_pe_dict[sector].append(eps)
# sector_pe_dict[sector].append(graham_number)
# sector_pe_dict[sector].append(graham_margin_of_safety)
else:
sector_pe_dict[sector] = []
print sector_pe_dict
# Find average PE per sector
sector_pe_dict = dict([(sectors, np.mean(sector_pe_dict[sectors],axis=0))
for sectors in sector_pe_dict if len(sector_pe_dict[sectors]) > 0])
# Sort in ascending order
sectors = sorted(sector_pe_dict, key=lambda x: sector_pe_dict[x], reverse=True)[:context.sect_numb]
# Filter out only stocks with that particular sector
context.stocks = [stock for stock in fundamental_df
if fundamental_df[stock]['morningstar_sector_code'] in sectors]
# Initialize a context.sectors variable
context.sectors = [context.sector_mappings[sect] for sect in sectors]
# Update context.fundamental_df with the securities (and pe_ratio) that we need
context.fundamental_df = fundamental_df[context.stocks]
update_universe(context.fundamental_df.columns.values)
def create_weights(context, stocks):
"""
Takes in a list of securities and weights them all equally
"""
if len(stocks) == 0:
return 0
else:
weight = 1.0/len(stocks)
return weight
def handle_data(context, data):
"""
Code logic to run during the trading day.
handle_data() gets called every bar.
"""