Placing stop orders

Hi



I programmed the following intra-day strategy.



Logic:



1 - Used 1 min data

2 - At 10 :00 am, buy stop order is placed at days high and sell stop order is placed at days low.

3 - At 15:20 exit any open positions.



Following is the program, I am not getting the desired result. I am getting problem in placing stop orders. I am not getting any syntex error but it is not executing trades as I wanted. Can you please help me out?


Zipline

from zipline.api import( symbol, get_datetime,order_target_percent,schedule_function,

date_rules, time_rules, attach_pipeline, pipeline_output,

set_commission,set_slippage,get_open_orders,cancel_order,

order_target,order,get_order

)

from zipline.errors import HistoryWindowStartsBeforeData

from zipline.finance import commission,slippage

from zipline.finance.slippage import FixedBasisPointsSlippage

Data manipulation

import pandas as pd

import numpy as np

import talib as ta

import bisect



def initialize(context):

context.universe = [symbol('NIFTY-I')]

context.set_slippage(FixedBasisPointsSlippage(basis_points = 0))

#Inputs

context.inputs = {'starttrade': 45, 'endtrade':345, 'exittime': 365,

'barresolution':'1m' }

#Variable

context.barcount = 0

context.current_bar = 0

context.previous_bar = 0

context.mp = dict((security,0) for security in context.universe)

context.qty = dict((security,0) for security in context.universe)

context.buylevel = 99999

context.selllevel = 0



def before_trading_start(context,data):

pass



def handle_data(context,data):

context.current_bar = data.current_dt.date()

if (context.current_bar != context.previous_bar):

context.barcount = 1

else:

context.barcount = context.barcount + 1

context.previous_bar = context.current_bar

strategy(context,data)

def strategy(context,data):

pricesnew = data.history(context.universe,['high','low'],context.barcount,

context.inputs['barresolution'])

px_high = pricesnew['high'][context.universe[0]].values

px_low = pricesnew['low'][context.universe[0]].values

dayshigh = np.max(px_high)

dayslow = np.min(px_low)

if context.barcount <= context.inputs['starttrade']:

context.buylevel = 99999

context.selllevel = 0

elif context.barcount >= context.inputs['endtrade']:

context.buylevel = 99999

context.selllevel= 0

else:

context.buylevel = dayshigh

context.selllevel = dayslow

placetrade(context,data)



def placetrade(context,data):

for security in context.universe:

marketposition = context.portfolio.positions[security].amount

#print(context.barcount, marketposition,context.buylevel,context.selllevel)

if (marketposition == 0) :

order(security, 75, stop_price = (context.buylevel))

if (marketposition == 0):

order(security, -75, stop_price = (context.selllevel))

if context.barcount == context.inputs['exittime']:

order_target(security, 0)

There are a few issues in your strategy implementation:


use a non-zero stop price (zipline unfortuantely checks if stop_price instead of if stop_price is not None which would have been more accurate)


# you place stoploss orders at every bar between start and end time. This accumulates your orders waiting for a trigger, and then executes all pent-up orders. You track only positions which does not work in this case. You need check for outstanding orders too. Or just use a tracking variable to mark you have already placed an order.

# you place orders with a high and low values to avoid execution. It is better not to place trades at all when you do not want them to execute. That will make back-testing faster and real trading less risky.

# Avoid placing multiple-orders with offsetting characteristics in the same bar. An order to place new trades and also sqaure-off in the same round may place the new trades and fail to square off (as the algo comes to know about the new positions arising out of the new trades only in the next iteration)

Thank you sir. I got the logic.



I have written as following. I there a better way to write it? or is it ok?



def placetrade(context,data):

for security in context.universe:

context.mp = context.portfolio.positions[security].amount

if context.barcount == context.inputs['starttrade']:

context.longid = order(security, 75, stop_price = (context.buylevel))

context.shortid = order(security, -75, stop_price = (context.selllevel))

if context.mp>0 and context.mp != context.premp :

context.longexitid = order(security, -75, stop_price = (context.selllevel))

if context.mp<0 and context.mp != context.premp :

context.shortexitid = order(security, 75, stop_price = (context.buylevel))

if context.barcount == context.inputs['endtrade'] and context.longid != None:

cancel_order(context.longid)

cancel_order(context.shortid)

if context.barcount == context.inputs['exittime']:

if context.longexitid != None:

cancel_order(context.longexitid)

if context.shortexitid != None:

cancel_order(context.shortexitid)

order_target(security, 0)

context.premp = context.mp

you are trading and squaring off at specific times everyday. The best way to write this will be through schedule function. Secondly, you are placing two orders, and want to cancel one if another gets executed. So you need to write a simple once-cancel-other logic too. Together, something like below may be:





def initialize(context):

    context.universe = [symbol('NIFTY-I')]

    context.set_slippage(FixedBasisPointsSlippage(basis_points = 0))



    schedule_function(open_trades, date_rules.every_day(),

                        time_rules.market_open(hours=0, minutes=45))



    schedule_function(square_off, date_rules.every_day(), 

                        time_rules.market_close(hours=0, minutes=10))



    context.b_oid = None

    context.s_oid = None



def handle_data(context, data):

    do_oco(context.b_oid)

    do_oco(context.s_oid)



def open_trades(context,data):

    prices = data.history(context.universe,['high','low'], 45, "1m")



    for sec in context.universe:

        px = prices.minor_xs(sec)

        high = px.high.max()

        low = px.low.min()

        context.b_oid = order(sec, 75, stop_price = high)

        context.s_oid = order(sec, -75, stop_price = low)



def square_off(context,data):

    for sec in context.universe:

        order_target(sec, 0)



def do_oco(oid):

    if oid is None:

        return

    

    order = get_order(oid)

    if order and order.stop_reached:

        oo = get_open_orders()

        for o in oo:

            cancel_order(o)

Thank you sir.