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]:
{96414821: <fxcm.fxcm_oco_order at 0x7f3535cccdd8>}

con.get_oco_order_ids() returns the OCO order ids.

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

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 96414821 96414821
orderId 96414820 96414825
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 01122018120146842 01122018120146842
timeInForce GTC GTC
tradeId 96414822 96414826
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

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]:
96414821

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.49865
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 96414821 96414821
orderId 96414820 96414825 96414855
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 01122018120219537 01122018120146842 01122018120219537
timeInForce GTC GTC GTC
tradeId 96414822 96414826 96414856
type LE SE LE

9.3. The fxcm_oco_order Class

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

In [18]:
oco_order = con.get_oco_order(bulk_id)
In [19]:
oco_order
Out[19]:
<fxcm.fxcm_oco_order at 0x7f3535cccdd8>

This class provides methods to get the instance’s ocoBulkId

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

… the ids of the contained orders …

In [21]:
oco_order.get_order_ids()
Out[21]:
[96414825, 96414855]

… and the order objects itself.

In [22]:
oco_order.get_orders()
Out[22]:
[<fxcm.fxcm_order at 0x7f3535646cf8>, <fxcm.fxcm_order at 0x7f3535668cc0>]

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]:
[<fxcm.fxcm_order at 0x7f3535646cf8>,
 <fxcm.fxcm_order at 0x7f3535668cc0>,
 <fxcm.fxcm_order at 0x7f3534e00048>]
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]:
[96414855, 96414934]