- Code: Select all
function closeall(account, instrument, sell)
local enum, row, valuemap, side, closed;
local offer;
local valuemap;
local CanClose;
-- get offer id and check whether close order can be used for the specified instrument and account.
offer = core.host:findTable("offers"):find("Instrument", instrument).OfferID;
CanClose = core.host:execute("getTradingProperty", "canCreateMarketClose", instrument, account);
-- just prepare the name of the direction ("S" for sell and "B" for buy).
if sell then
side = "S";
else
side = "B";
end
-- the flag indicating whether at least one position is closed.
closed = false;
-- get a enumerator for the "open trades" trading table
enum = core.host:findTable("trades"):enumerator();
-- and scan trough all table rows. one row is one trade.
while true do
row = enum:next();
if row == nil then
break;
end
-- if trade was placed for chosen account and instrument
-- and the trade is in the requested side - close it
if row.AccountID == account and
row.OfferID == offer and
row.BS == side then
-- use different close models depending on the account type
if CanClose then
-- non-NFA accounts, can use Market Close order
valuemap = core.valuemap();
valuemap.Command = "CreateOrder";
valuemap.OrderType = "CM"; -- close market order
valuemap.OfferID = OfferID;
valuemap.AcctID = Account;
valuemap.Quantity = row.Lot; -- the size is required because we can close the position partially
valuemap.TradeID = row.TradeID; -- the trade must be referenced int he close order
-- the side of the close order must be opposite to the side of the trade.
if row.BS == "B" then
valuemap.BuySell = "S";
else
valuemap.BuySell = "B";
end
-- and execute
local success, msg;
success, msg = terminal:execute(200, valuemap);
assert(success, msg);
else
-- NFA accounts. We cannot call close orders but can
-- execute an opposite open order. Since NFA accounts can
-- never be hedging accounts, the opposite open order
-- closes the existing positions first.
valuemap = core.valuemap();
valuemap.OrderType = "OM";
valuemap.Command = "CreateOrder";
valuemap.OfferID = OfferID;
valuemap.AcctID = Account;
valuemap.Quantity = row.Lot;
if row.BS == "B" then
valuemap.BuySell = "S";
else
valuemap.BuySell = "B";
end
local success, msg;
success, msg = terminal:execute(200, valuemap);
assert(success, msg);
end
-- we closed the position, so we should not open anything.
closed = true;
end
end
return closed;
end
The function enumerates all the trades and closes those of them which are opened in the specified direction for the specified account and the specified side (buy or sell).
This function has a number of lacks in case many trades must be closed:
a) In fact, the trades table is not refreshed exactly in the same moment when the trade is closed on the server. The update takes 250ms-1sec. Therefore, there is a chance that the function will try to close a trade which is already closed on the server. In case the close orders are prohibited, and, therefore, opposite order is used, this method will open an opposite position instead of closing.
b) The trades table changes dynamically, every time when new information is received from the server, so, it can skip some trades, for example, in case some trades appears or disappears during the enumeration loop is being executed.
To avoid this feature I recommend to use netting close orders which are available on any account, including FIFO accounts. These orders closes all existing trades for the specified account and specified instrument opened in the direction opposite to the order direction.
Here is an example of using of the netting order:
- Code: Select all
function closeall(account, instrument, sell)
local enum, row, valuemap, side, closed;
local offer;
local valuemap;
local CanClose;
-- get offer id and check whether close order can be used for the specified instrument and account.
offer = core.host:findTable("offers"):find("Instrument", instrument).OfferID;
valuemap = core.valuemap();
valuemap.OrderType = "CM";
valuemap.AcctID = account;
valuemap.OfferID = offer;
valuemap.TradeID = "all";
-- set an opposite direction
if sell then
side = "B";
else
side = "S";
end
valuemap.NetQtyFlag = "Y";
success, msg = terminal:execute(300, valuemap);
if not(success) then
assert(success, msg);
end
end