千问AI:区间涨幅动量轮动(3)
现在AI已经牛到,你只需要讲中文,给他一些知识库的内容,他就可以给你写量化策略,然后按照你的要求做优化和提升。
对AI的任务需求:
用akshare数据源写一个ETF趋势交易的轮动策略
豆包提示词:
#通过Akshare获取数据源,返回字段 date open high low close volume,5开头的基金是sh,1开头的基金是sz,把里面的条件尽量参数化
import akshare as ak
fund_etf_hist_sina_df = ak.fund_etf_hist_sina(symbol="sh510050")
print(fund_etf_hist_sina_df)
plt.rcParams["font.family"] = ["SimHei"]

import akshare as ak
import pandas as pd
import numpy as np
import time
# ========== 配置参数 ==========
etf_pool = [
"sh510300", # 沪深300ETF
"sh510500", # 中证500ETF
"sh512880", # 证券ETF
"sh512660", # 军工ETF
"sh513500", # 标普500ETF
"sh513100", # 纳指ETF
"sh513130", # 恒生科技ETF
"sz159915", # 创业板ETF
]
start_year = 2018
end_date_str = "2025-11-01"
momentum_window = 20 # 动量窗口(交易日)
top_k = 1 # 选Top 1
# ========== 获取数据 ==========
etf_data_dict = {}
for symbol in etf_pool:
try:
print(f"正在获取 {symbol} 数据...")
df = ak.fund_etf_hist_sina(symbol=symbol)
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
df.sort_index(inplace=True)
etf_data_dict[symbol] = df
time.sleep(0.3)
except Exception as e:
print(f"❌ 获取 {symbol} 失败: {e}")
# ========== 构建价格矩阵 ==========
all_dates = sorted(set.union(*[set(df.index) for df in etf_data_dict.values()]))
price_df = pd.DataFrame(index=all_dates)
for symbol, df in etf_data_dict.items():
price_df[symbol] = df['close']
price_df = price_df.loc[f"{start_year}-01-01":end_date_str].sort_index().ffill().dropna(how='all')
price_df.dropna(how='all', inplace=True)
if price_df.empty:
raise ValueError("价格数据为空,请检查ETF代码或网络")
# ========== 找出每周第一个交易日 ==========
trading_days = price_df.index
rebalance_dates = []
for i, date in enumerate(trading_days):
if i == 0:
rebalance_dates.append(date)
else:
prev = trading_days[i - 1]
if date.week != prev.week or date.year != prev.year:
rebalance_dates.append(date)
weekly_rebalance_dates = pd.DatetimeIndex(rebalance_dates)
# ========== 初始化持仓序列(修复版)==========
position_series = pd.Series([[] for _ in range(len(price_df))], index=price_df.index)
# ========== 执行每周调仓 ==========
for date in weekly_rebalance_dates:
lookback_start = date - pd.Timedelta(days=momentum_window * 2)
window_data = price_df.loc[lookback_start:date]
if len(window_data) < momentum_window:
continue
returns = (window_data.iloc[-1] / window_data.iloc[0]) - 1
returns = returns.dropna()
if returns.empty:
continue
top_symbols = returns.nlargest(top_k).index.tolist()
position_series[date] = top_symbols
# 向前填充持仓
position_series.ffill(inplace=True)
# ========== 计算策略收益 ==========
strategy_ret = pd.Series(index=price_df.index, dtype=float)
strategy_ret.iloc[0] = 0.0
for i in range(1, len(price_df)):
today = price_df.index[i]
yesterday = price_df.index[i - 1]
holdings = position_series[today]
if not holdings:
strategy_ret[today] = 0.0
else:
daily_rtn = 0.0
valid_count = 0
weight = 1.0 / len(holdings)
for sym in holdings:
if pd.notna(price_df.loc[yesterday, sym]) and pd.notna(price_df.loc[today, sym]):
ret = price_df.loc[today, sym] / price_df.loc[yesterday, sym] - 1
daily_rtn += weight * ret
valid_count += 1
strategy_ret[today] = daily_rtn if valid_count > 0 else 0.0
strategy_nav = (1 + strategy_ret).cumprod()
# ========== 基准 ==========
benchmark_symbol = "sh510300"
benchmark_nav = price_df[benchmark_symbol] / price_df[benchmark_symbol].iloc[0]
# ========== 输出结果 ==========
def annual_return(nav, freq=252): return nav.iloc[-1] ** (freq / len(nav)) - 1
def max_drawdown(nav):
rm = nav.cummax()
return ((nav - rm) / rm).min()
print(f"策略年化收益: {annual_return(strategy_nav):.2%}")
print(f"基准年化收益: {annual_return(benchmark_nav):.2%}")
print(f"策略最大回撤: {max_drawdown(strategy_nav):.2%}")
print(f"调仓次数: {len(weekly_rebalance_dates)}")
# ========== 绘图 ==========
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(strategy_nav, label='每周轮动策略')
plt.plot(benchmark_nav, label='沪深300ETF')
plt.legend()
plt.title('ETF 趋势轮动策略(每周一调仓 | sina 数据源)')
plt.grid(True)
plt.show()
策略年化收益: 42.85%
基准年化收益: 1.87%
策略最大回撤: -16.83%
调仓次数: 403
上一篇:安装本地的Python运行环境 下一篇:动量策略为啥有时候会失效?
次方量化-技术博客
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。