Files
lianghua/fix_fetchers.py
T

152 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""修复 fetcherfund_flow 单位乘数+保历史;macro 按列名映射+保历史;stock_api 全量历史+保历史"""
import io
ROOT = r'C:\Users\lookt\a_stock_timeline'
def read(p):
return io.open(p, encoding='utf-8').read()
def write(p, s):
io.open(p, 'w', encoding='utf-8').write(s)
print('patched:', p.split('a_stock_timeline')[-1])
NL = chr(10)
UP = 'from src.storage.db import upsert_df, upsert_rows, upsert_log, get_last_fetch'
UP_OLD = 'from src.storage.db import upsert_df, upsert_log, get_last_fetch'
# ── 2) fund_flow_fetcher ──
p = ROOT + r'\src\fetcher\fund_flow_fetcher.py'
s = read(p)
if 'def parse_cn_amount' not in s:
s = s.replace(UP_OLD, UP)
helper = NL.join([
"DB = r'C:" + chr(92) + "Users" + chr(92) + "lookt" + chr(92) + "a_stock_timeline"
+ chr(92) + "data" + chr(92) + "a_stock.db'",
"",
"",
"def parse_cn_amount(v):",
" '''1.5亿 -> 1.5e8, -300万 -> -3e6,逗号/空白容错;无效返回 None'''",
" if v is None or (isinstance(v, float) and v != v):",
" return None",
" s = str(v).replace(',', '').replace(' ', '').strip()",
" if not s or s in ('--', '-', 'nan'):",
" return None",
" mult = 1.0",
" if s.endswith('亿'):",
" mult, s = 1e8, s[:-1]",
" elif s.endswith('万'):",
" mult, s = 1e4, s[:-1]",
" try:",
" return float(s) * mult",
" except ValueError:",
" return None",
""])
marker = "DB = r'C:" + chr(92) + "Users" + chr(92) + "lookt" + chr(92) + "a_stock_timeline" + chr(92) + "data" + chr(92) + "a_stock.db'" + NL
s = s.replace(marker, helper, 1)
old = NL.join([
" # 主力净流入转数值(去掉\"\"/\"亿\"",
" df_ind['main_net_in'] = (df_ind['main_net_in'].astype(str)",
" .str.replace(r'[\\u4e00-\\u9fa5万/亿]', '', regex=True))",
" df_ind['main_net_in'] = pd.to_numeric(df_ind['main_net_in'], errors='coerce')"])
new = NL.join([
" # 主力净流入转数值:亿=1e8 万=1e4(带乘数换算)",
" df_ind['main_net_in'] = df_ind['main_net_in'].map(parse_cn_amount)",
" df_ind = df_ind[df_ind['main_net_in'].notna()]"])
if old in s:
s = s.replace(old, new)
old2 = NL.join([
" df = pd.concat(rows, ignore_index=True)",
" conn = sqlite3.connect(DB)",
" df.to_sql('money_flow', conn, if_exists='replace', index=False)",
" conn.close()",
" log.info(f'写入 money_flow: {len(df)} 行')",
" return df"])
new2 = NL.join([
" df = pd.concat(rows, ignore_index=True)",
" need = ['ts_code', 'trade_date', 'main_net_in',",
" 'large_net_in', 'medium_net_in', 'small_net_in']",
" for c in need:",
" if c not in df.columns:",
" df[c] = None",
" n = upsert_rows(df[need], 'money_flow', conflict_cols=['ts_code', 'trade_date'])",
" log.info(f'写入 money_flow: {n} 行(历史保留)')",
" return df"])
if old2 in s:
s = s.replace(old2, new2)
write(p, s)
# ── 3) macro_event_fetcher ──
p = ROOT + r'\src\fetcher\macro_event_fetcher.py'
s = read(p)
s = s.replace(UP_OLD, UP)
old = " df.columns = [c.lower() for c in df.columns]"
new = NL.join([
" # 实测列(akshare 1.18.92: 日期, 时间, 地区, 事件, 公布, 预期, 前值, 重要性",
" # 按列【名称】映射,避免位置错位",
" col_map = {'日期': 'event_date', '时间': 'event_time', '地区': 'source',",
" '事件': 'title', '公布': 'actual', '预期': 'forecast',",
" '前值': 'prev', '重要性': 'event_type'}",
" df = df.rename(columns=col_map)"])
if old in s:
s = s.replace(old, new, 1)
old2 = NL.join([
' df["event_type"] = df.get("importance", pd.Series([1] * len(df))).astype(int)',
' df["source"] = df.get("country", pd.Series([""] * len(df))).astype(str)'])
new2 = NL.join([
' df["event_type"] = pd.to_numeric(df["event_type"], errors="coerce").fillna(0).astype(int)',
' df["source"] = df["source"].fillna("").astype(str)'])
if old2 in s:
s = s.replace(old2, new2)
old3 = NL.join([
'def incremental_events(source: str = "macro_event") -> pd.DataFrame:',
' """增量采集宏观事件"""',
' # 优先 AkShare 财经日历(已知可用)',
' df = fetch_macro_calendar()',
' if df is not None and not df.empty:',
' upsert_df(df, source)',
' upsert_log(source, "", last_date=datetime.today().strftime("%Y-%m-%d"))',
' return df'])
new3 = NL.join([
'def incremental_events(source: str = "macro_event") -> pd.DataFrame:',
' """增量采集宏观事件(按 event_date+event_time+title 去重,历史保留)"""',
' df = fetch_macro_calendar()',
' if df is not None and not df.empty:',
" need = [c for c in ['event_date', 'event_time', 'title', 'event_type', 'source',",
" 'actual', 'forecast', 'prev', 'inserted_at'] if c in df.columns]",
" upsert_rows(df[need], source,",
" conflict_cols=['event_date', 'event_time', 'title'])",
' upsert_log(source, "", last_date=datetime.today().strftime("%Y-%m-%d"))',
' return df'])
if old3 in s:
s = s.replace(old3, new3)
write(p, s)
# ── 4) stock_api ──
p = ROOT + r'\src\fetcher\stock_api.py'
s = read(p)
s = s.replace(UP_OLD, UP)
old = NL.join([
" df = batch_fetch_indices(days=days)",
" if df is not None and not df.empty:",
' upsert_df(df, "stock_daily")'])
new = NL.join([
" df = batch_fetch_indices(days=days)",
" if df is not None and not df.empty:",
' upsert_rows(df, "stock_daily", conflict_cols=["ts_code", "trade_date"])'])
if old in s:
s = s.replace(old, new)
old_b = NL.join([
" df = fetch_daily(code, start, end)",
" if df is not None and not df.empty:",
' upsert_df(df, "stock_daily")'])
new_b = NL.join([
" df = fetch_daily(code, start, end)",
" if df is not None and not df.empty:",
' upsert_rows(df, "stock_daily", conflict_cols=["ts_code", "trade_date"])'])
if old_b in s:
s = s.replace(old_b, new_b)
write(p, s)
print('ALL FETCHER PATCHES DONE')