67 production .py modules that the running PINK service imports but which were never committed: prod/bingx/ (HTTP client, market/user streams, journal, config), prod/clean_arch/ adapters/persistence/runtime/dita/dita_v2 production modules and their co-located tests. Rule going forward: every module imported by launch_dolphin_pink.py / pink_direct.py must appear in git ls-files. Excludes _backup dirs, __pycache__, and non-code files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
from decimal import Decimal
|
|
from decimal import ROUND_HALF_EVEN
|
|
from typing import Any
|
|
|
|
|
|
CONVICTION_MIN = 0.5
|
|
CONVICTION_MAX = 9.0
|
|
EXCHANGE_LEV_MIN = 1
|
|
EXCHANGE_LEV_MAX = 3
|
|
LEVERAGE_MAPPING_RULE = "round_half_even_linear_0.5_to_9.0_to_1_to_exchange_cap"
|
|
|
|
|
|
def _clamp_exchange_bounds(exchange_min: Any, exchange_max: Any) -> tuple[int, int]:
|
|
lower = int(Decimal(str(exchange_min)))
|
|
upper = int(Decimal(str(exchange_max)))
|
|
if lower < 1:
|
|
lower = 1
|
|
if upper < lower:
|
|
upper = lower
|
|
return lower, upper
|
|
|
|
|
|
def normalize_bingx_leverage_value(
|
|
leverage: Any,
|
|
*,
|
|
exchange_min: Any = EXCHANGE_LEV_MIN,
|
|
exchange_max: Any = EXCHANGE_LEV_MAX,
|
|
) -> int:
|
|
"""
|
|
BingX exchange leverage is integer-only and conservatively capped.
|
|
"""
|
|
lower, upper = _clamp_exchange_bounds(exchange_min, exchange_max)
|
|
desired = int(
|
|
Decimal(str(leverage)).quantize(Decimal("1"), rounding=ROUND_HALF_EVEN)
|
|
)
|
|
if desired < lower:
|
|
return lower
|
|
if desired > upper:
|
|
return upper
|
|
return desired
|
|
|
|
|
|
def map_internal_conviction_to_exchange_leverage_target(
|
|
leverage: Any,
|
|
*,
|
|
exchange_min: Any = EXCHANGE_LEV_MIN,
|
|
exchange_max: Any = EXCHANGE_LEV_MAX,
|
|
) -> float:
|
|
"""
|
|
Map engine conviction/sizing into BingX exchange leverage.
|
|
|
|
The engine retains the fractional conviction signal internally. The exchange
|
|
receives a leverage target derived from that signal.
|
|
"""
|
|
lower, upper = _clamp_exchange_bounds(exchange_min, exchange_max)
|
|
internal = float(Decimal(str(leverage)))
|
|
internal = max(CONVICTION_MIN, min(CONVICTION_MAX, internal))
|
|
return float(lower + (
|
|
(internal - CONVICTION_MIN) / (CONVICTION_MAX - CONVICTION_MIN)
|
|
) * (upper - lower))
|
|
|
|
|
|
def map_internal_conviction_to_exchange_leverage(
|
|
leverage: Any,
|
|
*,
|
|
exchange_min: Any = EXCHANGE_LEV_MIN,
|
|
exchange_max: Any = EXCHANGE_LEV_MAX,
|
|
) -> int:
|
|
"""
|
|
Backwards-compatible integer exchange leverage mapper.
|
|
"""
|
|
target = map_internal_conviction_to_exchange_leverage_target(
|
|
leverage,
|
|
exchange_min=exchange_min,
|
|
exchange_max=exchange_max,
|
|
)
|
|
return normalize_bingx_leverage_value(
|
|
target,
|
|
exchange_min=exchange_min,
|
|
exchange_max=exchange_max,
|
|
)
|