Trade management functions (TMF)

Trade enter commands can receive the name of a trade management function (TMF) as the first argument: enterLong(MyTMF, ...);. Alternatively, a user function named manage can be defined as a global TMF for all entered trades:

int manage()

A TMF is a function for micro managing the trade. It is triggered for any open or pending trade at any price tick or price change of the traded asset. In most cases it's used for modifying entry, stop, or profit limits in a special way, thus overriding the standard trailing methods. Since a TMF runs at every tick, it 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 executed at special events in the lifetime of a trade: Right before entering or exiting due to an Entry, Stop, or TakeProfit limit, 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).

If the TMF is passed to an enter command, it can receive up to 8 additional var parameters following the function name: enterLong(MyTMF, parameter1, parameter2...). They must also appear in the function's parameter list and keep their values during the lifetime of the trade. The alternative global manage function has no parameters.

A TMF has the return type int and should normally return 0; other return values have a special meaning:

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 Execute the TMF at the next bar right before the run call, instead of at the next incoming tick.
16 Execute the TMF only at the following events: right before entering due to Entry, right before exiting due to Stop or TakeProfit, and right after the trade was closed.

The return values can be combined by addition. For instance, return 28  (28 = 4+8+16) executes the TMF only at the next bar or when Entry, Stop, or TakeProfit was hit, and does not automatically enter or exit in that case.   !!  When using a TMF, make sure the function has a return statement with the correct value!
 

Trade variables

In a selected trade, the variables listed below available for evaluation and partially for modification. Trades are automatically selected in a TMF or in a trade loop. They can also be selected by setting the ThisTrade pointer, f.i. with ThisTrade = enterLong();. In this case check if ThisTrade is nonzero, since accessing a variable of a nonexisting trade will cause Error 111. Without a selected trade, i.e. outside a TMF or trade enumeration loop and with no set ThisTrade pointer, trade variables have no meaning.

TradePriceOpen

The average ask price at the time when the trade or contract was filled; or the current ask price if the position was not yet filled.

TradeFill

The average fill price, equivalent to TradePriceOpen-ifelse(TradeIsShort,TradeSpread,0).

TradePriceClose

The average ask price at the time when the position was closed or the contract was sold or covered. If the position is still open, it's the current best ask price of the asset or contract. If an option was exercised or expired, this variable contains the underlying ask price at expiration.

TradeValue

The average current value of the trade, equivalent to TradePriceClose-ifelse(TradeIsLong,TradeSpread,0).

TradeSpread

The ask-bid spread at the trade opening time for short trades, or at the current and trade closing time for long trades.

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/swap of the trade, negative or positive. Calculated by multiplying the trade duration with the trade volume and the RollLong/RollShort value. Trades that last shorter than 12 hours get no rollover. If RollLong and RollShort are both at 0, TradeRoll can be modified by the TMF for using a broker-specific swap calculation. 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 more complex margin calculations. The current allocated margin amount of the trade is TradeMarginCost * TradeLots.

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 more 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.

TradeDir

1 for a long trade and -1 for a short trade.

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 a pending trade with OrderDelay will be opened. For open trades, the time at which it was opened.

TradeExitDate

The time in Windows Date format when the trade was closed (for closed trades) or will expire (for open or pending trades). The expiry date of options or futures is ymd(TradeExitDate).

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

Current stop level, initially determined from Stop, and modified by trailing. 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 determined 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]

TradeStr[0] .. TradeStr[7]

TradeInt[0] .. TradeInt[15]

A 64-byte area in the TRADE struct for storing up to 8 trade-specific variables or strings, or up to 16 integers per trade. They can be accessed and modified by a TMF or a trade enumeration loop. The locations are shared, i.e. either TradeVar[N] or TradeStr[N] can be used, but not both with the same index N. Two subsequent TradeInt are shared with a TradeVar at half the index, f.i. TradeInt[10] and TradeInt[11] are shared with TradeVar[5]. TradeStr can only be modified with strcpy and has a maximum length of 7 characters unless extended over adjacent TradeStr variables. It is recommended to define meaningful names for the variables, like #define MyLimit TradeVar[0].

Type:

var, string, int
 

TradeLots

Number of open Lots. If the trade was partially closed or partially filled, the number of still open or filled lots. Automatically updated when the broker APIs supports individual trades.

TradeLotsTarget

Number of lots to be opened. If the trade was only partially filled, TradeLots is smaller than TradeLotsTarget. To treat an unfilled or partially filled trade as if it were completely filled, set TradeLots = TradeLotsTarget.

TradeLife

Trade life time in bars 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). Not valid for resumed trades since they have no opening bar.

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. It is not valid for resumed trades since they have no opening bar.

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, normally identical to the order ticket number in the broker platform. 0 when the trade was not yet opened, -1 when the trade is identified not with a number, but with a TradeUUID string.

Type:

int
 

TradeUUID

The trade identifier string when TradeID == -1.

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
 

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.

TradeIsAsset

Is true when the trade used the same asset that was currently selected.

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 when the enter or exit order was unsuccessful due to an OrderLimit.

TradeIsUnfilled

Is true when a GTC trade was opened and was not immediately filled. For determining the initial fill amount, compare TradeLots with TradeLotsTarget.

TradeIsOpen

Is true when the trade was opened and is not yet closed.

TradeIsClosed

Is true when the trade was completely closed. This is the last TMF execution of the trade. The TradeProfit variable contains the final result.

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 Entry limit was hit. Unless the TMF returns 4, the trade will now be opened.

TradeIsStop

Is true in a TMF when the Stop limit was hit. Unless the TMF returns 4, the trade will now be closed and the TMF will then be called a final time with TradeIsClosed.

TradeIsProfit

Is true in a TMF when the TakeProfit limit was hit. Unless the TMF returns 4, the trade will now be closed and the TMF will then be called a final time with TradeIsClosed.

Type:

bool, read/only
 

ThisTrade

The TRADE* pointer in a trade loop or TMF. All trade variables are 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. ThisTrade can be set by script (f.i. ThisTrade = enterLong();) for accessing variables of a just opened trade, but will not keep its value between run or tick functions.
 

Remarks:

Examples (see also trade loops):

// 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 for calculating the fill amount of a GTC trade from the broker position.
// No other trade with the same asset must be open.
int adaptFill()
{
  if(Live && TradeLots < TradeLotsTarget) {
    TradeLots = (int)brokerCommand(GET_POSITION,SymbolTrade);
    return 0;
  } else
    return 16;
}
// TMF that moves the stop level in a special way 
int trailStopLong()
{
// 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(trailStopLong); }
// 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 Factor)
{
  if(TradeIsLong)
TradeStopLimit = max(TradeStopLimit,ChandelierLong(TimePeriod,Factor));
else
TradeStopLimit = min(TradeStopLimit,ChandelierShort(TimePeriod,Factor));
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