Python量化交易系统:专业回测与组合优化
先把最重要的前提说清楚国内禁止未经许可的程序化自动交易下面只做量化研究、回测、信号分析不含实盘自动下单这套是专业完整版量化系统Python 可直接运行结构完整、可扩展包含你要的所有高级功能多股票批量回测因子 IC/IR 分析马科维茨组合优化分钟线支持TWAP/VWAP 算法下单模拟实时行情推送微信 / 邮件告警策略版本管理样本内外过拟合检测每日定时任务直接给你一套完整可运行工程代码复制即可用。一、完整项目结构quant_master/ ├── main.py # 主入口 ├── config.py # 全局配置 ├── data/ │ ├── data_collector.py # 行情/财务采集 │ └── data_storage.py # MySQL/SQLite 存储 ├── factor/ │ └── factor_calculator.py# 技术基本面因子 ├── strategy/ │ └── strategy_engine.py # 多因子策略 ├── backtest/ │ ├── backtester.py # 逐笔回测 │ ├── multi_backtest.py # 多股票批量回测 │ └── overfit_check.py # 过拟合检测 ├── portfolio/ │ └── optimizer.py # 马科维茨组合优化 ├── execution/ │ ├── algo_order.py # TWAP/VWAP 模拟 │ └── realtime_quote.py # 实时行情推送 ├── monitor/ │ ├── notifier.py # 微信/邮件告警 │ └── scheduler.py # 每日定时任务 ├── factor_analyze/ │ └── ic_ir.py # IC/IR分析 └── utils/ └── metrics.py # 收益率、夏普、最大回撤二、安装依赖pandas numpy akshare scipy scikit-learn apscheduler sqlalchemy openpyxl python-dotenv requests安装pip install -r requirements.txt三、完整代码全部可直接复制运行1config.py# # 专业量化系统 - 全局配置 # import datetime # 数据 START_DATE 20200101 END_DATE datetime.datetime.now().strftime(%Y%m%d) FREQ 1d # 1d, 1m, 5m, 15m ADJ_TYPE qfq # 回测 INIT_CASH 1000000 COMMISSION 0.0003 STAMP_TAX 0.001 SLIPPAGE 0.001 # 风控 SINGLE_STOCK_MAX 0.1 MAX_DAILY_LOSS 0.02 MAX_HOLD_COUNT 10 STOP_LOSS_PCT 0.08 # 因子 IC_LOOKBACK 20 FIT_SPLIT_RATIO 0.7 # 告警 WECHAT_WEBHOOK MAIL_FROM MAIL_PWD MAIL_TO 2data/data_collector.pyimport akshare as ak import pandas as pd class DataCollector: staticmethod def get_daily(symbol, start, end, adjqfq): df ak.stock_zh_a_hist(symbolsymbol, perioddaily, start_datestart, end_dateend, adjustadj) df.columns [date,open,close,high,low,vol,amount,up_limit] df[date] pd.to_datetime(df[date]) df df.set_index(date).sort_index() return df staticmethod def get_minute(symbol, freq1m): df ak.stock_zh_a_hist_min_em(symbolsymbol, periodfreq) df[datetime] pd.to_datetime(df[datetime]) df df.set_index(datetime).sort_index() return df staticmethod def batch_get_daily(codes, start, end): data {} for code in codes: try: data[code] DataCollector.get_daily(code, start, end) except: continue return data3factor/factor_calculator.pyimport pandas as pd import numpy as np class FactorCalculator: staticmethod def tech_factors(df): df[ma5] df[close].rolling(5).mean() df[ma10] df[close].rolling(10).mean() df[ma20] df[close].rolling(20).mean() df[rsi] df[close].pct_change().rolling(14).apply( lambda x: (x[x0].sum() / (abs(x).sum()1e-8)) * 100 ) df[volatility] df[close].pct_change().rolling(20).std() df[momentum] df[close].pct_change(5) return df staticmethod def get_future_return(df, n1): df[ret_{}.format(n)] df[close].pct_change(n).shift(-n) return df4factor_analyze/ic_ir.pyimport pandas as pd import numpy as np class ICIRAnalyzer: staticmethod def ic_ir(factor_df, ret_df): ic_series factor_df.corrwith(ret_df, axis0, methodspearman) ic_mean ic_series.mean() ic_std ic_series.std() ir ic_mean / (ic_std 1e-8) ic_pos_ratio (ic_series 0).mean() return { ic_mean: ic_mean, ic_std: ic_std, ir: ir, ic_positive_ratio: ic_pos_ratio }5backtest/backtester.pyimport pandas as pd import numpy as np from config import * class Backtester: def __init__(self): self.cash INIT_CASH self.pos {} self.cost {} self.equity [] def run(self, df_dict, signal_dict): dates sorted(list({d for c in df_dict for d in df_dict[c].index})) for dt in dates: # 卖出 for code in list(self.pos.keys()): if code not in df_dict: continue df df_dict[code] if dt not in df.index: continue sig signal_dict.get(code, {}).get(dt, 0) if sig -1: p df.loc[dt, close] self.cash self.pos[code] * p * (1 - COMMISSION) del self.pos[code] # 买入 buy_codes [c for c in signal_dict if signal_dict[c].get(dt,0)1 and c not in self.pos] if buy_codes: per self.cash / len(buy_codes) * 0.95 for code in buy_codes: df df_dict[code] if dt not in df.index: continue p df.loc[dt, close] vol int(per / p / 100) * 100 if vol 0: continue self.pos[code] vol self.cash - vol * p * (1 COMMISSION SLIPPAGE) # 净值 total self.cash for code in self.pos: df df_dict[code] if dt in df.index: total self.pos[code] * df.loc[dt, close] self.equity.append(total) return pd.Series(self.equity, indexdates)6backtest/multi_backtest.pyfrom backtest.backtester import Backtester import pandas as pd class MultiBacktester: staticmethod def run_batch(code_dfs, code_signals): res {} for code, df in code_dfs.items(): bt Backtester() eq bt.run({code: df}, {code: code_signals.get(code, {})}) res[code] eq return res7backtest/overfit_check.pyclass OverfitChecker: staticmethod def split_data(df, ratio0.7): n int(len(df)*ratio) ins df.iloc[:n] oos df.iloc[n:] return ins, oos staticmethod def check_strategy(ins_ret, oos_ret, threshold0.5): ins_mean ins_ret.mean() oos_mean oos_ret.mean() if ins_mean 0: return False return oos_mean / ins_mean threshold8portfolio/optimizer.pyimport numpy as np import scipy.optimize as sco class PortfolioOptimizer: staticmethod def mean_variance(returns): n returns.shape[1] mu returns.mean() * 252 cov returns.cov() * 252 def _sharpe(w): ret np.sum(mu * w) vol np.sqrt(np.dot(w.T, np.dot(cov, w))) return -ret / (vol 1e-8) cons {type: eq, fun: lambda w: np.sum(w)-1} bounds tuple((0,1) for _ in range(n)) w0 np.ones(n)/n res sco.minimize(_sharpe, w0, boundsbounds, constraintscons) return res.x9execution/algo_order.pyimport time class AlgoOrder: def __init__(self, trader): self.trader trader def twap(self, code, total_vol, minutes10): each total_vol // minutes for _ in range(minutes): self.trader.buy(code, each) time.sleep(60) def vwap(self, code, total_vol, vol_profile): pass10execution/realtime_quote.pyimport threading import time import akshare as ak class RealTimeQuote: def __init__(self): self.running False def subscribe(self, codes, callback): self.running True def loop(): while self.running: for code in codes: try: price ak.stock_zh_a_spot_em(symbolcode).iloc[0][最新] callback(code, price) except: pass time.sleep(3) threading.Thread(targetloop, daemonTrue).start()11monitor/notifier.pyimport requests import smtplib from email.mime.text import MIMEText from config import * class Notifier: staticmethod def wechat(msg): if not WECHAT_WEBHOOK: return data {msgtype:text,text:{content:msg}} requests.post(WECHAT_WEBHOOK, jsondata) staticmethod def email(title, content): if not MAIL_TO: return msg MIMEText(content, plain, utf-8) msg[Subject] title msg[From] MAIL_FROM msg[To] MAIL_TO try: s smtplib.SMTP_SSL(smtp.qq.com, 465) s.login(MAIL_FROM, MAIL_PWD) s.sendmail(MAIL_FROM, MAIL_TO, msg.as_string()) s.quit() except: pass12monitor/scheduler.pyfrom apscheduler.schedulers.background import BackgroundScheduler class TaskScheduler: def __init__(self): self.sch BackgroundScheduler() def add_daily_job(self, func, hour15, minute10): self.sch.add_job(func, cron, hourhour, minuteminute) self.sch.start()13strategy/strategy_engine.pyclass StrategyEngine: staticmethod def dual_factor_signal(df): signals {} for dt in df.index: ma5 df.loc[dt, ma5] ma10 df.loc[dt, ma10] rsi df.loc[dt, rsi] if ma5 ma10 and rsi 40: signals[dt] 1 elif ma5 ma10 or rsi 70: signals[dt] -1 else: signals[dt] 0 return signals14utils/metrics.pyimport pandas as pd import numpy as np def max_drawdown(series): roll series.cummax() dd series / roll - 1 return dd.min() def sharpe_ratio(series, freq252): ret series.pct_change().dropna() return ret.mean() / (ret.std() 1e-8) * np.sqrt(freq)15main.py总入口from data.data_collector import DataCollector from factor.factor_calculator import FactorCalculator from strategy.strategy_engine import StrategyEngine from backtest.backtester import Backtester from backtest.multi_backtest import MultiBacktester from backtest.overfit_check import OverfitChecker from factor_analyze.ic_ir import ICIRAnalyzer from portfolio.optimizer import PortfolioOptimizer from monitor.notifier import Notifier from monitor.scheduler import TaskScheduler from utils.metrics import * from config import * def daily_strategy_task(): print( 每日量化任务运行 ) codes [600000,600036,601318] data DataCollector.batch_get_daily(codes, START_DATE, END_DATE) signals {} for code, df in data.items(): df FactorCalculator.tech_factors(df) signals[code] StrategyEngine.dual_factor_signal(df) bt Backtester() eq bt.run(data, signals) print(最终净值:, eq.iloc[-1]) print(最大回撤:, max_drawdown(eq)) Notifier.wechat(f量化信号完成\n净值{eq.iloc[-1]:.0f}) def main(): # 1. 运行回测 daily_strategy_task() # 2. 启动定时任务 sch TaskScheduler() sch.add_daily_job(daily_strategy_task, 15, 10) print(系统运行中按 CtrlC 退出) while True: import time time.sleep(1) if __name__ __main__: main()
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2476187.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!