|
@@ -0,0 +1,123 @@
|
|
|
|
|
+from __future__ import annotations
|
|
|
|
|
+
|
|
|
|
|
+import json
|
|
|
|
|
+
|
|
|
|
|
+import pytest
|
|
|
|
|
+
|
|
|
|
|
+from exec_mcp import repo, storage
|
|
|
|
|
+from exec_mcp.server import report_balance_snapshots, report_recent_trades
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@pytest.fixture()
|
|
|
|
|
+def temp_db(tmp_path, monkeypatch):
|
|
|
|
|
+ db_path = tmp_path / "exec.sqlite3"
|
|
|
|
|
+ monkeypatch.setattr(storage, "DB_PATH", db_path)
|
|
|
|
|
+ storage.init_db()
|
|
|
|
|
+ return db_path
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _create_account() -> str:
|
|
|
|
|
+ repo.create_account(display_name="strategy", venue="bitstamp", venue_account_ref="ref-1", api_key="k", api_secret="s")
|
|
|
|
|
+ return repo.list_accounts(enabled_only=False)[0]["id"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_report_recent_trades_defaults_to_filled_and_sorts_newest_first(temp_db):
|
|
|
|
|
+ account_id = _create_account()
|
|
|
|
|
+
|
|
|
|
|
+ with storage.get_connection() as conn:
|
|
|
|
|
+ rows = [
|
|
|
|
|
+ ("rec-1", "filled", "client-a", "1994292738961401", "2026-04-09T08:20:50+00:00"),
|
|
|
|
|
+ ("rec-2", "cancelled", "client-a", "1994292738961402", "2026-04-09T09:20:50+00:00"),
|
|
|
|
|
+ ("rec-3", "filled", "client-b", "1994292738961403", "2026-04-09T10:20:50+00:00"),
|
|
|
|
|
+ ("rec-4", "open", "client-a", "1994292738961404", "2026-04-09T11:20:50+00:00"),
|
|
|
|
|
+ ]
|
|
|
|
|
+ for record_id, status, client_id, order_id, stamp in rows:
|
|
|
|
|
+ conn.execute(
|
|
|
|
|
+ """
|
|
|
|
|
+ INSERT INTO order_records
|
|
|
|
|
+ (id, account_id, market, side, order_type, amount, price, expire_time, status, bitstamp_order_id, client_id, client_order_id, raw_json, created_at, updated_at)
|
|
|
|
|
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
|
|
+ """,
|
|
|
|
|
+ (
|
|
|
|
|
+ record_id,
|
|
|
|
|
+ account_id,
|
|
|
|
|
+ "xrpusd",
|
|
|
|
|
+ "buy",
|
|
|
|
|
+ "limit",
|
|
|
|
|
+ "10",
|
|
|
|
|
+ "2.00",
|
|
|
|
|
+ None,
|
|
|
|
|
+ status,
|
|
|
|
|
+ order_id,
|
|
|
|
|
+ client_id,
|
|
|
|
|
+ None,
|
|
|
|
|
+ json.dumps({"id": order_id, "status": status}),
|
|
|
|
|
+ stamp,
|
|
|
|
|
+ stamp,
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+ result = report_recent_trades(account_id=account_id)
|
|
|
|
|
+ assert result["ok"] is True
|
|
|
|
|
+ assert result["status"] == "filled"
|
|
|
|
|
+ assert result["count"] == 2
|
|
|
|
|
+ assert [row["bitstamp_order_id"] for row in result["orders"]] == ["1994292738961403", "1994292738961401"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_report_recent_trades_supports_all_statuses_and_client_filter(temp_db):
|
|
|
|
|
+ account_id = _create_account()
|
|
|
|
|
+
|
|
|
|
|
+ with storage.get_connection() as conn:
|
|
|
|
|
+ for idx, (status, client_id, stamp) in enumerate(
|
|
|
|
|
+ [
|
|
|
|
|
+ ("filled", "client-a", "2026-04-09T08:20:50+00:00"),
|
|
|
|
|
+ ("cancelled", "client-a", "2026-04-09T09:20:50+00:00"),
|
|
|
|
|
+ ("filled", "client-b", "2026-04-09T10:20:50+00:00"),
|
|
|
|
|
+ ],
|
|
|
|
|
+ start=1,
|
|
|
|
|
+ ):
|
|
|
|
|
+ order_id = f"19942927389614{idx}"
|
|
|
|
|
+ conn.execute(
|
|
|
|
|
+ """
|
|
|
|
|
+ INSERT INTO order_records
|
|
|
|
|
+ (id, account_id, market, side, order_type, amount, price, expire_time, status, bitstamp_order_id, client_id, client_order_id, raw_json, created_at, updated_at)
|
|
|
|
|
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
|
|
|
+ """,
|
|
|
|
|
+ (
|
|
|
|
|
+ f"rec-{idx}",
|
|
|
|
|
+ account_id,
|
|
|
|
|
+ "xrpusd",
|
|
|
|
|
+ "sell",
|
|
|
|
|
+ "limit",
|
|
|
|
|
+ "10",
|
|
|
|
|
+ "2.00",
|
|
|
|
|
+ None,
|
|
|
|
|
+ status,
|
|
|
|
|
+ order_id,
|
|
|
|
|
+ client_id,
|
|
|
|
|
+ None,
|
|
|
|
|
+ json.dumps({"id": order_id, "status": status}),
|
|
|
|
|
+ stamp,
|
|
|
|
|
+ stamp,
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ conn.commit()
|
|
|
|
|
+
|
|
|
|
|
+ result = report_recent_trades(account_id=account_id, status="all", client_id="client-a", limit=10)
|
|
|
|
|
+ assert result["ok"] is True
|
|
|
|
|
+ assert result["status"] == "all"
|
|
|
|
|
+ assert result["client_id"] == "client-a"
|
|
|
|
|
+ assert [row["status"] for row in result["orders"]] == ["cancelled", "filled"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_report_balance_snapshots_returns_history_newest_first(temp_db):
|
|
|
|
|
+ account_id = _create_account()
|
|
|
|
|
+
|
|
|
|
|
+ repo.save_balance_snapshot(account_id=account_id, asset_code="BTC", balance=1.25, balance_value=11250.0, value_currency="USD")
|
|
|
|
|
+ repo.save_balance_snapshot(account_id=account_id, asset_code="USD", balance=500.0, balance_value=500.0, value_currency="USD")
|
|
|
|
|
+
|
|
|
|
|
+ result = report_balance_snapshots(account_id=account_id)
|
|
|
|
|
+ assert result["ok"] is True
|
|
|
|
|
+ assert result["count"] == 2
|
|
|
|
|
+ assert [row["asset_code"] for row in result["snapshots"]] == ["USD", "BTC"]
|