|
|
@@ -1,6 +1,8 @@
|
|
|
from __future__ import annotations
|
|
|
|
|
|
import json
|
|
|
+import os
|
|
|
+import time
|
|
|
from datetime import datetime, timezone, timedelta
|
|
|
from decimal import Decimal, ROUND_DOWN
|
|
|
from uuid import uuid4
|
|
|
@@ -15,6 +17,13 @@ from .storage import get_connection
|
|
|
OPEN_ORDER_STATUSES = {"open", "new", "partially_filled"}
|
|
|
|
|
|
|
|
|
+def _bitstamp_call_delay_seconds() -> float:
|
|
|
+ try:
|
|
|
+ return max(int(os.getenv("BITSTAMP_CALL_DELAY_MS", "250")) / 1000.0, 0.0)
|
|
|
+ except Exception:
|
|
|
+ return 0.25
|
|
|
+
|
|
|
+
|
|
|
def _utc_now() -> str:
|
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
@@ -168,14 +177,19 @@ def get_open_orders(*, account_id: str, client_id: str | None = None) -> dict:
|
|
|
(account_id, client_id),
|
|
|
).fetchall()
|
|
|
|
|
|
+ order_status_v2 = getattr(getattr(client, "trading", None), "order_status_v2", None)
|
|
|
+ if order_status_v2 is None:
|
|
|
+ return {"ok": True, "client_id": client_id, "orders": [dict(row) for row in rows]}
|
|
|
+
|
|
|
orders = []
|
|
|
+ delay = _bitstamp_call_delay_seconds()
|
|
|
for row in rows:
|
|
|
order = dict(row)
|
|
|
bitstamp_order_id = order.get("bitstamp_order_id")
|
|
|
if not bitstamp_order_id:
|
|
|
continue
|
|
|
try:
|
|
|
- result = client.trading.order_status_v2(order_id=str(bitstamp_order_id), omit_transactions=True)
|
|
|
+ result = order_status_v2(order_id=str(bitstamp_order_id), omit_transactions=True)
|
|
|
status = _normalize_status(result.get("status", "unknown"))
|
|
|
if status not in OPEN_ORDER_STATUSES:
|
|
|
_set_local_order_status(bitstamp_order_id=str(bitstamp_order_id), status=status)
|
|
|
@@ -183,13 +197,15 @@ def get_open_orders(*, account_id: str, client_id: str | None = None) -> dict:
|
|
|
order["status"] = status
|
|
|
order["raw_json"] = json.dumps(result)
|
|
|
orders.append(order)
|
|
|
- except BitstampError as exc:
|
|
|
+ except Exception as exc:
|
|
|
msg = str(exc)
|
|
|
if "not found" in msg.lower():
|
|
|
_set_local_order_status(bitstamp_order_id=str(bitstamp_order_id), status="missing")
|
|
|
continue
|
|
|
# Best effort: keep the local record when the exchange cannot be queried.
|
|
|
orders.append(order)
|
|
|
+ if delay > 0:
|
|
|
+ time.sleep(delay)
|
|
|
|
|
|
return {"ok": True, "client_id": client_id, "orders": orders}
|
|
|
|
|
|
@@ -198,6 +214,7 @@ def cancel_all_orders(*, account_id: str, client_id: str | None = None) -> dict:
|
|
|
client_id = _normalize_client_id(client_id)
|
|
|
orders = get_open_orders(account_id=account_id, client_id=client_id)["orders"]
|
|
|
results = []
|
|
|
+ delay = _bitstamp_call_delay_seconds()
|
|
|
for order in orders:
|
|
|
bitstamp_order_id = order.get("bitstamp_order_id")
|
|
|
if not bitstamp_order_id:
|
|
|
@@ -212,6 +229,8 @@ def cancel_all_orders(*, account_id: str, client_id: str | None = None) -> dict:
|
|
|
results.append({"ok": False, "order_id": bitstamp_order_id, "error": detail, "status": "missing"})
|
|
|
continue
|
|
|
raise
|
|
|
+ if delay > 0:
|
|
|
+ time.sleep(delay)
|
|
|
return {"ok": True, "client_id": client_id, "cancelled": results, "count": len(results)}
|
|
|
|
|
|
|