整理 course 目录:原课程归入同名文件夹,新增学习资料/动手练习分类
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""量化练习公共库:数据获取(带缓存+重试) + 常用指标 + 回测指标。"""
|
||||
import os, time, pandas as pd, numpy as np
|
||||
|
||||
CACHE = os.path.join(os.path.dirname(__file__), "..", "data", "cache")
|
||||
os.makedirs(CACHE, exist_ok=True)
|
||||
|
||||
def _fetch(symbol, start, end, adjust, retries=6, wait=2.0):
|
||||
import akshare as ak
|
||||
last = None
|
||||
for i in range(retries):
|
||||
try:
|
||||
return ak.stock_zh_a_hist(symbol=symbol, period="daily",
|
||||
start_date=start, end_date=end, adjust=adjust)
|
||||
except Exception as e: # 网络间歇性抽风,重试
|
||||
last = e
|
||||
time.sleep(wait * (i + 1))
|
||||
raise last
|
||||
|
||||
def get_daily(symbol="000001", start="20200101", end="20241231", adjust="qfq"):
|
||||
"""拉单只A股日线(前复权),带本地缓存与自动重试。"""
|
||||
f = os.path.join(CACHE, f"{symbol}_{start}_{end}_{adjust}.csv")
|
||||
if os.path.exists(f):
|
||||
return pd.read_csv(f, parse_dates=["日期"])
|
||||
df = _fetch(symbol, start, end, adjust)
|
||||
df.to_csv(f, index=False, encoding="utf-8-sig")
|
||||
return df
|
||||
|
||||
def add_returns(df, price_col="收盘"):
|
||||
df = df.copy()
|
||||
df["ret"] = df[price_col].pct_change().fillna(0.0)
|
||||
return df
|
||||
|
||||
def net_value(ret):
|
||||
return (1 + pd.Series(ret).fillna(0.0)).cumprod()
|
||||
|
||||
def stats(ret, periods=252):
|
||||
ret = pd.Series(ret).fillna(0.0)
|
||||
nv = net_value(ret); total = nv.iloc[-1] - 1
|
||||
ann = (1 + total) ** (periods / max(len(ret), 1)) - 1
|
||||
vol = ret.std() * np.sqrt(periods)
|
||||
sharpe = (ret.mean() * periods) / vol if vol > 0 else np.nan
|
||||
dd = (nv / nv.cummax() - 1).min()
|
||||
calmar = ann / abs(dd) if dd < 0 else np.nan
|
||||
return {"总收益": f"{total:.2%}", "年化": f"{ann:.2%}", "年化波动": f"{vol:.2%}",
|
||||
"夏普": f"{sharpe:.2f}", "最大回撤": f"{dd:.2%}", "卡玛": f"{calmar:.2f}"}
|
||||
|
||||
def max_drawdown(nv):
|
||||
return (nv / nv.cummax() - 1).min()
|
||||
Reference in New Issue
Block a user