增加关键位人工输入
This commit is contained in:
@@ -7,7 +7,7 @@ from sqlalchemy import desc, select
|
||||
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
|
||||
from .models import AlertRecord, Base, KvStore, RuntimeLog
|
||||
from .models import AlertRecord, Base, KeyMonitor, KeyMonitorHistory, KvStore, RuntimeLog
|
||||
|
||||
DEFAULT_CHART_BAR = "1D"
|
||||
|
||||
@@ -152,5 +152,189 @@ class Storage:
|
||||
for row in rows
|
||||
]
|
||||
|
||||
async def add_key_monitor(
|
||||
self,
|
||||
*,
|
||||
symbol: str,
|
||||
inst_id: str,
|
||||
monitor_type: str,
|
||||
direction: str,
|
||||
upper: float,
|
||||
lower: float,
|
||||
sl_tp_mode: str,
|
||||
manual_take_profit: float | None,
|
||||
stop_outside_pct: float,
|
||||
breakeven_enabled: int,
|
||||
note: str | None = None,
|
||||
) -> int:
|
||||
async with self.session_factory() as session:
|
||||
row = KeyMonitor(
|
||||
symbol=symbol.strip().upper(),
|
||||
inst_id=inst_id.strip().upper(),
|
||||
monitor_type=monitor_type,
|
||||
direction=direction.strip().lower(),
|
||||
upper=upper,
|
||||
lower=lower,
|
||||
sl_tp_mode=sl_tp_mode,
|
||||
manual_take_profit=manual_take_profit,
|
||||
stop_outside_pct=stop_outside_pct,
|
||||
breakeven_enabled=breakeven_enabled,
|
||||
note=note,
|
||||
)
|
||||
session.add(row)
|
||||
await session.commit()
|
||||
await session.refresh(row)
|
||||
return int(row.id)
|
||||
|
||||
async def list_key_monitors(self) -> list[dict]:
|
||||
async with self.session_factory() as session:
|
||||
stmt = select(KeyMonitor).order_by(desc(KeyMonitor.created_at))
|
||||
rows = (await session.execute(stmt)).scalars().all()
|
||||
return [_key_monitor_to_dict(r) for r in rows]
|
||||
|
||||
async def get_key_monitor(self, kid: int) -> dict | None:
|
||||
async with self.session_factory() as session:
|
||||
row = await session.get(KeyMonitor, kid)
|
||||
return _key_monitor_to_dict(row) if row else None
|
||||
|
||||
async def delete_key_monitor(self, kid: int) -> bool:
|
||||
async with self.session_factory() as session:
|
||||
row = await session.get(KeyMonitor, kid)
|
||||
if not row:
|
||||
return False
|
||||
await session.delete(row)
|
||||
await session.commit()
|
||||
return True
|
||||
|
||||
async def finalize_key_monitor(
|
||||
self,
|
||||
row: dict,
|
||||
*,
|
||||
close_reason: str,
|
||||
last_alert_message: str | None,
|
||||
confirm_close: float | None,
|
||||
planned_sl: float | None,
|
||||
planned_tp: float | None,
|
||||
planned_rr: float | None,
|
||||
executor_signal_id: str | None,
|
||||
executor_status: str | None,
|
||||
checks: dict | None,
|
||||
) -> int:
|
||||
async with self.session_factory() as session:
|
||||
hist = KeyMonitorHistory(
|
||||
key_monitor_id=int(row["id"]),
|
||||
symbol=row["symbol"],
|
||||
inst_id=row["inst_id"],
|
||||
monitor_type=row["monitor_type"],
|
||||
direction=row["direction"],
|
||||
upper=float(row["upper"]),
|
||||
lower=float(row["lower"]),
|
||||
sl_tp_mode=row["sl_tp_mode"],
|
||||
manual_take_profit=row.get("manual_take_profit"),
|
||||
stop_outside_pct=float(row["stop_outside_pct"]),
|
||||
confirm_close=confirm_close,
|
||||
planned_sl=planned_sl,
|
||||
planned_tp=planned_tp,
|
||||
planned_rr=planned_rr,
|
||||
executor_signal_id=executor_signal_id,
|
||||
executor_status=executor_status,
|
||||
checks_json=json.dumps(checks or {}, ensure_ascii=False),
|
||||
last_alert_message=last_alert_message,
|
||||
close_reason=close_reason,
|
||||
)
|
||||
session.add(hist)
|
||||
active = await session.get(KeyMonitor, int(row["id"]))
|
||||
if active:
|
||||
await session.delete(active)
|
||||
await session.commit()
|
||||
await session.refresh(hist)
|
||||
return int(hist.id)
|
||||
|
||||
async def list_key_monitor_history(
|
||||
self,
|
||||
*,
|
||||
limit: int = 500,
|
||||
since: datetime | None = None,
|
||||
) -> list[dict]:
|
||||
async with self.session_factory() as session:
|
||||
stmt = select(KeyMonitorHistory).order_by(desc(KeyMonitorHistory.closed_at)).limit(limit)
|
||||
if since is not None:
|
||||
stmt = stmt.where(KeyMonitorHistory.closed_at >= since)
|
||||
rows = (await session.execute(stmt)).scalars().all()
|
||||
return [_key_history_to_dict(r) for r in rows]
|
||||
|
||||
async def delete_key_monitor_history(self, hid: int) -> bool:
|
||||
async with self.session_factory() as session:
|
||||
row = await session.get(KeyMonitorHistory, hid)
|
||||
if not row:
|
||||
return False
|
||||
await session.delete(row)
|
||||
await session.commit()
|
||||
return True
|
||||
|
||||
async def export_key_monitor_history_rows(
|
||||
self,
|
||||
*,
|
||||
start_utc: datetime,
|
||||
end_utc: datetime,
|
||||
) -> list[dict]:
|
||||
async with self.session_factory() as session:
|
||||
stmt = (
|
||||
select(KeyMonitorHistory)
|
||||
.where(
|
||||
KeyMonitorHistory.closed_at >= start_utc,
|
||||
KeyMonitorHistory.closed_at <= end_utc,
|
||||
)
|
||||
.order_by(KeyMonitorHistory.id.asc())
|
||||
)
|
||||
rows = (await session.execute(stmt)).scalars().all()
|
||||
return [_key_history_to_dict(r) for r in rows]
|
||||
|
||||
async def close(self) -> None:
|
||||
await self.engine.dispose()
|
||||
|
||||
|
||||
def _key_monitor_to_dict(row: KeyMonitor | None) -> dict:
|
||||
if row is None:
|
||||
return {}
|
||||
return {
|
||||
"id": row.id,
|
||||
"symbol": row.symbol,
|
||||
"inst_id": row.inst_id,
|
||||
"monitor_type": row.monitor_type,
|
||||
"direction": row.direction,
|
||||
"upper": row.upper,
|
||||
"lower": row.lower,
|
||||
"sl_tp_mode": row.sl_tp_mode,
|
||||
"manual_take_profit": row.manual_take_profit,
|
||||
"stop_outside_pct": row.stop_outside_pct,
|
||||
"breakeven_enabled": row.breakeven_enabled,
|
||||
"note": row.note,
|
||||
"created_at": row.created_at.isoformat(),
|
||||
}
|
||||
|
||||
|
||||
def _key_history_to_dict(row: KeyMonitorHistory) -> dict:
|
||||
return {
|
||||
"id": row.id,
|
||||
"key_monitor_id": row.key_monitor_id,
|
||||
"symbol": row.symbol,
|
||||
"inst_id": row.inst_id,
|
||||
"monitor_type": row.monitor_type,
|
||||
"direction": row.direction,
|
||||
"upper": row.upper,
|
||||
"lower": row.lower,
|
||||
"sl_tp_mode": row.sl_tp_mode,
|
||||
"manual_take_profit": row.manual_take_profit,
|
||||
"stop_outside_pct": row.stop_outside_pct,
|
||||
"confirm_close": row.confirm_close,
|
||||
"planned_sl": row.planned_sl,
|
||||
"planned_tp": row.planned_tp,
|
||||
"planned_rr": row.planned_rr,
|
||||
"executor_signal_id": row.executor_signal_id,
|
||||
"executor_status": row.executor_status,
|
||||
"checks_json": row.checks_json,
|
||||
"last_alert_message": row.last_alert_message,
|
||||
"close_reason": row.close_reason,
|
||||
"closed_at": row.closed_at.isoformat(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user