9. OCO Orders

This section is about OCO (“One Cancels Other”) orders.

In [1]:
import fxcmpy
import pandas as pd
import datetime as dt
con = fxcmpy.fxcmpy(config_file='fxcm.cfg')

9.1. Creating an OCO Order

To begin with, check the open positons.

In [2]:
con.get_orders()
Out[2]:

OCO orders are created by the method con.create_oco_order(). A detailed description of the method’s parameters is found in section API Documentation.

In [3]:
oco_order = con.create_oco_order(account_id='2815291',
                                 symbol='EUR/USD',
                                 is_buy=True, is_buy2=False,
                                 amount=30, is_in_pips= False,
                                 time_in_force='GTC',
                                 at_market=1,
                                 order_type='MarketRange',
                                 expiration='01122017',
                                 limit=1.13, limit2=1.12,
                                 rate=1.11, rate2=1.13,
                                 stop=1.1, stop2=1.15,
                                 trailing_step=0, trailing_step2=0,
                                 trailing_stop_step=0,
                                 trailing_stop_step2=0)

The con.oco_orders attribute is a dict object, containing all existing OCO orders as values and their ids as keys.

In [4]:
con.oco_orders
Out[4]:
{404812350: <fxcmpy.fxcmpy_oco_order.fxcmpy_oco_order at 0x7fac5c24d1d0>}

con.get_oco_order_ids() returns the OCO order ids.

In [5]:
con.get_oco_order_ids()
Out[5]:
[404812350]

After the OCO order placement, two orders a active. The ocoBulkId value connects the two orders to the OCO order.

In [6]:
con.get_orders().T
Out[6]:
0 1
accountId 2815291 2815291
accountName 02815291 02815291
amountK 30 30
buy 1.11 0
currency EUR/USD EUR/USD
currencyPoint 3 3
expireDate
isBuy True False
isELSOrder False False
isEntryOrder True True
isLimitOrder True False
isNetQuantity False False
isStopOrder False True
limit 1.13 1.12
limitPegBaseType -1 -1
limitRate 1.13 1.12
ocoBulkId 404812350 404812350
orderId 404812349 404812351
range 0 0
ratePrecision 5 5
sell 0 1.13
status 1 1
stop 1.1 1.15
stopMove 0 0
stopPegBaseType -1 -1
stopRate 1.1 1.15
t 3 3
time 06072018135952931 06072018135952932
timeInForce GTC GTC
tradeId 178168188 178168189
type LE SE

9.2. Changing OCO Orders

To add an existing order to an OCO order, the method con.add_to_oco() is used.

First, an entry order is created.

In [7]:
order = con.create_entry_order(symbol='USD/JPY', is_buy=True, rate = 110,
                               amount=50, is_in_pips = False,
                               time_in_force='GTC', stop=None,
                               limit=112, trailing_step=None)

The new order’s id is:

In [8]:
order_id = order.get_orderId()
order_id
Out[8]:
404812374

The order’s ocoBulkId should be 0:

In [9]:
order.get_ocoBulkId()
Out[9]:
0

Second, the order is added to the OCO order via the ocoBulkId value.

In [10]:
bulk_id = con.get_oco_order_ids()[0]
In [11]:
con.add_to_oco(oco_bulk_id=bulk_id, order_ids=[order_id])

Now the ocoBulkId value is the same as for the OCO order from above.

In [12]:
order.get_ocoBulkId()
Out[12]:
404812350

Removing an order is accomplished via the con.remove_from_oco() method.

In [13]:
con.remove_from_oco(order_ids=[order_id])
In [14]:
order.get_ocoBulkId()
Out[14]:
0

Once can also add and remove orders in one step, just use edit_oco_order()

In [15]:
order_id_2 = con.get_order_ids()[0]
In [16]:
con.edit_oco(oco_bulk_id=bulk_id,
             remove_order_ids=[order_id_2],
             add_order_ids=[order_id])
In [17]:
con.get_orders().T
Out[17]:
0 1 2
accountId 2815291 2815291 2815291
accountName 02815291 02815291 02815291
amountK 30 30 50
buy 1.11 0 110
currency EUR/USD EUR/USD USD/JPY
currencyPoint 3 3 4.54496
expireDate
isBuy True False True
isELSOrder False False False
isEntryOrder True True True
isLimitOrder True False True
isNetQuantity False False False
isStopOrder False True False
limit 1.13 1.12 112
limitPegBaseType -1 -1 -1
limitRate 1.13 1.12 112
ocoBulkId 0 404812350 404812350
orderId 404812349 404812351 404812374
range 0 0 0
ratePrecision 5 5 3
sell 0 1.13 0
status 1 1 1
stop 1.1 1.15 0
stopMove 0 0 0
stopPegBaseType -1 -1 -1
stopRate 1.1 1.15 0
t 3 3 3
time 06072018140139676 06072018135952932 06072018140139677
timeInForce GTC GTC GTC
tradeId 178168188 178168189 178168201
type LE SE LE

9.3. The fxcmpy_oco_order Class

The methods con.get_oco_order() and con.create_oco_order() both return an instance of the fxcmpy_oco_order class.

In [18]:
oco_order = con.get_oco_order(bulk_id)
In [19]:
oco_order
Out[19]:
<fxcmpy.fxcmpy_oco_order.fxcmpy_oco_order at 0x7fac5c24d1d0>

This class provides methods to get the instance’s ocoBulkId

In [20]:
oco_order.get_ocoBulkId()
Out[20]:
404812350

… the ids of the contained orders …

In [21]:
oco_order.get_order_ids()
Out[21]:
[404812351, 404812374]

… and the order objects itself.

In [22]:
oco_order.get_orders()
Out[22]:
[<fxcmpy.fxcmpy_order.fxcmpy_order at 0x7fac4839d9e8>,
 <fxcmpy.fxcmpy_order.fxcmpy_order at 0x7fac48391a20>]

The class has also methods to add or remove existing orders.

In [23]:
new_order = con.create_entry_order(symbol='GBP/USD', is_buy=True,
                                   amount=300, rate= 1.36,
                                   limit=1.37, is_in_pips = False,
                                   time_in_force='GTC')
In [24]:
oco_order.add_order([new_order])
In [25]:
oco_order.get_orders()
Out[25]:
[<fxcmpy.fxcmpy_order.fxcmpy_order at 0x7fac4839d9e8>,
 <fxcmpy.fxcmpy_order.fxcmpy_order at 0x7fac48391a20>,
 <fxcmpy.fxcmpy_order.fxcmpy_order at 0x7fac4833d9e8>]
In [26]:
oco_order.remove_order([new_order])

It is also possible to add orders to or remove from the OCO order in a single step.

In [27]:
order = oco_order.get_orders()[0]
In [28]:
oco_order.edit_order(add_orders=[new_order], remove_orders=[order])
In [29]:
oco_order.get_order_ids()
Out[29]:
[404812374, 404812521]
In [30]:
con.close()