Files
crypto_monitor/tests/test_trend_dca_enrich_fills.py
T
dekun 08082eb88f fix(trend): remove inferred DCA fill prices across all exchanges
Unify display on trend_leg_display_price: use recorded fills or grid triggers only; last done row avg comes from live entry, never back-solve trigger prices.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 18:10:33 +08:00

102 lines
3.8 KiB
Python

"""趋势回调运行中计划:实际成交价重算补仓表与金额盈亏比。"""
from __future__ import annotations
import json
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from strategy_snapshot_lib import attach_trend_dca_levels # noqa: E402
from strategy_trend_lib import ( # noqa: E402
calc_trend_plan_money_metrics,
trend_leg_display_price,
)
class TestTrendDcaEnrichFills(unittest.TestCase):
def _base_plan(self, **overrides):
plan = {
"direction": "long",
"stop_loss": 0.329,
"take_profit": 0.476,
"first_order_amount": 115,
"snapshot_available_usdt": 97.98,
"risk_percent": 5,
"contract_size": 1.0,
"grid_prices_json": json.dumps([0.3465, 0.343, 0.3395, 0.336, 0.3325]),
"leg_amounts_json": json.dumps([23, 23, 23, 23, 23]),
"dca_legs": 5,
"first_order_done": 1,
"legs_done": 0,
"avg_entry_price": 0.3537,
"order_amount_open": 115,
"target_order_amount": 230,
"leg_fill_prices_json": json.dumps([0.3537]),
}
plan.update(overrides)
return plan
def test_header_money_rr_not_price_rr(self):
plan = self._base_plan()
metrics = calc_trend_plan_money_metrics(plan)
self.assertAlmostEqual(metrics["risk_amount_u"], 4.899, places=2)
self.assertIsNotNone(metrics["money_rr"])
self.assertLess(metrics["money_rr"], 4.0)
def test_done_dca_uses_actual_fill_price(self):
plan = self._base_plan(
legs_done=1,
avg_entry_price=0.3512,
order_amount_open=138,
leg_fill_prices_json=json.dumps([0.3537, 0.3458]),
)
enriched = attach_trend_dca_levels(plan)
levels = enriched["dca_levels"]
self.assertEqual(len(levels), 6)
dca1 = levels[1]
self.assertEqual(dca1["status"], "done")
self.assertAlmostEqual(dca1["price"], 0.3458, places=4)
self.assertIsNotNone(dca1["avg_entry"])
self.assertIsNotNone(dca1["rr"])
dca2 = levels[2]
self.assertEqual(dca2["status"], "pending")
self.assertAlmostEqual(dca2["price"], 0.343, places=4)
def test_missing_dca_fills_use_grid_trigger_not_inferred_price(self):
"""缺补仓成交价时:触发价用计划网格,末档均价对齐头部,禁止反推离谱成交价。"""
plan = self._base_plan(
legs_done=2,
avg_entry_price=0.3507,
order_amount_open=161,
leg_fill_prices_json=json.dumps([0.3436]),
grid_prices_json=json.dumps([0.343, 0.343, 0.3395, 0.336, 0.3325]),
)
enriched = attach_trend_dca_levels(plan)
levels = enriched["dca_levels"]
dca1 = levels[1]
dca2 = levels[2]
self.assertEqual(dca1["status"], "done")
self.assertAlmostEqual(dca1["price"], 0.343, places=4)
self.assertEqual(dca2["status"], "done")
self.assertAlmostEqual(dca2["price"], 0.343, places=4)
self.assertAlmostEqual(dca2["avg_entry"], 0.3507, places=4)
self.assertLess(dca2["price"], 0.36)
def test_display_price_never_infers_from_target_avg(self):
"""四所共用:缺记录时只用网格,不因均价反推离谱触发价。"""
plan = self._base_plan(
legs_done=2,
avg_entry_price=0.3507,
leg_fill_prices_json=json.dumps([0.3436]),
grid_prices_json=json.dumps([0.343, 0.343, 0.3395, 0.336, 0.3325]),
)
self.assertAlmostEqual(trend_leg_display_price(plan, 2), 0.343, places=4)
self.assertLess(trend_leg_display_price(plan, 2), 0.36)
if __name__ == "__main__":
unittest.main()