feat: reset endpoint now liquidates Alpaca positions and cancels orders

- Added cancel_all_orders() and close_all_positions() to AlpacaBrokerAdapter
- Reset endpoint creates a temporary adapter to call Alpaca DELETE /v2/orders
  and DELETE /v2/positions before clearing DB and engine state
- Also clears positions table and processed_recommendation_ids on reset
- Broker reset is best-effort — DB/engine reset proceeds even if Alpaca fails
This commit is contained in:
Celes Renata
2026-04-17 04:03:31 +00:00
parent 5fc78bd9b4
commit 5fb59b379c
2 changed files with 85 additions and 1 deletions
+33 -1
View File
@@ -407,6 +407,9 @@ async def reset_paper_trading(body: CapitalRequest) -> dict[str, Any]:
"""Full paper trading reset: clear all positions, orders, decisions,
stop levels, and snapshots, then reset capital to the specified amount.
Also liquidates all positions and cancels all open orders on the
broker (Alpaca) so the paper account starts clean.
This is a destructive operation — all trading history is wiped.
"""
if engine is None:
@@ -420,7 +423,32 @@ async def reset_paper_trading(body: CapitalRequest) -> dict[str, Any]:
reserve = capital * reserve_pct
active = capital - reserve
# Clear trading state in the database
# --- Reset broker (Alpaca) state ---
broker_result: dict[str, Any] = {"orders_cancelled": 0, "positions_closed": 0}
try:
from services.adapters.broker_adapter import AlpacaBrokerAdapter
from services.shared.config import load_config as _load_config
broker_cfg = _load_config().broker
if broker_cfg.api_key:
adapter = AlpacaBrokerAdapter(
api_key=broker_cfg.api_key,
api_secret=broker_cfg.api_secret or "",
base_url=broker_cfg.base_url,
)
broker_result["orders_cancelled"] = await adapter.cancel_all_orders()
broker_result["positions_closed"] = await adapter.close_all_positions()
logger.info(
"Broker reset: cancelled %d orders, closed %d positions",
broker_result["orders_cancelled"],
broker_result["positions_closed"],
)
else:
logger.info("No broker API key configured — skipping broker reset")
except Exception:
logger.exception("Broker reset failed — continuing with DB/engine reset")
# --- Clear trading state in the database ---
if engine.pool:
try:
async with engine.pool.acquire() as conn:
@@ -438,6 +466,8 @@ async def reset_paper_trading(body: CapitalRequest) -> dict[str, Any]:
# Clear orders and their events
await conn.execute("DELETE FROM order_events")
await conn.execute("DELETE FROM orders")
# Clear synced positions from broker
await conn.execute("DELETE FROM positions")
# Re-seed reserve pool ledger
await conn.execute(
"INSERT INTO reserve_pool_ledger (amount, balance_after, trigger_type, notes) "
@@ -458,12 +488,14 @@ async def reset_paper_trading(body: CapitalRequest) -> dict[str, Any]:
reserve_pool=reserve,
)
engine.circuit_breaker_state = CircuitBreakerState()
engine.processed_recommendation_ids.clear()
return {
"reset": True,
"initial_capital": capital,
"active_pool": active,
"reserve_pool": reserve,
"broker": broker_result,
}