Stop price in catalyst.api.order


#1

Hi, got an error ‘Order type stop not currency supported by Catalyst. Please use limit or market orders only.’

My strategy required stop price, which is somewhere in beetween of OCHL values.

Any plans to get this type of order supported?

Any possible ways to overcome this limitation?

Maybe this is a limitation of a backtest mode only?


#2

Hi @dimadgo,

The stop order is not supported as not all exchanges have a stop order feature. Please have a look at this related discussion on Github. The enhancement discussed there is in our backlog, I hope we could address it soon.

Thanks,
Lena


#3

I’ve never used the stop order function (both in Quantopian when it supported live stock trading, and in Catalyst) in backtesting or live trading, as I figured that it would be easier to track if I wrote it myself. I can post up examples of regular and trailing stop losses once I’m at a computer, as it is kinda awkward to try and write up on a tablet.


#4

Hi, SOG35, that would be very nice of you!


#5

That is how I see why it is a problem. As soon as handle_data is called only every minute even on a life mode (right?), we have to wait for the next minute iteration before getting market data, as well as an other minute to send a market/limit order. That is a disaster for some strategies, including the one I have developed.

The most elegant solution for that problem seems to be a stop order implementation, that is ready to go on the market and just updated each iteration. Alternatively, a more frequent iteration, what is a subject to exchange’s API limits.

btw, I trade at Bitfinex, which is currently the biggest market and supports stop and many other types of orders.

For me personally this is so critical, that I would have to place further Catalyst development on hold until possible future implementation, otherwise I did not get the issue correctly and there could be some possible solutions to bypass that?

Please advice.


#6

OK, since you said that you are using Bitfinex (which I cannot use since I am American), I’m assuming that you can put in market orders, so I’m going enter it as such. The only exchange I’ve tried live trading with (Poloniex) does not allow market orders, so when I do a manual stop, I have to set a limit price that is low enough that it will likely fill.

Anyway, for a regular stop loss:

def initialize(context):

context.asset = symbol('btc_usd')
context.sell_pct = 0
context.stop_pct = 0.95

def handle_data(context, data):

cost_basis = context.portfolio.positions[context.asset].cost_basis
current_price = data.current(context.asset, 'price')
orders = context.blotter.open_orders
pos_amount = context.portfolio.positions[context.asset].amount
stop_price = cost_basis * context.stop_pct

if pos_amount > 0:
    if current_price <= stop_price:
        if len(orders) > 0:
            for order in orders:
                cancel_order(order)
                log.info('{}: canceling order'.format(data.current_dt))
                order_target_percent(context.asset, context.sell_pct)
        elif len(orders) == 0:
            order_target_percent(context.asset, context.sell_pct)

You’ll have to double check the formatting on cancellation, I’m not quite sure if I have it formatted right. The reason I have it formatted this way is so if I have an open order (say, for example, I’m already trying to limit sell at a different price, and then the price tanks to the point that I need to bail out immediately), it cancels this order and then immediately places the stop loss.

Now, for trailing stop loss:

def initialize(context):

context.asset = symbol('btc_usd')
context.sell_pct = 0
context.stop_pct = 0.95
context.stop_price = 0

def handle_data(context, data):

cost_basis = context.portfolio.positions[context.asset].cost_basis
current_price = data.current(context.asset, 'price')
orders = context.blotter.open_orders
pos_amount = context.portfolio.positions[context.asset].amount
context.stop_price = max(context.stop_price, cost_basis * context.stop_pct, current_price * context.stop_pct)

if pos_amount > 0:
    if current_price <= context.stop_price:
        if len(orders) > 0:
            for order in orders:
                cancel_order(order)
                log.info('{}: canceling order'.format(data.current_dt))
                order_target_percent(context.asset, context.sell_pct)
                context.stop_price = 0
        elif len(orders) == 0:
            order_target_percent(context.asset, context.sell_pct)
            context.stop_price = 0

In addition to the above, for the trailing stop loss, after your strategy makes a purchase, you will want to add context.stop_price = 0 in the line after your order. This resets the trailing stop loss so that it is not using the value from a previous trade.

As far as timing, the minute that it discovers that the current price is below your stop loss threshold, you should be able to get the stop loss order placed immediately


#7

Dear SOG35, first, thank you for your efforts !

I have studied your code and comments, but, if I am not mistaken, it does not give a solution to the problem described above, as anyway the algo would wait for at least 1 min before getting fresh price data, as well as taking any action, which crushes some strategies completely. Currently, I see not solution except enabling sending stop order, that is triggered inside the exchange (bitfinex). I would be grateful for your note on this opinion.

Concerning this your statement, I can not get it how can we have the “stop loss order placed immediately”, without market-established stop order once we are still bound to minute-to-minute limitation in getting and sending data.


#8

Best I can tell, wouldn’t the algo need to wait at least 1 minute before a native stop order would be triggered anyway? I don’t place stop orders very often in manual trading (both in stocks and crypto) because they almost always seem to be able to find the exact bottom, but I would think that if you had a stop loss order on the books, it would tie up those funds and prevent the strategy from continuing unless the order was first canceled.


#9

Thanks for this, I have a question - This only cancels open orders, but isn’t it missing also cancelling positions (filled orders) when they reach their stop loss?


#10

I agree with the above, the solution does not address the issue with smaller than 1min resolutions. In particular, if you wanted to place a stop-limit order only once another limit order has been fulfilled, then you would like to place the order at a stop of the buy-limit order. However, since stop orders are not supported and the api is only called once per minute, the price could have moved drastically in one minute and exceed your intended sell limit price.