How can I sell automatically a few days later after I place a buy order?

I have a problem when I started to program a simple strategy. Basically, what I want is, for example, selling the stock automatically in 5 days after I buy the stock. How I can achieve this using this platform?

6 responses

I figured it out. Just add a variable in 'context' to countdown the selling dates for each stock in the universe. Every time you buy a stock, you add a countdown for that stock. Then decrease the countdown by 1 per frame, when it reaches 0, it is the time to sell that stock. Attached is an example, but the strategy implemented here is not good, it's just for the illustration.

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
# Put any initialization logic here.  The context object will be passed to
# the other methods in your algorithm.

def initialize(context):
set_universe(universe.DollarVolumeUniverse(40, 45))

context.countdown = {}

# 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.

# Place orders with the order(SID, amount) method.

# TODO: implement your own logic here.
num_of_days_to_sell = 30
for sid in data:
# check if we should sell
if sid in context.countdown and context.countdown[sid] != []:
days_left = context.countdown[sid][0]
if days_left > 0:
context.countdown[sid][0] = days_left - 1
else:
context.countdown[sid].pop(0)
# sell the stock
order(sid, -100)
message = 'sell {n} shares {s}.'
log.info(message.format(n = 100, s = sid.symbol))

# check if we should buy
daily_return = data[sid].returns()
# if the stock drops more than 20%, buy it
if daily_return < -0.20:
order(sid, +100)
message = 'buy {n} shares {s}.'
log.info(message.format(n = 100, s = sid.symbol))
# set the selling date
if sid not in context.countdown:
context.countdown[sid] = [num_of_days_to_sell]
else:
context.countdown[sid].append(num_of_days_to_sell)


There was a runtime error.

An easier and probably more robust approach is to store a dict that maps your symbol to a target sale time, and then once per frame, look at your holdings and see if that time has been reached. Looking purely at frame counts is a great way for timing to go screwy due to unexpected irregularities.

Hi J. Shagam, thanks for your suggestion. Actually I thought about the approach you mentioned, but the problem is that 5 days later after the buying date may not be a trading day, so the date may never be reached. Or is there any way to get the 5th trading day after the buying date?

Ah, if you want trading days rather than calendar days, then yeah you'll have to do something like that.

Maybe nudge you in the right direction or some direction anyway to hopefully be able to tell when five trading days have gone by...

import datetime as dt  # Surprising that datetime doesn't have timezone
from pytz import timezone
from zipline.utils import tradingcalendar

def handle_data(context, data):
# Real-world time now
days_offset = 0  # Alter days_offset like 2 to go back in time 2 days.
today  = dt.date.today() - dt.timedelta(days=days_offset) # end
y_now  = today.year
m_now  = today.month
d_now  = today.day
week   = today - dt.timedelta(days=7) # start, a week ago
y_week = week.year
m_week = week.month
d_week = week.day
start  = dt.datetime(y_week,m_week,d_week,0,0,0,0,timezone('US/Eastern'))
end    = dt.datetime(y_now, m_now, d_now, 0,0,0,0,timezone('US/Eastern'))