Trade management functions and variables
Trade enter commands can receive a trade management function (TMF) as the first argument. A TMF is a function for micro managing the trade. It is repeatedly called until the trade is closed. In most cases it's used for modifying entry, stop, or profit limits in a special way, overriding the standard trailing methods. In live trading and in TICKS mode, a TMF is executed every tick and thus has access to the most recent price quote. When the market is closed and no price ticks are received, TMFs are not executed.
TMFs are also called at four special events in the lifetime of a trade: Right before entering or exiting due to Entry, Stop, or TakeProfit, and right after being closed. Which event it is can be checked in the TMF with the boolean expressions TradeIsEntry, TradeIsStop, TradeIsProfit, TradeIsClosed (described below).
A TMF has the type int and should normally return 0; other return values have a special meaning. !! When using a TMF,
make sure the function has a return statement with the correct value!
TMF return values:
0 - check the trade's Entry, Stop, TakeProfit, and Trail parameters, and exit or enter accordingly.
1 - if the trade is open or pending, exit or cancel it now.
If the exit order was unfilled due to an OrderLimit, repeat the
order after the given OrderDelay.
2 -
if the trade is pending, enter it now. If the entry order was unfilled due to an
OrderLimit, repeat the order after the given
OrderDelay.
4 - Don't use Entry, Stop, or TakeProfit for automatically entering or exiting. Exit or enter only when the TMF returns 1 or 2.
8 - call the TMF only once per bar, just before the run function call.
16 - call the TMF only at events (entering or exiting due to Entry, Stop, or TakeProfit, and after the trade was closed).
The return values can be combined by addition. For instance, return value 28 (= 4+8+16) executes the TMF only once per bar or when Entry, Stop, or TakeProfit was hit, and does not automatically enter or exit in that case.
A a list of up to 8 var variables can be passed as parameters to the TMF, f.i. enterLong(MyTMF, parameter1, parameter2...). They can appear in the argument list of the TMF definition and keep their values during the lifetime of the trade.
TMFs and trade loops have access to the following trade specific variables (prices are Ask prices):
TradePriceOpen
The ask price at which the trade was opened, or the premium per unit for options or futures. If the trade was not yet opened, it's the current ask price of the asset or contract.
This is not the fill price, which would be ask or bid depending on trade
direction.
TradePriceClose
The ask price at which the trade was closed or the option or future was sold or covered. If the trade is still open, it's the current price of the asset or contract.
If an option was exercised or expired in the money, this variable contains the underlying ask price at expiration. If
expired out of the money, this variable is 0.
TradeSpread
The ask-bid spread at the trade opening time for short trades, or at the trade
closing time for long trades.
If an option expired out of the money, this variable is 0.
TradeStrike
The strike price of the traded option (if any).
TradeUnderlying
The underlying price of the traded option (if any).
TradeRoll
The current accumulated rollover of the trade, negative or positive. Can be
modified by the TMF for adapting rollover to the formula actually used by the
broker. Otherwise, it is calculated by multiplying the trade duration with the
RollLong/RollShort value.
Trades that last shorter than 12 hours get no rollover. If the broker API
provides current rollover/swap values for open trades, TradeRoll
is read from the broker API.
TradeMarginCost
The margin cost of the trade per underlying unit, set up at entry from
MarginCost.
Can be modified by the TMF for complex margin calculations.TradeCommission
The commission cost of the trade per underlying unit, set up at entry from
Commission.
Can be modified by the TMF for using different commissions on entry and exit, or
for other complex commission calculations.TradeProfit
The current profit or loss of the trade in units of the account currency, including costs such as spread, rollover, slippage, and commission.
With no trade costs and no spread, the current profit of a trade is (TradePriceClose-TradePriceOpen)*TradeUnits.
The volume-neutral profit of the trade in pips is TradeProfit/TradeUnits/PIP. On NFA compliant accounts the profit is
estimated, as there is no profit assigned to a single trade. For options, TradeProfit is determined by the difference of premium and current contract price. If the option is expired or was exercised, TradeProfit is determined by the extrinsic value, i.e. the difference of strike and underlying price minus the premium.
TradeUnits
Conversion factor from price change to win/loss in account currency units; normally TradeLots*PIPCost/PIP for assets, or TradeLots*Multiplier for options or futures. Examples see below. The price move equivalent to a certain profit (not considering spread and commission) is Profit/TradeUnits.
TradeDate
The time in Windows Date format when the trade was entered (for pending trades) or opened (for open trades).TradeMFE
Maximum favorable excursion, the maximum price movement in favorable direction of the trade.
Only valid after the trade was opened.
TradeMFE*TradeUnits is the highest profit of the trade in account currency units while it was open (without trading costs).
TradeMAE
Maximum adverse excursion, the maximum price movement in adverse direction of the trade.
Only valid after the trade was opened.
TradeMAE*TradeUnits is the highest loss of the trade in account currency units while it was open (without trading costs).
TradeEntryLimit
Entry limit; initially calculated from Entry. The trade
will be opened when the price reaches this value. Can be modified by the TMF by
setting it to the desired price (not to a distance!).
TradeStopLimit
Stop limit, initially calculated from Stop; only valid
when the trade is open. The trade will be closed when the price reaches this
value. Can be modified by the TMF by setting it to the desired price (not to a
distance!).
TradeStopDiff
Difference of the initial price to the initial stop limit; negative for long trades and positive for short trades. Initially calculated from Stop and only valid when the trade is open. When TradeStopLimit was moved by trailing, the original stop position can be retrieved through TradePriceOpen+TradeStopDiff.
TradeProfitLimit
Profit limit, initially calculated from TakeProfit; only
valid when the trade is open. The trade will be closed when the price reaches
this value. Can be modified by the TMF by setting it to the desired price (not
to a distance!).
TradeTrailLimit
Trail limit, initially calculated from Trail; only valid when the trade is open and a stop limit was set. The stop limit will be moved when the price reaches this value. Can be modified by the
TMF by setting it to the desired price (not to a distance!).
TradeTrailSlope
Trail slope factor in the range 0..1; only valid when the price is over the Trail limit, and a Stop limit was set. Can be modified by the trade function for changing the trail slope f.i. after breakeven.
TradeTrailStep
Trail step factor in the range 0..1; only valid when the price is over the Trail limit, and a Stop limit was set. Can be modified by the trade function for changing the trail step f.i. after breakeven.
TradeTrailLock
Trail lock factor in the range 0..1; only valid when the price is over the Trail limit, and a Stop limit was set. Can be modified by the trade function for changing the trail lock f.i. after breakeven.
Type:
float, read/only if not mentioned otherwise. Convert them to var when using them in print/printf statements!
TradeVar[0] .. TradeVar[7]
8 general purpose var variables (default = 0). They are stored in the TRADE struct and can be used when a trade specific value must be preserved between trade function runs. They can be used and modified by the TMF. When they are used, it's recommended to define meaningful names for them, f.i. #define MyLimit TradeVar[0] etc. Without a trade, i.e. outside a TMF or trade enumeration loop, those variables have no meaning.
Type:
var
TradeLots
Number of Lots.
If the trade was partially closed or partially filled, the number of still open
or already executed lots.
TradeExitTime
Trade exit time in bars (the life time plus 1), or 0 for no time limit.
TradeBars
The number of bars since the trade was entered (for pending trades) or opened (for open trades).
TradeBarOpen
Number of the opening bar of the trade. For pending trades, the number of the bar at which the trade was entered. Can be set to the current bar number (Bar) for resetting the wait time of pending trades. After the trade is opened, this number must not be changed anymore.
TradeBarClose
Number of the closing bar of the trade, or 0 if the trade is still open.
TradeContract
The contract type for options and futures, a combination of PUT, CALL, EUROPEAN, BINARY, or FUTURE.
TradeID
Trade identifier number, identical to the ticket number in the broker platform, or 0 when the trade was not yet opened.
Type:
int, read/only
TradeIsShort
Boolean expression. Is true when the trade was entered with enterShort.
TradeIsLong
Is true when the trade was entered with enterLong.
TradeIsContract
Is true when the trade is an option or future contract.
TradeIsCall
Is true when the trade is a call option.
TradeIsPut
Is true when the trade is a put option.
TradeIsPhantom
Is true when the trade was entered in phantom mode for virtual hedging or for equity curve trading.
TradeIsPool
Is true for a pool trade for virtual hedging.
TradeIsVirtual
Is true for a phantom trade for virtual hedging.
TradeIsPending
Is true when the trade was not yet opened, f.i. because it was just entered or its Entry limit was not yet met.
TradeIsMissed
Is true in a TMF when the enter or exit order was unsuccessful
due to an OrderLimit. Can be used for an adaptive
enter/exit algorithm that adapts the limit to the market price (see example).TradeIsUnfilled
Is true when a GTC trade was opened with the broker, and is not yet
completely filled.
TradeIsOpen
Is true when the trade was opened and is not yet closed.
TradeIsClosed
Is true when the trade was closed.
The TradeProfit variable contains the final result of the trade.TradeIsExpired
Is true when the contract of the
trade was expired.TradeIsNewBar
Is true in a TMF at the first tick of a new bar.
TradeIsEntry
Is true in a TMF when the position is about to be opened because its Entry limit was just hit.
TradeIsStop
Is true in a TMF when the the position is about to be closed because its Stop limit was just hit.
TradeIsProfit
Is true in a TMF when the position is about to be closed because its TakeProfit limit was just hit.
Type:
bool, read/only
TradeAlgo
The algorithm identifier of the trade. Also set to Algo during a TMF.
TradeAsset
The asset name of the trade. Also set to Asset during a TMF or a trade loop.
Type:
string, read/only
ThisTrade
The TRADE* pointer.
All trade information can be accessed through this pointer. The TRADE struct is defined in include\trading.h. Its members are the above trade variables, redefined to easier-to-memorize names in include\variables.h.
Remarks:
- All trade variables listed above are only valid inside a TMF or a in trade enumeration loop. Otherwise they require ThisTrade to be set to a valid TRADE* pointer by script. This switches all trade variables to that trade.
!! If set from enterLong/Short, check ThisTrade
for nozero before accessing a trade variable! Any access to a trade variable
will crash when ThisTrade is 0.
- Asset specific variables, such as PIP, PIPCost etc. are automatically set to the trade asset during a TMF or a trade enumeration loop, unless you explicitely prevent this by switching to a different asset. For using algorithm specific variables in a TMF, such as trade statistics or AlgoVar, the algo function must be called in the TMF (see example).
- !! Most trade variables are of type float. They are normally automatically converted to var in lite-C, exept for functions that have no fixed variable type such as printf(). For
directly printing trade variables, place a (var) before them in the printf parameter list to convert them to var.
- !! Make sure that all TMFs
return a value. Ending the TMF function without a return value can cause
wrong or random trading behavior.
- The TICKS flag is often required for testing TMFs that use intrabar prices or enter / exit trades.
- TMFs can open new trades with enterLong/Short. However be careful when assigning them the same TMF: uncorrect entry conditions can then lead to an endless loop of entering new trades.
- Entering and exiting trades by returning 1 or 2 is attempted even during the weekend or holidays when price quotes arrive and
Weekend is at 2 or below.
- Exit a trade by returning 1, rather than calling
exitTrade.
- For tasks that are not related to a certain trade, using a
tick function is preferable to a TMF.
- Functions that affect the program flow - like loop,
optimize, etc. - can not be called in a TMF.
- Data series cannot be created in a TMF, and indicators that create data series can not be called;
but series and indicator values can be evaluated through global variables or
asset/algo specific variables.
Static series can be shifted in a TMF using the shift
function.
- The current candle is incomplete within a TMF, so its range and height
normally deviates from the other candles. The price functions return different values because they get their open, high, and low prices from the incomplete candle.
// TMF for adaptive entry / exit by moving OrderLimit every 30 seconds
int AdaptLimit()
{
if(TradeIsMissed) {
var Step = max(0.2*Spread,PIP/2);
OrderDelay = 30; // try again in 30 seconds
if(!TradeIsOpen) { // entry limit
if(TradeIsLong) {
if(OrderLimit > TradePriceOpen)
return 1; // cancel trade
OrderLimit += Step; // adapt limit
} else { // short
if(OrderLimit < TradePriceOpen-Spread)
return 1;
OrderLimit -= Step;
}
OrderLimit = roundto(OrderLimit,PIP/2);
return 2+16; // trigger tmf at next event
} else { // exit limit
if(TradeIsLong)
OrderLimit -= Step;
else
OrderLimit += Step;
OrderLimit = roundto(OrderLimit,PIP/2);
return 1+16; // trigger tmf at next event
}
}
return 16; // trigger tmf at next event
}
// TMF that moves the stop level in a special way
int TrailingStopLong()
{
// adjust the stop only when the trade is in profit.
if(TradeIsOpen and TradeProfit > 0)
// place the stop at the lowest bottom of the last 3 candles
TradeStopLimit = max(TradeStopLimit,LL(3));
// plot a line to make the stop visible in the chart
plot("Stop",TradeStopLimit,MINV,BLACK);
// return 0 to let Zorro check the stop/profit limits
return 0;
}
function run()
{
set(TICKS); // normally needed for TMF
...
enterLong(TrailingStopLong);
}
// print profit of every trade
...
for(open_trades)
printf("\n%s profit %.2f",Asset,(var)TradeProfit);
...
// TMF that opens an opposite trade when stopped out,
// and opens a new trade when profit target is reached (Zorro 1.22 and above)
int ReverseAtStop()
{
if(TradeIsStop) { // stop loss hit?
if(TradeIsShort)
enterLong(ReverseAtStop); // enter opposite trade
else
enterShort(ReverseAtStop);
}
if(TradeIsProfit) { // profit target hit?
if(TradeIsShort)
enterShort(ReverseAtStop); // enter same trade again
else
enterLong(ReverseAtStop);
}
// call the TMF at stop loss / profit target only
return 16;
}
function run()
{
set(TICKS); // normally needed for TMF
Weekend = 3; // don't run TMF at weekend
Stop = 100*PIP;
TakeProfit = 100*PIP;
if(Bar == LookBack) // enter the first trade directly at the first bar
enterLong(ReverseAtStop);
}
// TMF with parameters, for a Chandelier Stop
int Chandelier(var TimePeriod,var Multiplier)
{
if(TradeIsLong)
TradeStopLimit = max(TradeStopLimit,ChandelierLong(TimePeriod,Multiplier));
else
TradeStopLimit = min(TradeStopLimit,ChandelierShort(TimePeriod,Multiplier));
return 8; // only update once per bar
}
function run()
{
...
if(LongSignal) {
Stop = ChandelierLong(22,3);
enterLong(Chandelier,22,3);
}
...
}
See also:
trade statistics, enterLong/Short,
Stop, LifeTime, AlgoVar, tick(),
for(trades), user supplied functions
► latest version online