Support selectable demo exchanges and configurable analysis limits
Persist manual requests until exchange confirmation, preserve stop protection, and reconcile fills before settling plans. Tighten model stream, crawler, skill, research accounting, and frontend race handling, with regression coverage. Keep queued analyses pending until a fresh account snapshot is available.
This commit is contained in:
1 parent
fcaedfb358
commit
285b3952d7
33 files changed
+1890
-325
No files matched your search
@@ -0,0 +1,67 @@
|
||||
"""模拟盘支持按交易所隔离凭证、计划、订单和成交。
|
||||
|
||||
Revision ID: b8d1f4a92c60
|
||||
Revises: c5e8a1b3d207
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "b8d1f4a92c60"
|
||||
down_revision = "c5e8a1b3d207"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("trading_account", sa.Column("exchange", sa.String(16), server_default="binance", nullable=False))
|
||||
op.create_table(
|
||||
"trading_credentials",
|
||||
sa.Column("exchange", sa.String(16), primary_key=True),
|
||||
sa.Column("api_key_encrypted", sa.LargeBinary()),
|
||||
sa.Column("api_secret_encrypted", sa.LargeBinary()),
|
||||
sa.Column("api_key_hint", sa.String(8)),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
)
|
||||
op.execute("""INSERT INTO trading_credentials
|
||||
(exchange, api_key_encrypted, api_secret_encrypted, api_key_hint, updated_at)
|
||||
SELECT 'binance', api_key_encrypted, api_secret_encrypted, api_key_hint, updated_at FROM trading_account""")
|
||||
for column in ("api_key_encrypted", "api_secret_encrypted", "api_key_hint"):
|
||||
op.drop_column("trading_account", column)
|
||||
for table in ("trading_analyses", "trading_orders", "trading_events", "trading_fills"):
|
||||
op.add_column(table, sa.Column("exchange", sa.String(16), server_default="binance", nullable=False))
|
||||
if table != "trading_fills":
|
||||
op.create_index(f"ix_{table}_exchange", table, ["exchange"])
|
||||
op.alter_column("trading_orders", "exchange_id", type_=sa.String(64), existing_type=sa.String(32))
|
||||
for column in ("trade_id", "order_id"):
|
||||
op.alter_column("trading_fills", column, type_=sa.String(64), existing_type=sa.BigInteger(), postgresql_using=f"{column}::text")
|
||||
op.drop_constraint("trading_fills_pkey", "trading_fills", type_="primary")
|
||||
op.create_primary_key("trading_fills_pkey", "trading_fills", ["exchange", "symbol", "trade_id"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# Bybit ID 无法转回整数;已有 Bybit 数据时明确拒绝回退,避免丢失历史。
|
||||
op.execute("""DO $$ BEGIN
|
||||
IF EXISTS (SELECT 1 FROM trading_fills WHERE exchange != 'binance')
|
||||
OR EXISTS (SELECT 1 FROM trading_orders WHERE exchange != 'binance')
|
||||
OR EXISTS (SELECT 1 FROM trading_analyses WHERE exchange != 'binance')
|
||||
OR EXISTS (SELECT 1 FROM trading_credentials WHERE exchange != 'binance') THEN
|
||||
RAISE EXCEPTION '已有其他交易所数据,不能回退模拟盘迁移';
|
||||
END IF;
|
||||
END $$""")
|
||||
op.drop_constraint("trading_fills_pkey", "trading_fills", type_="primary")
|
||||
for column in ("trade_id", "order_id"):
|
||||
op.alter_column("trading_fills", column, type_=sa.BigInteger(), postgresql_using=f"{column}::bigint")
|
||||
op.create_primary_key("trading_fills_pkey", "trading_fills", ["symbol", "trade_id"])
|
||||
op.alter_column("trading_orders", "exchange_id", type_=sa.String(32))
|
||||
for table in ("trading_analyses", "trading_orders", "trading_events", "trading_fills"):
|
||||
if table != "trading_fills":
|
||||
op.drop_index(f"ix_{table}_exchange", table_name=table)
|
||||
op.drop_column(table, "exchange")
|
||||
for column, kind in (("api_key_encrypted", sa.LargeBinary()), ("api_secret_encrypted", sa.LargeBinary()), ("api_key_hint", sa.String(8))):
|
||||
op.add_column("trading_account", sa.Column(column, kind))
|
||||
op.execute("""UPDATE trading_account SET api_key_encrypted = c.api_key_encrypted,
|
||||
api_secret_encrypted = c.api_secret_encrypted, api_key_hint = c.api_key_hint
|
||||
FROM trading_credentials c WHERE c.exchange = 'binance'""")
|
||||
op.drop_table("trading_credentials")
|
||||
op.drop_column("trading_account", "exchange")
|
||||
@@ -0,0 +1,21 @@
|
||||
"""每日分析上限改为用户配置。
|
||||
|
||||
Revision ID: d2a4c6e8f103
|
||||
Revises: b8d1f4a92c60
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "d2a4c6e8f103"
|
||||
down_revision = "b8d1f4a92c60"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("trading_account", sa.Column("daily_analysis_limit", sa.Integer(), nullable=False, server_default="60"))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("trading_account", "daily_analysis_limit")
|
||||
Reference in new issue
Block a user