Back to Community
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.

Clone Algorithm
16
Loading...
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?

Clone Algorithm
16
Loading...
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.

Clone Algorithm
4
Loading...
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 ;-)

Clone Algorithm
2
Loading...
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 zipline.utils.tradingcalendar import get_early_closes, get_non_trading_days , get_trading_days

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
    return(dt.date not in context.non_trading_days)

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)

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

def first_tradable_day_of_month(context, y, m):
    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

# from https://www.quantopian.com/posts/intraday-trades
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.non_trading_days = get_non_trading_days(dt_start, dt_stop).date
    #context.trading_days = get_trading_days(dt_start, dt_stop).date
    
    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

Clone Algorithm
1
Loading...
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!