现金更正 + 法拉电子清仓记录
截图确认: - 可用资金 92,664.20(含天添利) - 冻结 39,481.40 - 总现金 132,145.60 - 总资产 = 持仓市值1,107,670 + 现金132,145.60 = 1,239,815.60 法拉电子 189.20卖出100股已记录
This commit is contained in:
@@ -5,11 +5,13 @@ import_holding_xls.py — 从 holding.xls 导入持仓到全系统
|
||||
用法:
|
||||
python3 import_holding_xls.py [--cash 现金] [--total 总资产] [--mv 市值]
|
||||
|
||||
--cash 必传!holding文件不含现金行,不传则现金=0。
|
||||
|
||||
不传 --total/--mv 则从 holding.xls 计算(可能有价格时差误差)。
|
||||
建议传截图上的真实数字。
|
||||
|
||||
示例:
|
||||
python3 import_holding_xls.py --cash 20230.10 --total 1008860.62 --mv 988512.96
|
||||
python3 import_holding_xls.py --cash 73758.0 --total 874598.90 --mv 800840.90
|
||||
"""
|
||||
import csv, json, sys, subprocess, sqlite3, os
|
||||
from datetime import datetime
|
||||
@@ -30,7 +32,9 @@ def clean_cell(v):
|
||||
|
||||
def main():
|
||||
# Parse args
|
||||
cash = 20230.10
|
||||
# ⚠️ 现金不从holding文件读取。holding只有股票持仓,现金必须单独提供(截图)。
|
||||
# 不传 --cash 则默认为0,会在后面警告。
|
||||
cash = 0.0
|
||||
total_assets = 0
|
||||
market_value = 0
|
||||
|
||||
@@ -69,7 +73,7 @@ def main():
|
||||
cost_amount = float(clean_cell(r[15])) if r[15].strip() and r[15].strip() != '--' else 0
|
||||
rate_str = clean_cell(r[16])
|
||||
rate = float(rate_str) if rate_str and rate_str != '--' else 0.8664
|
||||
mv_cny = mkt_val if currency == 'CNY' else mkt_val * rate
|
||||
mv_cny = mkt_val
|
||||
total_mv_cny += mv_cny
|
||||
|
||||
holdings.append({
|
||||
@@ -79,6 +83,11 @@ def main():
|
||||
'cost_amount': cost_amount, 'exchange_rate': rate,
|
||||
})
|
||||
|
||||
if cash <= 0:
|
||||
print("⚠️ 警告:未提供现金(--cash),现金默认=0。Dad可能给了截图现金数!")
|
||||
print(" holding文件不含现金行,必须手动提供。可以用:")
|
||||
print(f" python3 import_holding_xls.py --cash 73758.0")
|
||||
|
||||
# Use provided values or calculate
|
||||
if total_assets <= 0:
|
||||
total_assets = total_mv_cny + cash
|
||||
|
||||
@@ -71,25 +71,61 @@ def check_xiaoguo():
|
||||
check_http("http://192.168.1.122:18003/v1/models")
|
||||
|
||||
|
||||
PORTFOLIO_PATH = str(DATA / "portfolio.json")
|
||||
|
||||
|
||||
def check_price_monitor():
|
||||
"""价格监控:进程在跑 + 最近有数据"""
|
||||
# 进程检查
|
||||
r = subprocess.run(["pgrep", "-f", "price_monitor"], capture_output=True, timeout=5)
|
||||
process_alive = r.returncode == 0
|
||||
if not process_alive:
|
||||
log(False, "价格监控进程不在运行")
|
||||
"""价格监控:检查price_monitor cron最近是否运行 + 数据是否更新
|
||||
|
||||
注意:price_events 存储的是区间偏离事件(价格穿过买入区/止损/止盈边界),
|
||||
不是心跳信号。横盘期/无操作信号时自然不会有新事件。因此不检查event数,
|
||||
改为检查 cron 最后运行时间和 portfolio.json 数据新鲜度。
|
||||
"""
|
||||
# 检查cron最近运行记录
|
||||
cron_ok = False
|
||||
try:
|
||||
with open(str(CRON_JOBS)) as f:
|
||||
data = json.load(f)
|
||||
jobs_list = data.get("jobs", []) if isinstance(data.get("jobs"), list) else []
|
||||
if not jobs_list:
|
||||
jobs_list = list(data.get("jobs", {}).values())
|
||||
for job in jobs_list:
|
||||
if not job:
|
||||
continue
|
||||
script = job.get("script") or ""
|
||||
name = job.get("name") or ""
|
||||
if "price_monitor" in script or "价格监控" in name:
|
||||
last_run = job.get("last_run_at")
|
||||
if last_run:
|
||||
last_dt = datetime.fromisoformat(last_run)
|
||||
# 兼容带时区和无时区两种格式
|
||||
ref_now = datetime.now(last_dt.tzinfo) if last_dt.tzinfo else datetime.now()
|
||||
elapsed = (ref_now - last_dt).total_seconds()
|
||||
if elapsed < 600: # 10分钟内运行过
|
||||
cron_ok = True
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not cron_ok:
|
||||
log(False, "价格监控cron无最近运行记录(>10分钟未运行)")
|
||||
return
|
||||
|
||||
# 数据新鲜度(最近10分钟是否有事件)
|
||||
# 检查portfolio.json数据新鲜度
|
||||
try:
|
||||
conn = sqlite3.connect(str(DB_PATH))
|
||||
recent = conn.execute(
|
||||
"SELECT COUNT(*) FROM price_events WHERE created_at > datetime('now', '-10 minutes')"
|
||||
).fetchone()[0]
|
||||
conn.close()
|
||||
log(recent > 0, f"价格监控进程在跑,但最近10分钟无新事件")
|
||||
except:
|
||||
log(True, "价格监控进程在跑")
|
||||
pf = json.load(open(PORTFOLIO_PATH))
|
||||
pf_updated = pf.get("updated_at", "")
|
||||
if pf_updated:
|
||||
pf_dt = datetime.strptime(pf_updated, "%Y-%m-%d %H:%M")
|
||||
seconds_ago = (datetime.now() - pf_dt).total_seconds()
|
||||
if seconds_ago < 600: # 10分钟内
|
||||
log(True, f"价格监控运行正常,数据{int(seconds_ago//60)}分钟前更新")
|
||||
else:
|
||||
log(False, f"价格数据{int(seconds_ago)}秒未更新(portfolio.json)")
|
||||
else:
|
||||
log(False, "portfolio.json缺少updated_at字段")
|
||||
except Exception as e:
|
||||
log(False, f"价格数据新鲜度检查失败: {e}")
|
||||
|
||||
|
||||
def check_bots():
|
||||
@@ -124,11 +160,21 @@ def check_signal_pipeline():
|
||||
if risk_path.exists():
|
||||
risk = json.loads(risk_path.read_text())
|
||||
level = risk.get("level", "none")
|
||||
reason = risk.get("reason", "")
|
||||
if level == "high":
|
||||
log(False, f"🔴 宏观风险HIGH: {reason[:80]}")
|
||||
expired = risk.get("expired", False)
|
||||
# 提取摘要做原因描述(state.json用signals数组,不是reason字段)
|
||||
signals = risk.get("signals", [])
|
||||
reason = ""
|
||||
if signals and isinstance(signals, list) and len(signals) > 0:
|
||||
first_sig = signals[0]
|
||||
summary = first_sig.get("summary", "")
|
||||
if summary:
|
||||
reason = summary[:80].replace("\n", " ")
|
||||
if level == "high" and not expired:
|
||||
log(False, f"🔴 宏观风险HIGH: {reason}")
|
||||
elif level == "high" and expired:
|
||||
log(True, f"⏳ 宏观风险HIGH已过期(无新信号超过15分钟)")
|
||||
elif level == "medium":
|
||||
log(True, f"⚠️ 宏观风险MEDIUM: {reason[:80]}")
|
||||
log(True, f"⚠️ 宏观风险MEDIUM: {reason}")
|
||||
else:
|
||||
log(True, "无宏观风险状态文件(可能未生成)")
|
||||
except:
|
||||
|
||||
@@ -29,30 +29,32 @@ STATE_PATH = DATA_DIR / "macro_risk_state.json"
|
||||
# HIGH: 任何一条匹配 → 立即 HIGH 预警
|
||||
HIGH_PATTERNS = [
|
||||
# 全球巨头+核心产业
|
||||
r"苹果.*(?:涨价|降价|推迟|取消|禁|制裁|调查|召回|大跌|暴跌)",
|
||||
# 苹果: 排除合作/采购类新闻(如'苹果牵手长鑫存储,MLCC涨价'→非风险)
|
||||
r"苹果(?!.*?(?:牵手|合作|联合|携手|助力|入驻|投资|设立|引入)).*?(?:涨价|降价|推迟|取消|禁|制裁|调查|召回|大跌|暴跌)",
|
||||
r"openai.*(?:推迟|取消|风险|调查|起诉|倒闭|ipo)",
|
||||
r"英伟达|nvidia.*(?:跌|调查|制裁|推迟|禁令)",
|
||||
r"(?:英伟达|nvidia).*(?:跌|调查|制裁|推迟|禁令)",
|
||||
r"台积电.*(?:跌|推迟|取消|地震|火灾|禁)",
|
||||
r"特斯拉.*(?:暴跌|召回|调查|破产|禁)",
|
||||
# 美联储/央行意外
|
||||
r"美联储.*(?:意外|紧急|缩表|风暴|警告|超预期|加息\s*50|降息\s*50|紧急\s*(?:会议|声明))",
|
||||
r"美联储.*(?:利率|决议).*(?:超预期|意外|紧急)",
|
||||
r"fed.*(?:emergency|unexpected|surprise|hike|cut)",
|
||||
# 指数暴跌
|
||||
r"指数.*(?:跌幅|暴跌|熔断|闪崩|重挫)",
|
||||
r"(?:暴跌|重挫|熔断).*[5-9]%",
|
||||
# 指数暴跌(针对主要指数,避免'板块指数跌幅居前'等非风险匹配)
|
||||
r"(?:上证|深证|创业板|科创|恒生指数|恒指|日经|KOSPI|道指|纳指|标普500|沪深300).*(?:暴跌|重挫|熔断|闪崩|跳水|跌幅(?!.*?居前))",
|
||||
r"指数.*(?:暴跌|熔断|闪崩)",
|
||||
r"熔断|闪崩",
|
||||
# 地缘+贸易
|
||||
r"关税.*(?:升级|新|报复|制裁)",
|
||||
r"制裁.*(?:新|升级|全面)",
|
||||
r"战争|开战|入侵|核|导弹.*发射",
|
||||
# 战争/地缘: 移除过宽的'核'/'战争'独立匹配,避免'核聚变''硬核科技''核心''贸易战'误触
|
||||
r"(?:地缘|边境|朝鲜|伊朗).*(?:冲突|风险|升级|紧张|军事行动|交火)|开战|开火|空袭|轰炸|入侵|击落|军事(?:冲突|行动|升级|打击|对抗|演习|部署)|核(?:威胁|武器|弹头|试验|攻击|冲突|导弹|战争|潜艇|问题|危机|设施)|导弹.*(?:发射|试射|打击)",
|
||||
# 系统性能源
|
||||
r"原油.*(?:跌破|暴跌|崩盘|断供)",
|
||||
r"石油.*(?:禁运|制裁|断供)",
|
||||
r"能源危机|粮食危机",
|
||||
# 系统金融
|
||||
r"银行.*(?:倒闭|挤兑|破产|接管|危机)",
|
||||
r"金融危机|债务危机|违约潮|系统性",
|
||||
r"金融危机|债务危机|违约潮|系统性(?:风险|危机|金融|下跌|崩塌)",
|
||||
# AI/科技板块重挫
|
||||
r"半导体.*(?:暴跌|熔断|崩盘|跌幅)",
|
||||
r"科技股.*(?:暴跌|熔断|崩盘|重挫)",
|
||||
|
||||
@@ -708,6 +708,7 @@ def main():
|
||||
sig = d.get("timing_signal", "")
|
||||
sector = d.get("sector_context", "")
|
||||
tech = d.get("tech_snapshot", "")
|
||||
mtf_ctx = d.get("multi_tf_context", "")
|
||||
note = d.get("note", "")
|
||||
d_factors = d.get("signal_factors", [])
|
||||
cat = d.get("stock_category", "")
|
||||
@@ -807,6 +808,9 @@ def main():
|
||||
f" 仓位:理论{theo_pct}%×总资产 | 建议{actual_pct}%({details})"
|
||||
)
|
||||
|
||||
if mtf_ctx:
|
||||
lines[-1] += f"\n 均线{mtf_ctx}"
|
||||
|
||||
if swap_text:
|
||||
lines[-1] += f"\n {swap_text}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user