Back

Strategy Migration from Quantopian to QuantConnect

My code shown below has been modified to mask the original values, I'll explain the functions of the mentioned code and ultimately I'd like to have this be ported to QuantConnect to be traded using Interactive Brokers

The strategy is a Sole Short Selling strategy, in the code just for the sake of proving a point a backtest was initiated on 09/08/2017 utilizing only market orders. This was important to determine the ability to #1 get filled and #2 see if the most unreasonable execution could yield a profit. 

The strategy also relies on there being shares available for shorting at Interactive Brokers

Code Function Breakdown - 

Call Open, High, Low, Close, Volume Data

Calculate last day's momentum - Unreasonable, however it has proven profitable

Compute corporate values (book,sales,free cash flow) morning star - sort worst to best

With corporate values determine quality gross profit, balance sheet totals - sort worst to best

Using pandas create a custom volatility factor generated using the last 3 trading day closes. 

- Startup

Rank results based on momentum and utilize only those with a momentum below 0.7 pick the top 5

 

Universe filter - Average volume above N for liquidity

call the last price to be used in the universe filter

calculate average volume on as a 5 day sma

calculate RSI in a percentage

OH Range - 5 day HIGH SMA MINUS 5 DAY OPEN SMA

mean_range = OH Range divided by last price * 100

call value

call momentum

call volality 

filter by vol_range is average volume > greater than a set value to ensure liquidity 

filter by rsi_range = rsi percent greater than and less than set values

filter by OH_range_percent - mean range between two predefined values

define dollar volume = averagedollarvolume(5 day sma)

filter by high_volume = dollar_volume percentile between 20,90

define price = usequity.close.latest

filter by at most price

filter by at least price

initiate pipe screen to include

high_volume, at most price, at least price, volume range, rsi_range, OH range

utilize the S&P as a bench mark

for an orderly market when managing larger sums implement slippage

the strategy rebalances every day on market open

open orders cancelled at market close

positions are closed out once the momentum factor exceeds the universe filter

 

In exchange for your assistance you will learn a new strategy and will receive the original quantopian code which yielded the above results exceeding 300% in less than one year.

 

 

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import CustomFactor, AverageDollarVolume
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.factors import RSI
from quantopian.pipeline.data import morningstar
from zipline.finance.asset_restrictions import HistoricalRestrictions, Restriction, RESTRICTION_STATES as states
from datetime import timedelta

import pandas as pd
import numpy as np



class Value(CustomFactor):

inputs = [morningstar.valuation_ratios.book_value_yield,
morningstar.valuation_ratios.sales_yield,
morningstar.valuation_ratios.fcf_yield]


window_length = 1

def compute(self, today, assets, out, book_value, sales, fcf):
value_table = pd.DataFrame(index=assets)
value_table["book_value"] = book_value[-1]
value_table["sales"] = sales[-1]
value_table["fcf"] = fcf[-1]
out[:] = value_table.rank().mean(axis=1)


class Momentum(CustomFactor):

inputs = [USEquityPricing.close]
window_length = 1

def compute(self, today, assets, out, close):
out[:] = close[-1] / close[0]


class Quality(CustomFactor):

inputs = [morningstar.income_statement.gross_profit, morningstar.balance_sheet.total_assets]
window_length = 1

def compute(self, today, assets, out, gross_profit, total_assets):
out[:] = gross_profit[-1] / total_assets[-1]

class Volatility(CustomFactor):

inputs = [USEquityPricing.close]
window_length = 3

def compute(self, today, assets, out, close):
close = pd.DataFrame(data=close, columns=assets)
# Since we are going to rank largest is best we need to invert the sdev.
out[:] = 1 / np.log(close).diff().std()

# Compute final rank and assign long and short baskets.
def before_trading_start(context, data):
results = pipeline_output('factors').dropna()
ranks = results.rank().mean(axis=1).order()

context.shorts = 1 / ranks[results["momentum"] < .7].head(5)
context.shorts /= context.shorts.sum()

context.security_list = context.shorts.index.tolist()


# Put any initialization logic here. The context object will be passed to
# the other methods in your algorithm.
def initialize(context):
pipe = Pipeline()
pipe = attach_pipeline(pipe, name='factors')
last_price = USEquityPricing.close.latest

#factors
avg_vol = SimpleMovingAverage(inputs=[USEquityPricing.volume],window_length=5)
# RSI Relative Strength Indicator would give stocks that are most
rsi_percentage = RSI(inputs=[USEquityPricing.close], window_length=5)
#Open to High range.
OH_range = (SimpleMovingAverage(inputs=[USEquityPricing.high],window_length=5)
- SimpleMovingAverage(inputs=[USEquityPricing.open],window_length=5))
mean_range = (OH_range / last_price) * 100
#filters

value = Value()
momentum = Momentum()
quality = Quality()
volatility = Volatility()
vol_range = avg_vol > 7000
rsi_range = ((rsi_percentage < 100) & (rsi_percentage > 50))
OH_range_pct = ((mean_range > 1) & (mean_range < 100))


pipe.add(value, "value")
pipe.add(momentum, "momentum")
pipe.add(quality, "quality")
pipe.add(volatility, "volatility")
pipe.add(avg_vol, 'Volume')
pipe.add(rsi_percentage, 'RSI')
pipe.add(mean_range, 'Volatility')



dollar_volume = AverageDollarVolume(window_length=5)
high_volume = dollar_volume.percentile_between(20,90)

price = USEquityPricing.close.latest
AtMostPrice = (price <= 35)
AtLeastPrice = (price >= 2)

# Screen out low liquidity securities.
pipe.set_screen(
high_volume
& AtMostPrice
& AtLeastPrice
& vol_range
& rsi_range
& OH_range_pct
)

context.spy = sid(8554)
context.shorts = None
context.longs = None

#set_commission(commission.PerShare(cost=0.008, min_trade_cost=1))
#set_commission(commission.PerTrade(cost=0.00))
set_slippage(slippage.VolumeShareSlippage(volume_limit=0.15,
price_impact=0.00))
schedule_function(rebalance,
date_rules.every_day(),
time_rules.market_open())
#schedule_function(noovernight, date_rules.every_day(), time_rules.market_close(minutes=30))
schedule_function(cancel_open_orders,
date_rules.every_day(),
time_rules.market_close())
schedule_function(record_vars,
date_rules.every_day(),
time_rules.market_close())
schedule_function(screen_time,
date_rules.every_day(),
time_rules.market_open(minutes=1))




# Will be called on every trade event for the securities you specify.
def record_vars(context, data):
record(lvg=context.account.leverage,
exposure=context.account.net_leverage,
pos_count=len(context.portfolio.positions),
oo=len(get_open_orders()))

def screen_time(context,data):

results = pipeline_output('factors')

context.pipeline_output = results.sort_values('momentum', ascending = True).iloc[:5]

#Total number of securities that the fit the strategy
print 'Total Securities in the Universe: %d' % len(results)

#Stocks to be traded
log.info("\n" + str(context.pipeline_output.head(5)))
log.info("\n" + str(len(context.pipeline_output.index)))


def cancel_open_orders(context, data):
open_orders = get_open_orders()
for security in open_orders:
for order in open_orders[security]:
cancel_order(order)



def rebalance(context, data):
for security in context.shorts.index:
if get_open_orders(security):
continue
if data.can_trade(security):
order_target_percent(security, -context.shorts[security])

for security in context.portfolio.positions:
for order in context.portfolio.positions:
continue
if data.can_trade(security) and security not in context.security_list:
order_target_percent(security, 0)

def noovernight(context,data):
for security in context.portfolio.positions:
order_target_percent(security, 0)

def handle_data(context, data):
pass
Update Backtest






The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.



Update Backtest





0

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.


Loading...

This discussion is closed