diff --git a/建材指数监控/data.json b/建材指数监控/data.json new file mode 100644 index 0000000..12af6c5 --- /dev/null +++ b/建材指数监控/data.json @@ -0,0 +1,300 @@ +{ + "summary": { + "date": "2026-07-23", + "value": 915, + "change": 0.2191, + "chg_3m": 0.6601, + "chg_6m": 5.5363, + "chg_1y": -1.507 + }, + "mas": { + "MA5": { + "value": 913.4, + "direction": "up", + "price_vs_ma": "above" + }, + "MA10": { + "value": 911.6, + "direction": "up", + "price_vs_ma": "above" + }, + "MA20": { + "value": 906.2, + "direction": "up", + "price_vs_ma": "above" + }, + "MA60": { + "value": 911.1, + "direction": "down", + "price_vs_ma": "above" + } + }, + "signals": [ + { + "period": "短期", + "signal": "偏多", + "detail": "价格 > MA5" + }, + { + "period": "中期", + "signal": "偏多", + "detail": "MA5 > MA20" + }, + { + "period": "长期", + "signal": "偏空", + "detail": "MA20 < MA60" + }, + { + "period": "动量(5日)", + "signal": "偏多", + "detail": "+3" + } + ], + "overall": { + "signal": "偏多", + "color": "#16a34a" + }, + "recent": [ + { + "date": "06-24", + "value": 901, + "chg": -0.2215, + "MA5": 905.8, + "MA20": 914.2, + "MA60": 920.5 + }, + { + "date": "06-25", + "value": 900, + "chg": -0.111, + "MA5": 904.0, + "MA20": 913.1, + "MA60": 920.4 + }, + { + "date": "06-26", + "value": 897, + "chg": -0.3333, + "MA5": 901.6, + "MA20": 911.9, + "MA60": 920.1 + }, + { + "date": "06-27", + "value": 896, + "chg": -0.1115, + "MA5": 899.4, + "MA20": 910.6, + "MA60": 919.8 + }, + { + "date": "06-28", + "value": 896, + "chg": 0.0, + "MA5": 898.0, + "MA20": 909.4, + "MA60": 919.5 + }, + { + "date": "06-29", + "value": 899, + "chg": 0.3348, + "MA5": 897.6, + "MA20": 908.6, + "MA60": 919.2 + }, + { + "date": "06-30", + "value": 898, + "chg": -0.1112, + "MA5": 897.2, + "MA20": 907.6, + "MA60": 918.8 + }, + { + "date": "07-01", + "value": 898, + "chg": 0.0, + "MA5": 897.4, + "MA20": 906.6, + "MA60": 918.4 + }, + { + "date": "07-02", + "value": 898, + "chg": 0.0, + "MA5": 897.8, + "MA20": 905.6, + "MA60": 918.1 + }, + { + "date": "07-03", + "value": 899, + "chg": 0.1114, + "MA5": 898.4, + "MA20": 904.6, + "MA60": 917.7 + }, + { + "date": "07-04", + "value": 899, + "chg": 0.0, + "MA5": 898.4, + "MA20": 903.6, + "MA60": 917.4 + }, + { + "date": "07-05", + "value": 899, + "chg": 0.0, + "MA5": 898.6, + "MA20": 902.8, + "MA60": 917.0 + }, + { + "date": "07-06", + "value": 898, + "chg": -0.1112, + "MA5": 898.6, + "MA20": 901.9, + "MA60": 916.6 + }, + { + "date": "07-07", + "value": 901, + "chg": 0.3341, + "MA5": 899.2, + "MA20": 901.2, + "MA60": 916.2 + }, + { + "date": "07-08", + "value": 899, + "chg": -0.222, + "MA5": 899.2, + "MA20": 900.8, + "MA60": 915.7 + }, + { + "date": "07-09", + "value": 900, + "chg": 0.1112, + "MA5": 899.4, + "MA20": 900.3, + "MA60": 915.3 + }, + { + "date": "07-10", + "value": 903, + "chg": 0.3333, + "MA5": 900.2, + "MA20": 900.0, + "MA60": 915.0 + }, + { + "date": "07-11", + "value": 903, + "chg": 0.0, + "MA5": 901.2, + "MA20": 899.7, + "MA60": 914.5 + }, + { + "date": "07-12", + "value": 903, + "chg": 0.0, + "MA5": 901.6, + "MA20": 899.5, + "MA60": 914.1 + }, + { + "date": "07-13", + "value": 904, + "chg": 0.1107, + "MA5": 902.6, + "MA20": 899.6, + "MA60": 913.7 + }, + { + "date": "07-14", + "value": 905, + "chg": 0.1106, + "MA5": 903.6, + "MA20": 899.8, + "MA60": 913.3 + }, + { + "date": "07-15", + "value": 908, + "chg": 0.3315, + "MA5": 904.6, + "MA20": 900.2, + "MA60": 913.0 + }, + { + "date": "07-16", + "value": 912, + "chg": 0.4405, + "MA5": 906.4, + "MA20": 900.9, + "MA60": 912.8 + }, + { + "date": "07-17", + "value": 912, + "chg": 0.0, + "MA5": 908.2, + "MA20": 901.7, + "MA60": 912.5 + }, + { + "date": "07-18", + "value": 912, + "chg": 0.0, + "MA5": 909.8, + "MA20": 902.5, + "MA60": 912.2 + }, + { + "date": "07-19", + "value": 912, + "chg": 0.0, + "MA5": 911.2, + "MA20": 903.2, + "MA60": 912.0 + }, + { + "date": "07-20", + "value": 914, + "chg": 0.2193, + "MA5": 912.4, + "MA20": 904.0, + "MA60": 911.7 + }, + { + "date": "07-21", + "value": 913, + "chg": -0.1094, + "MA5": 912.6, + "MA20": 904.7, + "MA60": 911.5 + }, + { + "date": "07-22", + "value": 913, + "chg": 0.0, + "MA5": 912.8, + "MA20": 905.4, + "MA60": 911.3 + }, + { + "date": "07-23", + "value": 915, + "chg": 0.2191, + "MA5": 913.4, + "MA20": 906.2, + "MA60": 911.1 + } + ] +} \ No newline at end of file diff --git a/建材指数监控/index.html b/建材指数监控/index.html new file mode 100644 index 0000000..e4abf56 --- /dev/null +++ b/建材指数监控/index.html @@ -0,0 +1,196 @@ + + + + + +建材价格指数 · 趋势监控 + + + + + + +

建材价格指数 · 趋势监控

+

+ + +
+
+
最新值
+
+
+
+
+
近3月涨跌
+
+
+
+
近6月涨跌
+
+
+
+
近1年涨跌
+
+
+
+ + +
+ + +

均线系统

+ + + +
均线数值方向价格位置
+ + +

近30日明细

+ + + +
日期指数日涨跌%MA5MA20MA60
+ +

数据来源:akshare macro_china_construction_index · 建材综合指数

+ + + + diff --git a/建材指数监控/refresh.py b/建材指数监控/refresh.py new file mode 100644 index 0000000..17ad9bd --- /dev/null +++ b/建材指数监控/refresh.py @@ -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})")