Initial commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
批量更新数据库中缺少财务指标的基本面数据
|
||||
"""
|
||||
import akshare as ak
|
||||
import pandas as pd
|
||||
import psycopg2
|
||||
from datetime import date, datetime
|
||||
import time
|
||||
|
||||
# 数据库配置
|
||||
DB_CONFIG = {
|
||||
'host': 'localhost',
|
||||
'port': 5432,
|
||||
'dbname': 'stock_app',
|
||||
'user': 'postgres',
|
||||
'password': 'xypg5432'
|
||||
}
|
||||
|
||||
def get_db():
|
||||
"""获取数据库连接"""
|
||||
try:
|
||||
conn = psycopg2.connect(**DB_CONFIG)
|
||||
return conn
|
||||
except Exception as e:
|
||||
print(f"数据库连接失败: {e}")
|
||||
return None
|
||||
|
||||
def get_stocks_need_update():
|
||||
"""获取需要更新财务指标的股票列表"""
|
||||
conn = get_db()
|
||||
if not conn:
|
||||
return []
|
||||
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT code, name
|
||||
FROM stock_fundamental
|
||||
WHERE roe IS NULL OR eps IS NULL
|
||||
""")
|
||||
return cur.fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def fetch_financial_indicators(stock_code):
|
||||
"""从akshare获取股票财务指标"""
|
||||
try:
|
||||
df = ak.stock_financial_analysis_indicator(symbol=stock_code, start_year='2024')
|
||||
if df is None or df.empty:
|
||||
return None
|
||||
|
||||
latest = df.iloc[-1]
|
||||
|
||||
def safe_float(val):
|
||||
if pd.isna(val):
|
||||
return None
|
||||
try:
|
||||
return float(val)
|
||||
except:
|
||||
return None
|
||||
|
||||
return {
|
||||
'eps': safe_float(latest.get('摊薄每股收益(元)')),
|
||||
'bps': safe_float(latest.get('每股净资产_调整后(元)')),
|
||||
'roe': safe_float(latest.get('净资产收益率(%)')),
|
||||
'gross_margin': safe_float(latest.get('销售毛利率(%)')),
|
||||
'net_margin': safe_float(latest.get('销售净利率(%)')),
|
||||
'revenue_yoy': safe_float(latest.get('主营业务收入增长率(%)')),
|
||||
'profit_yoy': safe_float(latest.get('净利润增长率(%)')),
|
||||
}
|
||||
except Exception as e:
|
||||
print(f" 获取 {stock_code} 财务指标失败: {e}")
|
||||
return None
|
||||
|
||||
def update_stock_fundamental(stock_code, data):
|
||||
"""更新股票基本面数据"""
|
||||
conn = get_db()
|
||||
if not conn:
|
||||
return False
|
||||
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
UPDATE stock_fundamental
|
||||
SET roe = %s, eps = %s, bps = %s,
|
||||
revenue_yoy = %s, profit_yoy = %s,
|
||||
gross_margin = %s, net_margin = %s,
|
||||
updated_at = NOW()
|
||||
WHERE code = %s
|
||||
""", (
|
||||
data.get('roe'),
|
||||
data.get('eps'),
|
||||
data.get('bps'),
|
||||
data.get('revenue_yoy'),
|
||||
data.get('profit_yoy'),
|
||||
data.get('gross_margin'),
|
||||
data.get('net_margin'),
|
||||
stock_code
|
||||
))
|
||||
conn.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
print(f" 更新 {stock_code} 失败: {e}")
|
||||
return False
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print("批量更新基本面财务指标")
|
||||
print("=" * 50)
|
||||
|
||||
# 获取需要更新的股票
|
||||
stocks = get_stocks_need_update()
|
||||
print(f"\n需要更新的股票数量: {len(stocks)}")
|
||||
|
||||
if not stocks:
|
||||
print("所有股票财务指标已完整,无需更新")
|
||||
return
|
||||
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
|
||||
for i, (code, name) in enumerate(stocks, 1):
|
||||
print(f"\n[{i}/{len(stocks)}] 正在更新 {code} {name}...")
|
||||
|
||||
# 获取财务指标
|
||||
data = fetch_financial_indicators(code)
|
||||
|
||||
if data:
|
||||
# 更新数据库
|
||||
if update_stock_fundamental(code, data):
|
||||
print(f" ✓ 更新成功: EPS={data.get('eps')}, ROE={data.get('roe')}%")
|
||||
success_count += 1
|
||||
else:
|
||||
fail_count += 1
|
||||
else:
|
||||
print(f" ✗ 无法获取财务指标")
|
||||
fail_count += 1
|
||||
|
||||
# 避免请求过快
|
||||
time.sleep(0.5)
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print(f"更新完成! 成功: {success_count}, 失败: {fail_count}")
|
||||
print("=" * 50)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user