Gross Exposure Flattener

What it does
Reduces a fixed matched slice from both long and short when total gross exposure is high, balanced enough, and already profitable.

Why this exists

In hedge mode, long and short positions are independent. A healthy pair can grow both sides at the same time, which increases gross exposure even when net exposure stays small.
The flattener trims that matched exposure without trying to rebalance the pair. It places one reduce-only order on the long side and one reduce-only order on the short side, using the same base quantity for both sides.
For all config fields, see Config Reference.

How it works

The check runs from the short-mode grid after normal exposure evaluation.
CheckPasses when
Gross exposurelongUsd + shortUsd is at or above maxGrossPositionUsd * triggerGrossPct
Balanceabs(longUsd - shortUsd) / grossUsd is at or below maxNetToGrossPct
PnLCombined unrealised PnL meets minCombinedUnrealisedPnlUsd
Slice PnLEstimated PnL for the fixed slice meets minEstimatedFlattenPnlUsd
Minimum positionThe slice would leave both sides above the reserve quantity
Confirmation countconsecutiveTriggers qualifying checks have happened in a row
CooldownNo flatten attempt started for this symbol during cooldownMinutes
Profit LockProfit Lock is not controlling the symbol
When all checks pass:
  1. The bot pauses that symbol.
  2. It cancels all open orders for the symbol.
  3. It refreshes positions and rebuilds the fixed slice plan.
  4. It reduces the larger-notional side first.
  5. If the first leg lands exactly on target, it reduces the other side by the same quantity.
  6. It refreshes positions, clears stale rebalancer state after a position change, and restarts the symbol.
If the initial cancel-all step fails, the bot aborts before placing reduce orders and logs an error. If the first reduce leg does not reach its exact target, the second leg is not placed.

Fixed slice behavior

flattenUsdPerSide is a USD value, not a target gross exposure.
Example: flattenUsdPerSide = 1000 and mark price is $2. The bot computes a base quantity of 500, rounds it down to the exchange qtyStep, then tries to reduce 500 base units from the long position and 500 base units from the short position.
The slice is not shrunk to fit a small side. If the configured slice would fully close a side or breach minPositionQty, the attempt is skipped.

Configuration placement

You can place the block globally under defaults:
"defaults": {
  "flattener": {
    "enabled": false,
    "triggerGrossPct": 0.5,
    "flattenUsdPerSide": 1000,
    "maxNetToGrossPct": 0.25,
    "minCombinedUnrealisedPnlUsd": 25,
    "minEstimatedFlattenPnlUsd": 5,
    "consecutiveTriggers": 2,
    "cooldownMinutes": 15
  }
}
The feature stays off until you set enabled to true. Only enabled short-mode rows can trigger it. Long-mode rows can inherit the block from defaults, but they do not evaluate it.
Pair-level opt-in works too:
"pairs": {
  "HYPEUSDT": [
    { "enabled": true, "mode": "long" },
    {
      "enabled": true,
      "mode": "short",
      "flattener": { "enabled": true, "flattenUsdPerSide": 500 }
    }
  ]
}

Interaction with other features

FeatureInteraction
Exposure GuardSupplies the exposure evaluation points that can trigger checks.
Profit LockSkips while Profit Lock controls the symbol.
RebalancerCleared after a position-changing flatten so the restarted grid uses fresh baselines.
Short Inventory RefillIndependent trigger path. Both use the same symbol lock, so they do not mutate the same symbol at the same time.
Short Size GuardMay change future short order size after the symbol resumes.
Hedge ThrottleMay widen future short spacing after the symbol resumes.

Tuning tips

If you want...Adjust this
Earlier checksLower triggerGrossPct or lower maxGrossPositionUsd carefully
Smaller trimsLower flattenUsdPerSide
More balanced trimsLower maxNetToGrossPct
More profit confirmationRaise minCombinedUnrealisedPnlUsd or minEstimatedFlattenPnlUsd
Fewer attemptsRaise consecutiveTriggers or cooldownMinutes

Troubleshooting

SymptomLikely cause
Feature never triggersGross exposure is below threshold, PnL is too low, net-to-gross is too high, cooldown is active, Profit Lock is active, or enabled: false at the effective scope
It skips near a tiny positionThe fixed slice would breach the reserve quantity or fully close a side
Only one reduce order happensThe first reduce leg did not reach its exact target, so the second leg was not placed
Cancel failure stops the attemptInitial cancel-all failure is treated as a hard abort before reduce orders
No effect after a config editSave the config, then restart the bot so it runs with the new settings