mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-28 06:22:49 +08:00
feat: make exit throttle gates strategy-configurable, soften defaults
The anti-churn exit gates (min hold, noise-close window, re-entry cooldown, bypass and noise-band thresholds) were hardcoded constants in auto_trader_throttle.go — every flat-ish position was forced to hold 8h+ and changing the pacing meant a code change and redeploy. - RiskControlConfig gains 7 exit-gate fields (minutes / signed price-%), zero = built-in default; accessor methods centralize fallbacks and are hot-reloaded from the DB like the rest of the strategy config - Throttle reads the gates from the strategy; prompt hold/exit guidance is now rendered from the same values so the AI is told exactly what the code will enforce - Defaults softened: min hold 4h -> 1.5h, noise window 8h -> 3h, re-entry 3h -> 1.5h, bypasses -5/+12 -> -3/+8, noise band -4..+6 -> -2..+3 (price-basis). A +-2-3% move is 15-20x round-trip fees — no longer 'noise' worth locking - Strategy Studio gets an 'exit pacing' row (min hold / flat-close window / re-entry cooldown); thresholds editable via strategy JSON - Live strategy updated in data/data.db with the softened values
This commit is contained in:
@@ -2321,6 +2321,68 @@ export function StrategyStudioPage() {
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div className="mt-4 grid gap-4 sm:grid-cols-3">
|
||||
<label className="space-y-2">
|
||||
<span className="text-xs text-nofx-text-muted">
|
||||
{text(language, '最小持仓时间', 'Min hold')}
|
||||
</span>
|
||||
<select
|
||||
value={risk.min_hold_minutes ?? 90}
|
||||
onChange={(event) =>
|
||||
patchRisk({
|
||||
min_hold_minutes: Number(event.target.value),
|
||||
})
|
||||
}
|
||||
className="w-full rounded-lg border border-[rgba(26,24,19,0.14)] bg-nofx-bg px-3 py-2 text-sm text-nofx-text"
|
||||
>
|
||||
{[30, 60, 90, 120, 180, 240].map((value) => (
|
||||
<option key={value} value={value}>
|
||||
{value >= 60 ? `${value / 60}h` : `${value}m`}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="space-y-2">
|
||||
<span className="text-xs text-nofx-text-muted">
|
||||
{text(language, '横盘仓锁定窗口', 'Flat-close window')}
|
||||
</span>
|
||||
<select
|
||||
value={risk.noise_hold_minutes ?? 180}
|
||||
onChange={(event) =>
|
||||
patchRisk({
|
||||
noise_hold_minutes: Number(event.target.value),
|
||||
})
|
||||
}
|
||||
className="w-full rounded-lg border border-[rgba(26,24,19,0.14)] bg-nofx-bg px-3 py-2 text-sm text-nofx-text"
|
||||
>
|
||||
{[60, 120, 180, 240, 360, 480].map((value) => (
|
||||
<option key={value} value={value}>
|
||||
{`${value / 60}h`}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="space-y-2">
|
||||
<span className="text-xs text-nofx-text-muted">
|
||||
{text(language, '同币再入冷却', 'Re-entry cooldown')}
|
||||
</span>
|
||||
<select
|
||||
value={risk.reentry_cooldown_minutes ?? 90}
|
||||
onChange={(event) =>
|
||||
patchRisk({
|
||||
reentry_cooldown_minutes: Number(event.target.value),
|
||||
})
|
||||
}
|
||||
className="w-full rounded-lg border border-[rgba(26,24,19,0.14)] bg-nofx-bg px-3 py-2 text-sm text-nofx-text"
|
||||
>
|
||||
{[30, 60, 90, 120, 180].map((value) => (
|
||||
<option key={value} value={value}>
|
||||
{value >= 60 ? `${value / 60}h` : `${value}m`}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -209,4 +209,14 @@ export interface RiskControlConfig {
|
||||
min_position_size: number; // Min position size in USDT (CODE ENFORCED)
|
||||
min_risk_reward_ratio: number; // Min take_profit / stop_loss ratio (AI guided)
|
||||
min_confidence: number; // Min AI confidence to open position (AI guided)
|
||||
|
||||
// Exit throttle gates (CODE ENFORCED, 0/absent = backend defaults).
|
||||
// PnL thresholds are PRICE-move percentages (leverage-independent).
|
||||
min_hold_minutes?: number; // AI closes blocked before this unless a bypass fires
|
||||
noise_hold_minutes?: number; // flat closes inside the noise band blocked until this
|
||||
reentry_cooldown_minutes?: number; // same-symbol reopen cooldown after a close
|
||||
early_stop_bypass_pct?: number; // price loss unlocking an early close (negative)
|
||||
early_tp_bypass_pct?: number; // price profit unlocking an early close (positive)
|
||||
noise_loss_floor_pct?: number; // noise band lower edge (negative)
|
||||
noise_profit_ceiling_pct?: number; // noise band upper edge (positive)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user