feat: mo_data.py unified read layer (DB-first, JSON fallback) + cash_log table + batch JSON→DB migration (16 files)
This commit is contained in:
+54
@@ -263,6 +263,20 @@ def init_all_tables(conn: sqlite3.Connection):
|
||||
updated_at TEXT
|
||||
);
|
||||
|
||||
-- 现金变更日志(每次买卖/出入金记录)
|
||||
CREATE TABLE IF NOT EXISTS cash_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TEXT NOT NULL DEFAULT (datetime('now','localtime')),
|
||||
cash_before REAL, -- 变更前可用现金
|
||||
cash_after REAL, -- 变更后可用现金
|
||||
frozen_before REAL, -- 变更前冻结资金
|
||||
frozen_after REAL, -- 变更后冻结资金
|
||||
change_amount REAL, -- 现金变动额(正=入金/卖股,负=出金/买股)
|
||||
source TEXT NOT NULL, -- 来源: screenshot/manual/import_xls/trade
|
||||
note TEXT, -- 备注: 例如 "卖出法拉电子 200股"
|
||||
verified INTEGER DEFAULT 0 -- 是否已验证(0=未验证,1=Dad确认)
|
||||
);
|
||||
|
||||
-- 建议时间线(decisions.json advice_timeline[])
|
||||
CREATE TABLE IF NOT EXISTS advice_timeline (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -371,6 +385,20 @@ def init_all_tables(conn: sqlite3.Connection):
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
|
||||
# cash_log migration (2026-07-01)
|
||||
try:
|
||||
conn.execute("ALTER TABLE cash_log ADD COLUMN frozen_before REAL")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE cash_log ADD COLUMN frozen_after REAL")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
try:
|
||||
conn.execute("ALTER TABLE cash_log ADD COLUMN verified INTEGER DEFAULT 0")
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
|
||||
# ── 币种约束迁移(2026-06-30)────────────────────────────────
|
||||
_currency_migrations = [
|
||||
("holdings", ["price REAL", "market_value REAL", "change_pct REAL",
|
||||
@@ -1041,3 +1069,29 @@ def write_watchlist_stock(conn, stock: dict) -> tuple[bool, str]:
|
||||
return True, f"自选 {stock.get('code')} 已写入"
|
||||
except sqlite3.IntegrityError as e:
|
||||
return False, f"约束: {e}"
|
||||
|
||||
|
||||
def write_cash_log(conn, data: dict) -> tuple[bool, str]:
|
||||
"""记录现金变更(替代手动改 portfolio.json cash 字段)"""
|
||||
try:
|
||||
conn.execute("""
|
||||
INSERT INTO cash_log (cash_before, cash_after, frozen_before, frozen_after,
|
||||
change_amount, source, note)
|
||||
VALUES (?,?,?,?,?,?,?)
|
||||
""", (
|
||||
data.get('cash_before'), data.get('cash_after'),
|
||||
data.get('frozen_before'), data.get('frozen_after'),
|
||||
data.get('change_amount'), data.get('source', 'manual'),
|
||||
data.get('note', ''),
|
||||
))
|
||||
conn.commit()
|
||||
return True, "现金变更已记录"
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def query_cash_log(conn, limit: int = 20) -> list[dict]:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM cash_log ORDER BY id DESC LIMIT ?", (limit,)
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
Reference in New Issue
Block a user