The main methods for managing orders include methods such as OpenOrder, ModifyOrder, CancelOrder. By calling these methods, developers are essentially providing execution instructions. However, the exchange / trading connection does not guarantee that this instruction will be followed. They can be fulfilled completely, partially or with deviations.
To obtain information about what is happening with orders, developers can override methods such as OnOrderChanged, OnOrderRegisterFailed, OnOrderModifyFailed, OnOrderCancelFailed.
It is important to understand that these methods cause less response from the exchange/trading connection and may be on different threads and may sometimes use sync methods.
Using synchronous methods
Order placing
To place an order, use the OpenOrder method, to which the filled Order entity is passed.
An example of placing a market buy order with a volume of 1 lot:
var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Buy,
Type = OrderTypes.Market,
QuantityToFill = 1,
};
OpenOrder(order);
An example of placing a limit order to sell at a price of 100 with a volume of 1 lot:
var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.Limit,
Price = 100,
QuantityToFill = 1,
};
OpenOrder(order);
An example of placing a stop order to sell at a price of 100 with a volume of 1 lot:
var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.Stop,
TriggerPrice = 100,
QuantityToFill = 1,
};
OpenOrder(order);
An example of placing a stop-limit order to sell at an activation price of 100 and a maximum execution price of 95, with a volume of 1 lot:
var order = new Order
{
Portfolio = Portfolio,
Security = Security,
Direction = OrderDirections.Sell,
Type = OrderTypes.StopLimit,
TriggerPrice = 100,
Price = 95,
QuantityToFill = 1,
};
OpenOrder(order);
The OpenOrder method does not guarantee that an order will be placed, it only sends the order to the exchange. The sending result should be viewed in the OnOrderChanged and OnOrderRegisterFailed methods.
If the exchange rejects the application for placing an order, the OnOrderRegisterFailed method will be called, which will receive a link to the original placed order and a message from the exchange.
In the process of placing an order and accepting it by the exchange, the exchange sends updates to this order. All order updates are sent to OnOrderChanged. Through order.Status() you can get the current state of the order.
An example of placing an order and controlling its placement:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
_firstTime = false;
{
Price = 100,
QuantityToFill = 1,
};
OpenOrder(_order);
}
}
protected override void OnOrderRegisterFailed(
Order order,
string message)
{
if (order == _order)
{
}
}
protected override void OnOrderChanged(
Order order)
{
if (order == _order)
{
switch (order.Status())
{
break;
break;
break;
{
break;
}
break;
}
}
}
}
Represents an order for trading on a financial exchange.
Definition Order.cs:15
decimal Unfilled
Gets the remaining unfilled volume of the order.
Definition Order.cs:318
Represents a portfolio entity with various properties related to account balance, Profit and Loss (Pn...
Definition Portfolio.cs:20
Represents a security entity used in the application.
Definition Security.cs:16
Represents an abstract class for a chart strategy that extends the functionality of an Indicator and ...
Definition ChartStrategy.cs:27
Definition AsyncConnector.cs:2
OrderTypes
Specifies the type of an order.
Definition OrderTypes.cs:7
OrderStatus
Represents the possible status of an order.
Definition OrderStates.cs:33
OrderDirections
Specifies the direction of an order.
Definition OrderDirections.cs:7
Definition ChartStrategy.cs:2
Order changing
To change an placed order, you need to create a copy of this order, change the price or volume in it and call ModifyOrder, passing the old order and the new one as parameters. We also need to remember that if we store a link to the old order, then when modifying we need to assign our field a link to the new order.
If the OnOrderModifyFailed method receives an order previously sent for modification, then the modification was impossible for some reason.
The order change status should be tracked in OnOrderChanged.
In the example of changing an order, it is assumed that the _order
object contains an order that is active at the time of launch:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
_newOrder = _order.
Clone();
_newOrder.Price = 200;
ModifyOrder(_order, _newOrder);
}
}
protected override void OnOrderModifyFailed(
Order order,
Order newOrder,
string error)
{
if (order == _order)
{
}
}
protected override void OnOrderChanged(
Order order)
{
if (order == _newOrder)
{
switch (order.Status())
{
break;
break;
break;
{
break;
}
break;
}
}
}
}
Order Clone()
Creates a shallow copy of the current order.
Definition Order.cs:637
Order canceling
CancelOrder sends an instruction to the exchange to cancel the order. There is also no guarantee of successful cancellation, so you need to track the status of orders in the OnOrderCancelFailed and OnOrderChanged methods.
Before sending a CancelOrder, it is recommended to ensure that the State of the order is equal to OrderStates.Active.
In the order cancellation example, it is assumed that the _order
object contains an order that is active at the time of launch:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
{
CancelOrder(_order);
_firstTime = false;
}
}
}
protected override void OnOrderCancelFailed(
Order order,
string message)
{
if (order == _order)
{
}
}
protected override void OnOrderChanged(
Order order)
{
{
}
}
}
OrderStates State
Gets or sets the current state of the order.
Definition Order.cs:504
bool Canceled
Gets a value indicating whether the order is canceled.
Definition Order.cs:572
OrderStates
Represents the possible states of an order.
Definition OrderStates.cs:7
Using asynchronous methods
You can use asynchronous order management methods just like synchronous ones, and getting the results becomes more convenient.
Now there is no need to track the result in the OnNewOrder, OnOrderChanged, OnOrderRegisterFailed, OnOrderModifyFailed and OnOrderCancelFailed methods. Opening, canceling or modifying an order must be placed in a try-catch
block.
It must be remembered that the result can still be both successful and unsuccessful. If the result was successful, in the code below we can find out the status of the order or perform other necessary actions. If the result is unsuccessful, an exception is thrown and we can intercept it in the catch
block.
It should also be noted that if you have active limit or stop limit orders, the moment when their state or status changes can be found in OnOrderChanged.
Order placing
Using OpenOrderAsync:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
_firstTime = false;
{
Price = 100,
QuantityToFill = 1,
};
OpenPositionAsync(_order);
}
}
private async Task OpenPositionAsync(
Order order)
{
try
{
await OpenOrderAsync(order);
switch (order.Status())
{
break;
break;
break;
}
}
catch (Exception ex)
{
this.LogInfo($"Open position error: {ex.Message}.");
}
}
}
Order changing
Using ModifyOrderAsync:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
ChangeOrderAsync();
}
}
private async Task ChangeOrderAsync()
{
_newOrder = _order.
Clone();
_newOrder.Price = 200;
try
{
await ModifyOrderAsync(_order, _newOrder);
}
catch (Exception ex)
{
}
}
}
Order canceling
Using CancelOrderAsync:
{
private bool _firstTime = true;
protected override void OnCalculate(int bar, decimal value)
{
if (bar == CurrentBar - 1 && _firstTime)
{
{
TryCancelOrderAsync();
_firstTime = false;
}
}
}
private async Task TryCancelOrderAsync()
{
try
{
await CancelOrderAsync(_order);
}
catch (Exception ex)
{
}
}
}
Points to consider
Since the API provides an asynchronous mechanism for working with trading functions, this must be taken into account during development.
Some common mistakes when working with an asynchronous approach:
- In the strategy, a trigger to cancel an order is triggered, and the algorithm calls CancelOrder. While the response has not arrived from the exchange, the trigger fires again and the algorithm again sends the CancelOrder request to the exchange. As a result, the second request will be rejected by the exchange.
- The strategy fires a trigger to open a position, the algorithm checks CurrentPosition, which is equal to zero, and sends a market order. While the response has not come from the exchange and the value of the position has not been updated, the trigger fires again and another market order is sent, which ultimately leads to an increase in risks.
- In the strategy, a trigger to close a position is triggered, the algorithm checks CurrentPosition, creates a closing order with a volume equal to CurrentPositions, and sends this order. While the response has not come from the exchange and the value of the position has not been updated, the trigger fires again and another market order is sent, which ultimately leads not to the closing of the position, but to its reversal. It is important to understand that order statuses and positions arrive asynchronously as a response is received from the exchange.