Refactor opportunity scoring model
This commit is contained in:
@@ -128,11 +128,111 @@ class DustOverlapSpotClient(FakeSpotClient):
|
||||
|
||||
def klines(self, symbol, interval, limit):
|
||||
rows = []
|
||||
for index, close in enumerate([1.0, 1.1, 1.2, 1.3, 1.4, 1.45, 1.5][-limit:]):
|
||||
setup_curve = [
|
||||
1.4151,
|
||||
1.4858,
|
||||
1.3868,
|
||||
1.5,
|
||||
1.4009,
|
||||
1.5142,
|
||||
1.4151,
|
||||
1.5,
|
||||
1.4292,
|
||||
1.4858,
|
||||
1.4434,
|
||||
1.4717,
|
||||
1.4505,
|
||||
1.4575,
|
||||
1.4547,
|
||||
1.4604,
|
||||
1.4575,
|
||||
1.4632,
|
||||
1.4599,
|
||||
1.466,
|
||||
1.4618,
|
||||
1.4698,
|
||||
1.4745,
|
||||
1.5,
|
||||
]
|
||||
for index, close in enumerate(setup_curve[-limit:]):
|
||||
rows.append([index, close * 0.98, close * 1.01, close * 0.97, close, 100 + index * 10, index + 1, close * 100])
|
||||
return rows
|
||||
|
||||
|
||||
class OpportunityPatternSpotClient:
|
||||
def account_info(self):
|
||||
return {"balances": [{"asset": "USDT", "free": "100", "locked": "0"}]}
|
||||
|
||||
def ticker_price(self, symbols=None):
|
||||
return []
|
||||
|
||||
def ticker_stats(self, symbols=None, *, window="1d"):
|
||||
rows = {
|
||||
"SETUPUSDT": {
|
||||
"symbol": "SETUPUSDT",
|
||||
"lastPrice": "106",
|
||||
"priceChangePercent": "4",
|
||||
"quoteVolume": "10000000",
|
||||
"highPrice": "107",
|
||||
"lowPrice": "98",
|
||||
},
|
||||
"CHASEUSDT": {
|
||||
"symbol": "CHASEUSDT",
|
||||
"lastPrice": "150",
|
||||
"priceChangePercent": "18",
|
||||
"quoteVolume": "9000000",
|
||||
"highPrice": "152",
|
||||
"lowPrice": "120",
|
||||
},
|
||||
}
|
||||
if not symbols:
|
||||
return list(rows.values())
|
||||
return [rows[symbol] for symbol in symbols]
|
||||
|
||||
def exchange_info(self):
|
||||
return {
|
||||
"symbols": [
|
||||
{"symbol": "SETUPUSDT", "status": "TRADING"},
|
||||
{"symbol": "CHASEUSDT", "status": "TRADING"},
|
||||
]
|
||||
}
|
||||
|
||||
def klines(self, symbol, interval, limit):
|
||||
curves = {
|
||||
"SETUPUSDT": [
|
||||
100,
|
||||
105,
|
||||
98,
|
||||
106,
|
||||
99,
|
||||
107,
|
||||
100,
|
||||
106,
|
||||
101,
|
||||
105,
|
||||
102,
|
||||
104,
|
||||
102.5,
|
||||
103,
|
||||
102.8,
|
||||
103.2,
|
||||
103.0,
|
||||
103.4,
|
||||
103.1,
|
||||
103.6,
|
||||
103.3,
|
||||
103.8,
|
||||
104.2,
|
||||
106,
|
||||
],
|
||||
"CHASEUSDT": [120, 125, 130, 135, 140, 145, 150],
|
||||
}[symbol]
|
||||
rows = []
|
||||
for index, close in enumerate(curves[-limit:]):
|
||||
rows.append([index, close * 0.98, close * 1.01, close * 0.97, close, 100 + index * 20, index + 1, close * 100])
|
||||
return rows
|
||||
|
||||
|
||||
class OpportunityServiceTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.config = {
|
||||
@@ -177,10 +277,13 @@ class OpportunityServiceTestCase(unittest.TestCase):
|
||||
def test_scan_is_deterministic(self):
|
||||
with patch.object(opportunity_service, "audit_event", return_value=None):
|
||||
payload = opportunity_service.scan_opportunities(
|
||||
self.config | {"opportunity": self.config["opportunity"] | {"top_n": 2}}, spot_client=FakeSpotClient()
|
||||
self.config | {"opportunity": self.config["opportunity"] | {"top_n": 2}},
|
||||
spot_client=OpportunityPatternSpotClient(),
|
||||
)
|
||||
self.assertEqual([item["symbol"] for item in payload["recommendations"]], ["SOLUSDT", "BTCUSDT"])
|
||||
self.assertEqual([item["action"] for item in payload["recommendations"]], ["enter", "enter"])
|
||||
self.assertEqual([item["symbol"] for item in payload["recommendations"]], ["SETUPUSDT", "CHASEUSDT"])
|
||||
self.assertEqual([item["action"] for item in payload["recommendations"]], ["trigger", "chase"])
|
||||
self.assertGreater(payload["recommendations"][0]["metrics"]["setup_score"], 0.6)
|
||||
self.assertGreater(payload["recommendations"][1]["metrics"]["extension_penalty"], 1.0)
|
||||
|
||||
def test_scan_respects_ignore_dust_for_overlap_penalty(self):
|
||||
client = DustOverlapSpotClient()
|
||||
@@ -201,7 +304,7 @@ class OpportunityServiceTestCase(unittest.TestCase):
|
||||
ignored_rec = ignored["recommendations"][0]
|
||||
included_rec = included["recommendations"][0]
|
||||
|
||||
self.assertEqual(ignored_rec["action"], "enter")
|
||||
self.assertEqual(ignored_rec["action"], "trigger")
|
||||
self.assertEqual(ignored_rec["metrics"]["position_weight"], 0.0)
|
||||
self.assertEqual(included_rec["action"], "skip")
|
||||
self.assertEqual(included_rec["metrics"]["position_weight"], 1.0)
|
||||
|
||||
Reference in New Issue
Block a user