My first algorithm

Hey guys, I'm new to the community. This is my first piece of code that I've ever written. I'm currently taking intro to programming so I know a bit of Python.

I wrote this very basic algorithm to get a basic grasp of Datetime and how Quantopian works. A couple of questions though...

I'm currently only executing this trade in 2009. My plan with this algorithm is to buy on the last day of each month and sell at the end of the first day of each month.

How do I specify to sell at the end of the day?

I'm very confused as to if why if I sell in on the last day of each month and buy on the first day of each month, why are the returns positive when compared to buying on the last day of each month and buying on the first day, my returns are negative and seem to be negatively correlated to the benchmark.

16
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
# Put any initialization logic here.  The context object will be passed to
import datetime

# the other methods in your algorithm.
def initialize(context):
context.security = symbol('SPY')
context.first_day = [datetime.datetime(2011,x,1) for x in range(1,13)]

context.last_day = [datetime.datetime(2011,x,28) for x in range(1,13)]

# Will be called on every trade event for the securities you specify.
def handle_data(context, data):
# Implement your algorithm logic here.

# data[sid(X)] holds the trade event data for that security.
# context.portfolio holds the current portfolio state.

y = get_datetime().year
m = get_datetime().month
d = get_datetime().day

event_date = datetime.datetime(y,m,d)

for eachdate in context.last_day:
if event_date == datetime.datetime(2009,11,1):
order(context.security, -1000)

for eachdate in context.first_day:
if event_date == eachdate:
order(context.security, +1000)


There was a runtime error.
10 responses

Sorry, I found a bug at the bottom when I wasn't comparing to the lists.

Here is the updated algorithm that I have. Does this look right? Are returns supposed to be only 8% for 2011?

16
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
# Put any initialization logic here.  The context object will be passed to
import datetime

# the other methods in your algorithm.
def initialize(context):
context.security = symbol('SPY')
context.first_day = [datetime.datetime(2011,x,1) for x in range(1,13)]

context.last_day = [datetime.datetime(2011,x,28) for x in range(1,13)]

# Will be called on every trade event for the securities you specify.
def handle_data(context, data):
# Implement your algorithm logic here.

# data[sid(X)] holds the trade event data for that security.
# context.portfolio holds the current portfolio state.

y = get_datetime().year
m = get_datetime().month
d = get_datetime().day

event_date = datetime.datetime(y,m,d)

for eachdate in context.last_day:
if event_date == eachdate:
order(context.security, +1000)

for eachdate in context.first_day:
if event_date == eachdate:
order(context.security, -1000)


There was a runtime error.

Hello Kai,

I really like your first_day, last_day approach, but unfortunately it doesn't always execute the order. For instance 28 May 2011 was a Saturday, so your algorithm misses the timing and gets out of sync from what you want.

I believe the quantopian people will introduce a new ordering feature to schedule an order in the future, which would make your algo a lot easier to implement.

Something like this?

I used order_target_percent instead as its more robust, depending on exactly what date you start the backtest.

4
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
import datetime

def initialize(context):
context.security = symbol('SPY')
context.first_day = [datetime.datetime(y,x,1) for x in range(1,13) for y in range(2011,2015)]
context.last_day = [datetime.datetime(y,x,28) for x in range(1,13) for y in range(2011,2015)]

def handle_data(context, data):
y = get_datetime().year
m = get_datetime().month
d = get_datetime().day
event_date = datetime.datetime(y,m,d)

for eachdate in context.last_day:
if event_date >= eachdate: # that date or after
# remove eachdate from the last_day list
context.last_day.remove(eachdate)
order_target_percent(context.security, 0.0)    # no position
log.info("exiting")
break

for eachdate in context.first_day:
if event_date >= eachdate:  # that date or after
# remove eachdate from the first_day list
context.first_day.remove(eachdate)
order_target_percent(context.security, -1.0)    # short
log.info("going short")
break


There was a runtime error.

Some code to show usage of zipline.utils.tradingcalendar and some other details such as generators (yield). But it doesn't seems a great idea... but that was a nice exercice ;-)

2
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
import datetime

from pytz import timezone

def date_allowed(context, dt):
#return(dt.weekday() in [0,1,2,3,4]) # monday=0 -> friday=4 - no saturday=5 no sunday=6

def next_month_first_day(context, y, m):
if m<12:
return(datetime.datetime(y, m+1, 1))
elif m==12:
return(datetime.datetime(y+1, 1, 1))
else:
raise(NotImplementedError)

dt = next_month_first_day(context, y, m)
while True:
dt = dt - datetime.timedelta(days=1)
if date_allowed(context, dt):
break
return(dt)

dt = datetime.datetime(year=y, month=m, day=1)
while not date_allowed(context, dt):
dt = dt + datetime.timedelta(days=1)
return(dt)

def gen_y_m(context, dt_start, dt_stop):
(y_start, m_start) = (dt_start.year, dt_start.month)
(y, m) = (y_start, m_start)
(y_stop, m_stop) = (dt_stop.year, dt_stop.month)

while True:
yield(y, m)
if m==m_stop and y==y_stop:
break
m += 1
if m==13:
m = 1
y += 1

def endofday_check(context, minutes_early):
# Converts all time-zones into US EST to avoid confusion
loc_dt = get_datetime().astimezone(timezone('US/Eastern'))
date = get_datetime().date()

# Checks for an early close on special dates such as holidays and the day after thanksgiving
# The market closes at 1:00PM EST on those days
if date in context.early_closes:
# Returns true if it's 1:00PM - minutes so in this case 12:54PM
if loc_dt.hour == 12 and loc_dt.minute == (59-minutes_early):
log.debug(get_datetime())
return True
else:
return False
# Returns true if it's 4:00PM EST - minutes so in this case at 3:54PM
# Daylight savings time are accounted for, so it will automatically adjust to DST
elif loc_dt.hour == 15 and loc_dt.minute == (59-minutes_early):
log.debug(get_datetime())
return True
else:
return False

def initialize(context):
dt_start = datetime.datetime(2011, 1, 1)
dt_stop = datetime.datetime(2014, 12, 31)

context.security = symbol('SPY')
context.first_day = [first_tradable_day_of_month(context, y, m) for (y, m) in gen_y_m(context, dt_start, dt_stop)]
context.last_day = [last_tradable_day_of_month(context, y, m) for (y, m) in gen_y_m(context, dt_start, dt_stop)]

context.early_closes = get_early_closes(dt_start,dt_stop).date
# Minutes before close that you want to execute your order, so this will execute at 3:55 PM only
context.minutes_early = 5

def handle_data(context, data):
dt = get_datetime()
(y, m, d) = (dt.year, dt.month, dt.day)
event_date = datetime.datetime(y, m, d)

# buy on the last day of each month
# and sell at the end of the first day of each month

for eachdate in context.last_day:
if event_date >= eachdate:  # that date or after
# remove eachdate from the last_day list
log.info("going long")
order_target_percent(context.security, 1.0)    # long
context.last_day.remove(eachdate)
break

for eachdate in context.first_day:
if event_date >= eachdate: # that date or after
# remove eachdate from the first_day list
if endofday_check(context, context.minutes_early):
log.info("exiting")
order_target_percent(context.security, 0.0)
context.first_day.remove(eachdate)
break


There was a runtime error.

Welcome Kai,
Congrats on writing your first algo. It can be a lot to learn outside libraries when you are learning to program, but in this case I think it is pretty straight forward. Pandas has some useful date functionality that might help you out with this sort of thing. They have already written the code to get the fist and last business days of the month. It should work for you unless a market holiday falls on the first or last business day of the month.

cheers,
David

1
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
# Put any initialization logic here.  The context object will be passed to
import datetime

import pandas as pd

from pandas.tseries.offsets import BMonthBegin, BMonthEnd

# the other methods in your algorithm.
def initialize(context):
context.security = symbol('SPY')

context.month_start = BMonthBegin()
context.month_end = BMonthEnd()
context.last_day = pd.Timestamp('2000-01-01')

# Will be called on every trade event for the securities you specify.
def handle_data(context, data):

now = get_datetime()
if context.month_start.onOffset(now):
print "start %s"%now
order_target(context.security, 0)

context.last_day = context.month_end.apply(now)

if now.date() == context.last_day.date():
print "last day %s"%now
order_target_percent(context.security, 1.0)


There was a runtime error.

Hello Kai,

I know that this algo is more of an exercise to learn Quantopian's platform and all that but I am curious about your rationale for the strategy per se. Meaning, what does it mean for you to buy on the last day and sell on the end of the first day of the next month? Is that because of some particular reason or it's just about learning how to program on Quatopian?

Again, I'm just curious and always open to learn from others' ideas. Good luck with your learning!

Akram,
My main rationale is to capture the return from people investing in mutual funds, 401K's. Apparently, I read somewhere that people always add to their accounts on the first of each month.

So you aim at capturing the small bumps that happen between the end of the month and the end of the first day of the next one.

That's very interesting!

Yes, that's what I aim to capture. However, as you can see... my coding skills aren't up to par :(

But they will improve with time, especially with such a helpful and friendly community as Quantopian's.

Just keep coding!