Skip to main content

Percentage and Tick Prices

NinjaTrader commands only accept floating-point price levels. But as traders, it's often easier to define our trade logic in percentages, ticks, points, or dollars as relative values to the underlying price.

There are 6 fields where a price can be explicitly set in a CrossTrade alert message:

TAKE_PROFIT, LIMIT_PRICE, STOP_PRICE, STOP_LOSS, STOP_LOSS_LIMIT, STOP_LOSS_STOP

We've added functionality to define any of the above variables in terms of %, ticks-value, point-value, or dollar-value from the underlying price.

warning

It is important to note that %, tick, point, and dollar values are translated to a price level and not, for instance, have anything to do with the value of position.

On Tradovate

Relative price values require a fresh quote because Tradovate's trading API has no quote endpoint. With destination=tradovate;, CrossTrade's own server-side pricing is the only source used to resolve take_profit, stop_loss, limit_price, and stop_price to absolute tick-rounded prices. Tradovate market-data entitlement, one user's Add-On cache, and direct GetQuote are never fallbacks. The order fails closed when fresh pricing isn't available. For a continuous symbol such as ES1!, CrossTrade must identify a concrete contract to translate and pin on the order.

How to define price levels

Typically, a price level is defined as a floating-point number, e.g., 5349.25. You can also define a price level relative to the underlying price, like so:

take_profit=5%;
stop_loss=25 ticks;
limit_price=-2.5%;
stop_price=12 ticks;

For take_profit and the stop_loss* fields, positive relative values are protective magnitudes and CrossTrade derives their direction from action. For a buy, a positive take profit resolves above the entry reference and a positive stop loss resolves below it. For a sell, those directions are reversed. Use positive magnitudes for action-aware TP/SL placement. The entry reference is the submitted limit_price or stop_price when the entry order carries one, the live quote for market entries, and on NinjaTrader the actual fill price for deferred brackets: see Which price the offset is measured from.

Entry offsets remain explicitly signed. For limit_price and stop_price, a positive value is above the quote and a negative value is below it, regardless of action. For example, a buy limit 10 ticks below the market is limit_price=-10 ticks;.

You can also use the point-value or dollar-value of a move in the underlying, like so:

take_profit=15 points;
stop_loss=250 dollars;
limit_price=2.5%;
stop_price=12 ticks;

Price Formatting

Percentages

Any of the following representations of % are valid:

5%;
5 %;
5.2%;
5.5236 %;

Ticks

Any of the following representations of tick(s) are valid:

1 tick;
1 ticks;
1tick;
1ticks;
12tick;
12 ticks;
7.5 ticks;
etc.

Points

Any of the following representations of point(s) are valid:

1 point;
1 points;
1point;
1points;
12 pts;
-12pts;
12 pt;
12pt;
7.5 points;
etc.

Dollars

Any of the following representations of $ are valid:

$1;
$1.00;
$ 1;
-$500;
- $500
$ 500.00;
$1,000;
$1,000.50;
etc.
warning

For an immediate entry, dollar offsets use the current quote as their pricing pivot. When NinjaTrader defers a relative TP/SL bracket for a working limit or stop entry, the final bracket is calculated from the actual fill price instead. Tradovate converts the offset before placement and submits the resulting absolute price in its server-side order structure: for a limit or stop entry the offset is measured from your submitted entry price, and for a market entry it is measured from the current quote.

How it works

Broker orders require absolute prices, so a percentage, tick, point, or dollar value must be translated into the underlying's price. When a relative price field is presented:

  1. CrossTrade obtains a fresh quote. NinjaTrader orders use your Add-On's data feed; Tradovate orders are priced by CrossTrade server-side from live market data.
  2. The reference price for that field (see Which price the offset is measured from) and the instrument's tick size define the price level that represents that value.
  3. The price field is swapped with the real value. CrossTrade will calculate the actual price level, rounded to the nearest tick.
  4. CrossTrade sends the final absolute price to the selected broker destination.

Entry offsets (limit_price, stop_price) are interpreted relative to the last price of the most recent quote: +10% is ten percent above the underlying price, and -10 ticks is ten ticks below it. TP/SL offsets are oriented from action so positive magnitudes remain protective for both buys and sells, and they measure from your expected entry price: the submitted (or just-resolved) limit_price or stop_price when the entry order carries one, or the same live quote for market entries. A resting limit entry placed away from the market keeps exactly the bracket distances you asked for.

If the instrument cannot be quoted, the quote is stale or untrusted, or a Tradovate continuous contract cannot be pinned to the quoted expiry, the alert errors out without placing the order.

Which price the offset is measured from

The reference price depends on the field, the entry type, and the destination:

Offset onNinjaTrader destinationTradovate destination
limit_price / stop_price (entry)Live quote (your Add-On's data feed)Live quote (CrossTrade's server-side pricing)
take_profit / stop_loss* with a market entryLive quote; the bracket is submitted alongside the entryLive quote; converted to absolute prices before placement
take_profit / stop_loss* with a limit or stop entryActual fill price. The Add-On holds the bracket until the entry fills (wait-for-fill), then measures the offsets from the fillSubmitted entry price (limit_price for limit entries, stop_price for stop entries). The absolute prices are fixed at placement and are not recalculated from the fill
take_profit / stop_loss with cancelandbracketLive quote at command time (the position already exists)Live quote at command time (the position already exists)
atm_targets / atm_stops (Tradovate ATM)n/aActual fill price. Tradovate's native order strategy applies the offsets to the fill

The practical difference shows on a limit or stop entry: NinjaTrader re-measures the bracket from the price you actually got, so a better-than-limit fill shifts the whole bracket with it. Tradovate fixes the bracket prices when the order is submitted, keeping exactly the distances you asked for around your submitted entry price, even if the fill improves on it. If you want fill-measured bracket distances on Tradovate, use the atm_* fields instead of take_profit / stop_loss.

danger

Misspellings may not be caught by CrossTrade filters. If this happens, the value will be passed through unaffected. NT8 does not throw an error for non-numeric prices, e.g., 10 tic, and may result in unexpected behavior.

Example Payloads

The following command will set an OCO bracket order to take profit at 2.5% above the underlying price and stop loss at 5% below the underlying price:

key=your-secret-key;
command=place;
account=sim101;
instrument=ES 09-26;
action=buy;
qty=1;
order_type=market;
tif=day;
take_profit=2.5%;
stop_loss=5%;

Similarly, we can set a buy limit order at 10 ticks below the current price. Entry offsets remain signed, so this value is negative:

key=your-secret-key;
command=place;
account=sim101;
instrument=ES 09-26;
action=buy;
qty=1;
order_type=limit;
tif=day;
limit_price=-10 ticks;

This example illustrates using a $-based approach instead of ticks:

key=your-secret-key;
command=place;
account=sim101;
instrument=ES 09-26;
action=buy;
qty=1;
order_type=market;
tif=day;
take_profit=$1000;
stop_loss=$500;