ETF 20 - Ranked by 10-Year Percent Change

Hi Quantopian Community!!

I took the top 20 stocks according to the ''Barcharts Stocks - Ranked by 10-Year Percent Change''

To remember:

You will have to apply a system that will add/remove stocks each year so you will remain with the top 20 stocks. (Currently not applied)

Please feel free to critique this system - I would like to know if you have any other ideas on how such a system can be run or modified.

Thank you in advance for any assistance.

Regards
Alex

63
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
'''
This algorithm defines a target long-only diversified portfolio and rebalances
it at a user-specified frequency.
'''

import datetime
import pytz
import pandas as pd

def initialize(context):
# Define the instruments in the portfolio:
context.sids = {
sid(28570): 0.05,
sid(28160): 0.05,
sid(9736): 0.05,
sid(3450): 0.05,
sid(21774): 0.05,
sid(19917): 0.05,
sid(6413): 0.05,
sid(24): 0.05,
sid(13711): 0.05,
sid(14328): 0.05,
sid(17196): 0.05,
sid(23709): 0.05,
sid(30301): 0.05,
sid(508): 0.05,
sid(24861): 0.05,
sid(3210): 0.05,
sid(26395): 0.05,
sid(25339): 0.05,
sid(10843): 0.05,
sid(20281): 0.05,
}

# Define the benchmark (used to get early close dates for reference).
context.spy           = sid(8554)

start_date = context.spy.security_start_date
end_date   = context.spy.security_end_date

# Initialize context variables the define rebalance logic:
context.rebalance_date = None
context.next_rebalance_Date = None
context.rebalance_days = 30

# Get the dates when the market closes early:
context.early_closes = get_early_closes(start_date, end_date).date

def handle_data(context, data):
# Get the current exchange time, in local timezone:
exchange_time = pd.Timestamp(get_datetime()).tz_convert('US/Eastern')

# If it is rebalance day, rebalance:
if context.rebalance_date == None or exchange_time >= context.next_rebalance_date:
# If we are in rebalance window but there are open orders, wait til next minute
if has_open_orders(data,context) == True:
log.info('Has open orders, not rebalancing.')
else:
# If there are no open orders we can rebalance.
rebalance(context, data, exchange_time)
log.info('Rebalanced portfolio to target weights at %s' % exchange_time)

# Update the current and next rebalance dates
context.rebalance_date = exchange_time
context.next_rebalance_date = context.rebalance_date + datetime.timedelta(days=context.rebalance_days)
print(context.next_rebalance_date)

def rebalance(context,data,exchange_time):
for sid in context.sids:
if sid in data:
order_target_percent(sid, context.sids[sid])

def has_open_orders(data,context):
# Only rebalance when we have zero pending orders.
has_orders = False
for stk in data:
orders = get_open_orders(stk)
if orders:
for oo in orders:
message = 'Open order for {amount} shares in {stock}'
message = message.format(amount=oo.amount, stock=stk)
has_orders = True
return has_orders

There was a runtime error.
7 responses

Hi Alex,

This algorithm is the very definition of look-ahead bias, which in words is defined as:

Bias created by the use of information or data in a study or
simulation that would not have been known or available during the
period being analyzed. This will usually lead to inaccurate results in
the study or simulation.

Unless you have a way of time travelling, you just can't use information from 10 years in the future to pick a basket of stocks. What would be interesting is to pick the top stocks as of 2002 and see what the return on them is going into the future. I did a quick and dirty take, using the "top stocks of 2002" and following them to the present. Somewhat surprisingly, at first blush it seems to have promise. You could try "rebalancing" based on the top stocks each year (after the year closes) and seeing if these results hold true in general or if 2002 was somehow unique. Also, I think the algo needs to handle stocks that go out of business.

8
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
'''
This algorithm defines a target long-only diversified portfolio and rebalances
it at a user-specified frequency.
'''

import datetime
import pytz
import pandas as pd

def initialize(context):
# Define the instruments in the portfolio:
context.sids = {

sid(23065): 0.1,
sid(21669): 0.1,
sid(15408): 0.1,
sid(9451): 0.1,
sid(23759): 0.1,
sid(3585): 0.1,
sid(23602): 0.1,
sid(1597): 0.1,
sid(8722): 0.1,
sid(20855): 0.1,

}

# Define the benchmark (used to get early close dates for reference).
context.spy           = sid(8554)

start_date = context.spy.security_start_date
end_date   = context.spy.security_end_date

# Initialize context variables the define rebalance logic:
context.rebalance_date = None
context.next_rebalance_Date = None
context.rebalance_days = 30

# Get the dates when the market closes early:
context.early_closes = get_early_closes(start_date, end_date).date

def handle_data(context, data):
# Get the current exchange time, in local timezone:
exchange_time = pd.Timestamp(get_datetime()).tz_convert('US/Eastern')

# If it is rebalance day, rebalance:
if context.rebalance_date == None or exchange_time >= context.next_rebalance_date:
# If we are in rebalance window but there are open orders, wait til next minute
if has_open_orders(data,context) == True:
log.info('Has open orders, not rebalancing.')
else:
# If there are no open orders we can rebalance.
rebalance(context, data, exchange_time)
log.info('Rebalanced portfolio to target weights at %s' % exchange_time)

# Update the current and next rebalance dates
context.rebalance_date = exchange_time
context.next_rebalance_date = context.rebalance_date + datetime.timedelta(days=context.rebalance_days)
print(context.next_rebalance_date)

def rebalance(context,data,exchange_time):
for sid in context.sids:
if sid in data:
order_target_percent(sid, context.sids[sid])

def has_open_orders(data,context):
# Only rebalance when we have zero pending orders.
has_orders = False
for stk in data:
orders = get_open_orders(stk)
if orders:
for oo in orders:
message = 'Open order for {amount} shares in {stock}'
message = message.format(amount=oo.amount, stock=stk)
has_orders = True
return has_orders

There was a runtime error.

Oops, wasn't re-balancing because once a security stopped trading the order just stayed unfilled preventing any other orders from happening. Fixed that plus as securities drop out target percentages are now adjusted.

34
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
'''
This algorithm defines a target long-only diversified portfolio and rebalances
it at a user-specified frequency.
'''

import datetime
import pytz
import pandas as pd

def initialize(context):
# Define the instruments in the portfolio:
context.sids = {

sid(23065): 0.1,
sid(21669): 0.1,
sid(15408): 0.1,
sid(9451): 0.1,
sid(23759): 0.1,
sid(3585): 0.1,
sid(23602): 0.1,
sid(1597): 0.1,
sid(8722): 0.1,
sid(20855): 0.1,

}

# Define the benchmark (used to get early close dates for reference).
context.spy           = sid(8554)

start_date = context.spy.security_start_date
end_date   = context.spy.security_end_date

# Initialize context variables the define rebalance logic:
context.rebalance_date = None
context.next_rebalance_Date = None
context.rebalance_days = 30

# Get the dates when the market closes early:
context.early_closes = get_early_closes(start_date, end_date).date

def handle_data(context, data):
# Get the current exchange time, in local timezone:
exchange_time = pd.Timestamp(get_datetime()).tz_convert('US/Eastern')

# If it is rebalance day, rebalance:
if context.rebalance_date == None or exchange_time >= context.next_rebalance_date:
# If we are in rebalance window but there are open orders, wait til next minute
#if has_open_orders(data,context) == True:
#     log.info('Has open orders, not rebalancing.')
#else:
# If there are no open orders we can rebalance.
rebalance(context, data, exchange_time)
log.info('Rebalanced portfolio to target weights at %s' % exchange_time)

# Update the current and next rebalance dates
context.rebalance_date = exchange_time
context.next_rebalance_date = context.rebalance_date + datetime.timedelta(days=context.rebalance_days)
print(context.next_rebalance_date)

def rebalance(context,data,exchange_time):

valid_sids = [sid for sid in context.sids if sid in data and sid.security_end_date >= exchange_time]

print(float(len(valid_sids)))
for sid in valid_sids:

def has_open_orders(data,context):
# Only rebalance when we have zero pending orders.
has_orders = False
for stk in data:
orders = get_open_orders(stk)
if orders:
for oo in orders:
message = 'Open order for {amount} shares in {stock}'
message = message.format(amount=oo.amount, stock=stk)
has_orders = True
return has_orders

There was a runtime error.

Hi Alan thanks for the info and fix!! This looks quite promising to me! I am still new to coding, you have just saved me a tremendous amount of time. Then what do you think about this strategy? Do you think it will be viable? Something that will be better for the longer term investor? If you are looking to run this for 30 years plus? I have been trading a similar strategy(I take the close of the year end of FEB as this is most of the companies Financial year end's here in SA then I remove the stocks that have fallen and add the new top ten entries) (can only afford to buy the top 10 right now) but on the top movers from the JSE (South African Exchange) for the past 2 years, but I have recently been wondering if I am on the right track. I am a student and I am busy getting enough data so I can Include it in my Thesis. I wanted to use a real life example rather than just a fictitious one, that is why I started investing with real money - I have a back-test on some data I received from a trader here but the accuracy of the data bothers me so I basically wanted to add about 3 years worth of real data.

I dont want to be to forward but my very poor attempts to change the algo have all failed... Is there anybody that could somehow add a function to this last algo that can take the data from (Barchart or anyone else) and take the top 20 best performing stocks each year from 2002 until now re-balancing each year with the new top 20?? I am in the process of learning more about programming but it may take me a good few months... lol

look ahead bias is one, but in such strategies, make sure you handle properly the following:
- survivorship bias: tendency to exclude failed or delisted companies during a simulation (because they are not part of your dataset, or because you based you analysis on stocks currently in SP-500 for example)
- invest only if enough liquidity

@Alexander is this leverage? how to remove.. the leverage part... thanks...

@Alan how to make this into symbols...? context=symbols does not work.... thanks...

13 Error SyntaxError: invalid syntax

context.stocks = symbols('SWHC':0.05,
'FIZZ':0.05, 'AMZN':0.05, 'HPY':0.05, 'ATVI':0.05, 'DYAX':0.05, 'STMP':0.05, 'NFLX':0.05, 'SMED':0.05, 'COKE':0.05, 'ABMD':0.05, 'OLED':0.05, 'NTES':0.05, 'NEO':0.05, 'CTRP':0.05, 'HRL':0.05, 'SLP':0.05, 'AYI':0.05, 'TYL':0.05,

)