新增建材价格指数趋势监控仪表盘
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""拉取建材价格指数,更新 data.json 并刷新 index.html。"""
|
||||
import json
|
||||
import pandas as pd
|
||||
import akshare as ak
|
||||
|
||||
df = ak.macro_china_construction_index()
|
||||
df['日期'] = pd.to_datetime(df['日期'])
|
||||
df = df.sort_values('日期').reset_index(drop=True)
|
||||
|
||||
for w in [5, 10, 20, 60]:
|
||||
df[f'MA{w}'] = df['最新值'].rolling(w).mean().round(1)
|
||||
df[f'MA{w}_dir'] = df[f'MA{w}'].diff().apply(lambda x: 'up' if x > 0 else ('down' if x < 0 else 'flat'))
|
||||
|
||||
latest = df.iloc[-1]
|
||||
|
||||
signals = []
|
||||
if latest['最新值'] > latest['MA5']:
|
||||
signals.append(('短期', '偏多', '价格 > MA5'))
|
||||
else:
|
||||
signals.append(('短期', '偏空', '价格 < MA5'))
|
||||
if latest['MA5'] > latest['MA20']:
|
||||
signals.append(('中期', '偏多', 'MA5 > MA20'))
|
||||
else:
|
||||
signals.append(('中期', '偏空', 'MA5 < MA20'))
|
||||
if latest['MA20'] > latest['MA60']:
|
||||
signals.append(('长期', '偏多', 'MA20 > MA60'))
|
||||
else:
|
||||
signals.append(('长期', '偏空', 'MA20 < MA60'))
|
||||
|
||||
momentum_5d = latest['最新值'] - df.iloc[-6]['最新值']
|
||||
signals.append(('动量(5日)', '偏多' if momentum_5d > 0 else '偏空', f"{momentum_5d:+d}"))
|
||||
|
||||
bull_count = sum(1 for _, s, _ in signals if s == '偏多')
|
||||
if bull_count >= 3:
|
||||
overall = ('偏多', '#16a34a')
|
||||
elif bull_count <= 1:
|
||||
overall = ('偏空', '#dc2626')
|
||||
else:
|
||||
overall = ('震荡', '#d97706')
|
||||
|
||||
summary = {
|
||||
'date': latest['日期'].strftime('%Y-%m-%d'),
|
||||
'value': int(latest['最新值']),
|
||||
'change': round(float(latest['涨跌幅']), 4),
|
||||
'chg_3m': round(float(latest['近3月涨跌幅']), 4),
|
||||
'chg_6m': round(float(latest['近6月涨跌幅']), 4),
|
||||
'chg_1y': round(float(latest['近1年涨跌幅']), 4),
|
||||
}
|
||||
|
||||
mas = {}
|
||||
for w in [5, 10, 20, 60]:
|
||||
mas[f'MA{w}'] = {
|
||||
'value': float(latest[f'MA{w}']),
|
||||
'direction': latest[f'MA{w}_dir'],
|
||||
'price_vs_ma': 'above' if latest['最新值'] > latest[f'MA{w}'] else 'below'
|
||||
}
|
||||
|
||||
rows = []
|
||||
for _, r in df.tail(30).iterrows():
|
||||
rows.append({
|
||||
'date': r['日期'].strftime('%m-%d'),
|
||||
'value': int(r['最新值']),
|
||||
'chg': round(float(r['涨跌幅']), 4),
|
||||
'MA5': None if pd.isna(r['MA5']) else round(float(r['MA5']), 1),
|
||||
'MA20': None if pd.isna(r['MA20']) else round(float(r['MA20']), 1),
|
||||
'MA60': None if pd.isna(r['MA60']) else round(float(r['MA60']), 1),
|
||||
})
|
||||
|
||||
output = {
|
||||
'summary': summary,
|
||||
'mas': mas,
|
||||
'signals': [{'period': p, 'signal': s, 'detail': d} for p, s, d in signals],
|
||||
'overall': {'signal': overall[0], 'color': overall[1]},
|
||||
'recent': rows,
|
||||
}
|
||||
|
||||
with open('data.json', 'w') as f:
|
||||
json.dump(output, f, ensure_ascii=False, indent=2)
|
||||
|
||||
SENTINEL = '/*__DATA_SENTINEL__*/{}'
|
||||
html = open('index.html').read()
|
||||
html = html.replace(SENTINEL, json.dumps(output, ensure_ascii=False))
|
||||
open('index.html', 'w').write(html)
|
||||
|
||||
print(f"刷新完成: {summary['date']} → {summary['value']} (日涨跌 {summary['change']:+.2f}%)")
|
||||
print(f"综合信号: {overall[0]}")
|
||||
print("信号明细:")
|
||||
for p, s, d in signals:
|
||||
print(f" {p}: {s} ({d})")
|
||||
Reference in New Issue
Block a user