Mariner Backtesting - Immediate or Cancel Example

Example IOC orders using order.algo_buy() and order.algo_sell()

see also: GUIDs for IOC orders

Working Example:

 # Copyright Cloudquant, LLC. All right reserved.
from cloudquant.interfaces import Strategy


class ImmediateOrCancel(Strategy):
    @classmethod
    def is_symbol_qualified(cls, symbol, md, service, account):
        return symbol in ["SPY", "AAPL", "GDX", "NUGT", "XLF", "JNUG"]

    def on_start(self, md, order, service, account):

        # print start time and symbol
        print(self.symbol + "\t" + service.time_to_string(service.system_time) + "\tin on_start()")

        # add a timer to enter a position at 9:33
        service.add_time_trigger(service.time(9, 33), timer_id='enter')

        # add a timer to exit any position held at the end of the day
        service.add_time_trigger(service.time(15, 59, 35), repeat_interval=service.time_interval(seconds=5), timer_id='exit')

    def on_timer(self, event, md, order, service, account):

        if event.timer_id == 'enter':
            # Send Order, algorithm: Sell IOC ARCA at Script Price
            # Immediately buy up to 10,000 shares, cancel the rest
            order_id = order.algo_sell(self.symbol, "43e3ee45-5516-4881-9dce-2fdff9741410",
                                       intent="init", order_quantity=10000, price=md.L1.ask)

            # print the symbol, time, and the order_id
            print("\n" + self.symbol + "\t" + service.time_to_string(event.timestamp) + "\torder number: " + order_id)

        else:

            # Cancel the buy order
            order.cancel(self.symbol)
            if account[self.symbol].position.capital_short != 0.00:
                # Send exit order
                # Algorithm: Buy Market ARCA
                order.algo_buy(self.symbol, '2b4fdc55-ff01-416e-a5ea-e1f1d4524c7d', intent='exit')


    def on_fill(self, event, md, order, service, account):
        # if shares are bought
        if event.shares > 0:
            print('\nBUY\t' + self.symbol + '\t' + service.time_to_string(event.timestamp) + "\tin on_fill()")

        # if shares are sold
        elif event.shares < 0:
            print('\nSELL\t' + self.symbol + '\t' + service.time_to_string(event.timestamp) + "\tin on_fill()")

            # after a position has been entered place an limit exit order
            # algorithm: Buy Limit ARCA PL at Script Price
            order.algo_buy(self.symbol, "e3ad53b9-4195-4c68-8407-f38be2a94f04", intent='exit', price=md.L1.bid - .15)

        # print statement when an order fills
        print('\n', service.time_to_string(event.timestamp), event)

    def on_cancel(self, event, md, order, service, account):
        print('\n', service.time_to_string(event.timestamp), event)

Console

AAPL    2016-11-01 09:25:00.000000  in on_start()
GDX 2016-11-01 09:25:00.000000  in on_start()
JNUG    2016-11-01 09:25:00.000000  in on_start()
NUGT    2016-11-01 09:25:00.000000  in on_start()
SPY 2016-11-01 09:25:00.000000  in on_start()
XLF 2016-11-01 09:25:00.000000  in on_start()

AAPL    2016-11-01 09:33:00.000000  order number: 0000000000000001

GDX 2016-11-01 09:33:00.000000  order number: 0000000000000002

JNUG    2016-11-01 09:33:00.000000  order number: 0000000000000003

NUGT    2016-11-01 09:33:00.000000  order number: 0000000000000004

SPY 2016-11-01 09:33:00.000000  order number: 0000000000000005

XLF 2016-11-01 09:33:00.000000  order number: 0000000000000006

2016-11-01 09:33:00.001700 CancelEvent(instruction_id='249d6ba4-f32e-5f04-801b-2d7365b7f5d7', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='249d6ba4-f32e-5f04-801b-2d7365b7f5d7', order_id='0000000000000001', state='C', price=113.66999816894531, shares=None, reason='market bid < order price on immediate or cancel order', timestamp=1478007180001700, symbol='AAPL', account_id=0, clordid=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=6)

2016-11-01 09:33:00.001700 CancelEvent(instruction_id='498dbeee-342e-52aa-840c-ef0ecf0f6356', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='498dbeee-342e-52aa-840c-ef0ecf0f6356', order_id='0000000000000002', state='C', price=25.17, shares=-3000, reason='Order partially filled, remainder cancelled', timestamp=1478007180001700, symbol='GDX', account_id=0, clordid=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=6)

SELL    GDX 2016-11-01 09:33:00.001700  in on_fill()

2016-11-01 09:33:00.001700 FillEvent(instruction_id='498dbeee-342e-52aa-840c-ef0ecf0f6356', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='498dbeee-342e-52aa-840c-ef0ecf0f6356', order_id='0000000000000002', state='E', price=25.17, shares=-3000, timestamp=1478007180001700, symbol='GDX', account_id=0, clordid=None, collect=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', actual_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=8)

2016-11-01 09:33:00.001700 CancelEvent(instruction_id='d444efa8-eaf2-54e0-a4d6-fa0b35641c8f', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='d444efa8-eaf2-54e0-a4d6-fa0b35641c8f', order_id='0000000000000003', state='C', price=13.350000381469727, shares=None, reason='market bid < order price on immediate or cancel order', timestamp=1478007180001700, symbol='JNUG', account_id=0, clordid=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=6)

2016-11-01 09:33:00.001700 CancelEvent(instruction_id='0905ea43-ef33-5ede-95a2-5aacf36d402b', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='0905ea43-ef33-5ede-95a2-5aacf36d402b', order_id='0000000000000004', state='C', price=15.15999984741211, shares=None, reason='market bid < order price on immediate or cancel order', timestamp=1478007180001700, symbol='NUGT', account_id=0, clordid=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=6)

SELL    SPY 2016-11-01 09:33:00.001700  in on_fill()

2016-11-01 09:33:00.001700 FillEvent(instruction_id='fe466038-7f05-552d-8b00-8de16aec2835', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='fe466038-7f05-552d-8b00-8de16aec2835', order_id='0000000000000005', state='F', price=212.84, shares=-10000, timestamp=1478007180001700, symbol='SPY', account_id=0, clordid=None, collect=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', actual_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=8)

2016-11-01 09:33:00.001700 CancelEvent(instruction_id='50a4a957-b1fd-560e-ae64-d821d8fcbc6f', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='50a4a957-b1fd-560e-ae64-d821d8fcbc6f', order_id='0000000000000006', state='C', price=19.850000381469727, shares=None, reason='market bid < order price on immediate or cancel order', timestamp=1478007180001700, symbol='XLF', account_id=0, clordid=None, intent='init', order_algorithm='43e3ee45-5516-4881-9dce-2fdff9741410', expected_direction='increase', script_class_name='ImmediateOrCancel', line_number=26, kind=6)

2016-11-01 09:37:33.092000 CancelEvent(instruction_id='fe466038-7f05-552d-8b00-8de16aec2835', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='fe466038-7f05-552d-8b00-8de16aec2835', order_id='0000000000000008', state='C', price=212.68001, shares=133, reason='Order partially filled, remainder cancelled', timestamp=1478007453092000, symbol='SPY', account_id=0, clordid=None, intent='exit', order_algorithm='limit', expected_direction='reduce', script_class_name='ImmediateOrCancel', line_number=52, kind=6)

BUY SPY 2016-11-01 09:37:33.092000  in on_fill()

2016-11-01 09:37:33.092000 FillEvent(instruction_id='fe466038-7f05-552d-8b00-8de16aec2835', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='fe466038-7f05-552d-8b00-8de16aec2835', order_id='0000000000000008', state='E', price=212.68001, shares=133, timestamp=1478007453092000, symbol='SPY', account_id=0, clordid=None, collect=None, intent='exit', order_algorithm='limit', expected_direction='reduce', actual_direction='reduce', script_class_name='ImmediateOrCancel', line_number=52, kind=8)

BUY GDX 2016-11-01 10:06:49.827000  in on_fill()

2016-11-01 10:06:49.827000 FillEvent(instruction_id='498dbeee-342e-52aa-840c-ef0ecf0f6356', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='498dbeee-342e-52aa-840c-ef0ecf0f6356', order_id='0000000000000007', state='F', price=25.010000228881836, shares=3000, timestamp=1478009209827000, symbol='GDX', account_id=0, clordid=None, collect=None, intent='exit', order_algorithm='limit', expected_direction='reduce', actual_direction='reduce', script_class_name='ImmediateOrCancel', line_number=52, kind=8)

BUY SPY 2016-11-01 15:59:35.001700  in on_fill()

2016-11-01 15:59:35.001700 FillEvent(instruction_id='fe466038-7f05-552d-8b00-8de16aec2835', script_id=u'3960b0e7-53f2-45dd-a643-fbe8189299c3', user_key='fe466038-7f05-552d-8b00-8de16aec2835', order_id='0000000000000009', state='F', price=211.05999755859375, shares=9867, timestamp=1478030375001700, symbol='SPY', account_id=0, clordid=None, collect=None, intent='exit', order_algorithm='market', expected_direction='reduce', actual_direction='reduce', script_class_name='ImmediateOrCancel', line_number=38, kind=8)