Limit Order Management
Eight fields that turn a simple limit order into something more dynamic: chase the touch as price moves, reposition a pending limit, fall back to market if the chase budget runs out, exit a position with a limit instead of a market.
- Chase logic:
chaseLimitOrder: truere-prices the order at the moving best touch until it fills, the chase budget runs out, or the order is cancelled. - Default chase budget: up to 180 attempts × 20 s ≈ 1 hour. Tune the cadence with
updateLimitOrderTimeInterval. - Reposition to touch:
updateCurrentLimitOrder: truesnaps the limit order nearest to market over to the current best bid/ask. It ignorespriceand is wired on KuCoin, Coinbase, and Hyperliquid only. - Limit close:
useLimitClose: trueis the only way to exit a position via limit. Without it, anorderType=closepayload is forced to market by TVH's auto-mapping.
limitClosePercent accepts placeholders. Other limit-management fields are flags and integers — not placeholder-compatible.
Quick reference table
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
limitPriceType | string | no | fixedPrice | How TVH derives the limit price. fixedPrice = use price verbatim. bestPrice = pin to the current best bid (buys) or best ask (sells) at submission time. |
useLimitClose | bool | no | false | When set together with a close command, exit the position using a limit order (price from price or chase logic) instead of a market order. |
limitClosePercent | decimal | no | 0 | Offset (percent from current price) for the limit-close order. Positive value pushes the close price into profit territory. |
cancelLimitOrderOffset | int | no | 0 | Delay in seconds after which TVH auto-cancels the still-pending entry/DCA limit orders on the pair. Only runs with isLimit=true and a value greater than 0. TP/SL orders are untouched. Capped at 604800 s (7 days). |
updateCurrentLimitOrder | bool | no | false | Reposition the open limit order nearest to market (not the most recent one) to the current best bid/ask. Cancels and re-places it, keeping size and leverage. Ignores price — it can only snap to the touch. |
chaseLimitOrder | bool | no | false | Re-place the limit order at the moving best price until it fills, expires, or the chase budget runs out. Default budget: 180 attempts × 20 s = 1 hour. |
updateLimitOrderBuyMarketAfterNotFilled | bool | no | false | Fallback to market order once the chase budget is exhausted. Otherwise the order is simply cancelled. |
updateLimitOrderTimeInterval | int | no | 20 | Seconds to wait between chase attempts. Default 20 s; the chase runs for up to 180 attempts (~1 hour budget). |
Chase logic
The chase loop turns a static limit order into an aggressive maker entry: place at the touch, watch the touch move, cancel-and-replace, repeat. The order stays maker-only the whole time.
Minimal chase payload
{
"exchange": "bybit",
"pair": "BTCUSDT",
"apiKey": "bybit-main",
"isBuy": true,
"isLimit": true,
"limitPriceType": "bestPrice",
"units": 0.05,
"chaseLimitOrder": true,
"token": "<token>"
}
limitPriceType: "bestPrice"tells TVH to ignore thepricefield and use the current best touch (best bid for buys, best ask for sells).chaseLimitOrder: trueactivates the loop.- Default budget kicks in: 180 attempts × 20 s.
Chase with fallback to market
{
"chaseLimitOrder": true,
"limitPriceType": "bestPrice",
"updateLimitOrderTimeInterval": 10,
"updateLimitOrderBuyMarketAfterNotFilled": true
}
A 10-second cadence shortens each retry window. If the order still hasn't filled by the end of the chase budget, fall back to a market order. Useful when "get in soon or take what you can get" matters more than fee tier.
Without updateLimitOrderBuyMarketAfterNotFilled, the chase just gives up and cancels the pending limit at the end of the budget — the trade is lost.
Why postOnly and chaseLimitOrder work together
Chase needs postOnly: true (the default) to stay maker-side. If your limit price would cross the spread between the chase-loop's "check" and "replace" cycles, postOnly rejects the offending placement and TVH re-prices on the next iteration. The whole loop stays on the maker side.
If you disable postOnly, the chase can accidentally take liquidity on a fast move — defeating the purpose. Keep postOnly: true for chase setups.
Tuning the interval
The attempt budget stays at 180; the interval sets how long the whole chase runs:
| Interval | Total chase time | Rate-limit risk |
|---|---|---|
| 1 s | 180 × 1s = 3 min | High — most exchanges rate-limit cancel/replace at this rate |
| 5 s | 180 × 5s = 15 min | Moderate |
| 10 s | 180 × 10s = 30 min | Low |
| 20 s | 180 × 20s = 1 h (default) | Very low |
| 60 s | 180 × 60s = 3 h | Negligible |
| 300 s | 180 × 300s = 15 h | Negligible |
An interval below ~5 s dramatically raises the risk of hitting exchange rate limits. An exchange-side ban makes all subsequent trades on that API key fail until the cooldown lifts. Recommended range: 10-30 seconds for active strategies.
limitPriceType — where the limit price comes from
Only two values are part of the supported contract:
| Value | Behaviour |
|---|---|
"fixedPrice" (default) | Use the price field verbatim. |
"bestPrice" | Pin to the current touch — best bid for buys, best ask for sells — at submission time. price is ignored. |
Only fixedPrice and bestPrice are supported. Unknown strings happen to behave like bestPrice today, but don't rely on that: stick to the two documented values.
Use bestPrice for chase setups; use fixedPrice to "snipe at this exact level".
Reposition a pending limit to the touch
updateCurrentLimitOrder: true is a one-shot instruction that moves an open limit order back onto the current best price. It does not place a new order.
{
"exchange": "kucoin-futures",
"pair": "BTCUSDT",
"apiKey": "kucoin-futures-main",
"updateCurrentLimitOrder": true,
"isBuy": true,
"token": "<token>"
}
What it actually does:
- Finds the open limit order nearest to the market on that side — for a buy, the highest-priced (most aggressive) bid; for a sell, the lowest ask. Not the most recently placed order.
- Cancels it and re-places it at the current best bid (buys) / best ask (sells), preserving the original quantity and leverage.
- Ignores the
pricefield. This flag can only snap to the touch, it cannot move an order to an arbitrary level. To set a specific price, cancel and re-submit a new limit instead.
updateCurrentLimitOrder is wired only on the newer adapters: KuCoin (Futures + Spot), Coinbase (Futures + Spot), and Hyperliquid. On Binance, Binance Futures, Bybit, OKX, and BitMEX it is a no-op. For those, use chaseLimitOrder to keep an order pinned to the touch automatically.
Use case: a follow-up alert that nudges an unfilled maker entry back to the front of the book, without re-sending the full command.
Limit close — exit via limit instead of market
Without useLimitClose, an orderType: "close" payload is forced to market by TVH's auto-mapping. To exit with a limit:
{
"exchange": "binance-futures",
"pair": "BTCUSDT",
"apiKey": "binance-futures-main",
"isClose": true,
"useLimitClose": true,
"isLimit": true,
"price": 65500,
"token": "<token>"
}
The position closes at limit price 65500 if the market hits it. Until then, the position stays open with no SL/TP follow-up — that's your responsibility.
Limit close with chase
Combine with chase for an aggressive maker exit:
{
"isClose": true,
"useLimitClose": true,
"limitPriceType": "bestPrice",
"chaseLimitOrder": true,
"updateLimitOrderBuyMarketAfterNotFilled": true,
"updateLimitOrderTimeInterval": 10
}
Chase the close at the best touch (TVH picks the appropriate side based on the position direction) on a 10-second cadence, then fall back to market if no fill by the end of the budget. Earns the maker rebate when it lands.