
1. 项目概述从零搭建一个可复用的选股框架如果你对量化投资感兴趣想自己动手写点策略但又觉得无从下手那今天聊的这个基于聚宽社区和jqdatasdk的简单选股策略可能就是你的第一块敲门砖。这玩意儿不是什么能预测未来的“圣杯”它的核心价值在于提供了一个清晰、完整、可运行的代码骨架让你能亲手把书本上的财务指标、技术指标变成一行行能跑出股票列表的代码。我见过太多新手卡在数据获取、回测框架对接这些前期准备上折腾半天热情就耗光了。而这个项目恰恰帮你绕过了这些“脏活累活”直接聚焦在策略逻辑本身——也就是你最该花心思的地方。简单说jqdatasdk是聚宽量化平台提供的一个本地数据获取工具包它让你能在自己的 Python 环境里像调用本地库一样方便地获取A股行情、财务、基本面等数据。而“聚宽社区”则是一个宝库里面充满了其他开发者分享的策略思路和代码片段。我们这个项目就是利用jqdatasdk从本地获取数据实现一个在聚宽社区里常见的、逻辑清晰的选股策略并输出可执行的股票列表。整个过程完全在本地完成不依赖聚宽的在线回测系统自由度更高也更适合用来验证想法、做快速研究。它适合谁呢首先是量化投资的初学者你想知道一个策略从想法到代码的完整路径是怎样的。其次是有一定Python基础但对金融市场和量化工具还比较陌生的程序员这个项目能帮你建立起数据与策略之间的桥梁。最后哪怕你是个有经验的投资者想快速测试某个选股条件比如“市盈率低于20且最近一个月涨幅超过5%的股票”这套框架也能让你在几分钟内得到结果比手动翻财报和K线图高效太多了。2. 策略核心逻辑与设计思路拆解2.1 策略逻辑多因子过滤的“漏斗模型”一个典型的简单选股策略其核心思想可以概括为“漏斗模型”。我们从一个庞大的股票池比如全部A股开始像过筛子一样一层一层地施加筛选条件最终留下符合所有条件的少数标的。这个过程的严谨性和逻辑性直接决定了策略的有效性。我设计的这个示例策略包含了三个常见的筛选维度它们分别代表了不同的投资视角市值过滤选取市值大于一定规模的股票。这通常是为了规避流动性过差的小盘股降低交易冲击成本和非系统性风险。在实际操作中你可以设定一个阈值比如只选择市值排名在前70%的股票。估值过滤选取市盈率PE在一定合理范围内的股票。这是价值投资的经典思路避免买入估值过高的标的。例如可以设定 PE 0排除亏损股且 PE 30。动量过滤选取近期股价有一定上涨动能的股票。这是趋势跟踪思想的体现。我们可以计算股票在过去一段时间比如20个交易日的涨跌幅并筛选出涨幅为正的股票。将这三个条件用“与”逻辑结合就构成了一个“中大市值、估值合理、且近期有上涨势头”的选股策略。这个逻辑本身并不复杂但关键在于如何准确、高效地用代码实现每一个过滤条件这正是jqdatasdk发挥价值的地方。2.2 为什么选择 jqdatasdk 与本地化开发市面上数据源很多为什么偏偏用jqdatasdk这背后有几个很实际的考量。首先数据质量与规范性。聚宽的数据在国内量化圈子里是经过多年检验的涵盖了行情、财务、指数、宏观等各个方面并且做了大量的清洗和复权处理比如前复权。对于初学者乃至大多数专业开发者来说直接使用经过处理的高质量数据能避免在数据清洗上踩坑把精力集中在策略逻辑上。自己从原始交易所数据开始处理是个工程量巨大且容易出错的事情。其次本地开发的灵活性与隐私性。使用jqdatasdk意味着所有计算都在你自己的电脑上进行。你的策略代码、核心参数、选股结果完全掌握在自己手里没有上传到任何第三方平台的风险。这对于策略保密性要求高的个人或机构来说是一个重要优势。同时本地运行也让你可以自由地结合其他Python库如pandas,numpy,scikit-learn等进行更复杂的数据分析和建模不受在线平台的功能限制。最后学习路径的平滑性。聚宽社区有海量的策略和讨论很多代码思路可以直接借鉴或修改。使用jqdatasdk能让你的本地代码与社区资源保持“语言相通”方便你学习、调试和优化。当你熟悉了这套本地模式后如果想进行大规模历史回测也可以相对平滑地迁移到聚宽的在线回测系统或者其他的回测框架如backtrader,Zipline等中。注意jqdatasdk需要注册聚宽账号并获取认证凭证才能使用它有每日调用次数的限制免费版足够个人学习研究。这意味着它不适合超高频率如秒级、分钟级的海量数据调用场景但对于日级、周级的选股策略开发和验证完全绰绰有余。3. 环境搭建与核心工具详解3.1 Python环境与必要库的安装工欲善其事必先利其器。一个干净、独立的Python环境是开始一切项目的好习惯它能避免不同项目间的库版本冲突。我强烈推荐使用conda或venv来创建虚拟环境。# 使用 conda 创建环境假设你安装了Anaconda或Miniconda conda create -n quant_env python3.8 conda activate quant_env # 或者使用 venv python -m venv quant_env # Windows 激活 quant_env\Scripts\activate # Linux/Mac 激活 source quant_env/bin/activate环境激活后开始安装核心库。除了jqdatasdk我们还会用到数据分析三件套pip install jqdatasdk pandas numpypandas: 数据处理的基石我们的股票数据几乎都会以DataFrame的形式存在和操作。numpy: 提供高效的数值计算在计算指标如收益率、均值时常用。有时候为了数据可视化我们可能还会安装matplotlib或seaborn但在这个纯选股项目中不是必须的。3.2 jqdatasdk 的配置与认证安装好后第一件事就是认证。你需要先去聚宽官网注册账号然后在“我的账号” - “认证信息”中查看你的username通常是手机号或邮箱和password。在你的Python脚本或Jupyter Notebook的开头你需要这样进行认证import jqdatasdk as jq import pandas as pd import numpy as np from datetime import datetime, timedelta # 替换为你的聚宽账号和密码 username ‘your_username‘ password ‘your_password‘ # 进行认证 jq.auth(username, password) # 认证成功后可以尝试获取一条数据测试 try: # 获取贵州茅台的最新股价 price jq.get_price(‘000001.XSHE‘, end_datedatetime.now(), count1, fields[‘close‘]) print(‘认证成功最新数据示例\n‘, price) except Exception as e: print(‘认证或数据获取失败‘, e)认证成功后这个会话在有效期内通常一天都可以调用数据接口。记得千万不要将你的账号密码直接硬编码在提交到公开仓库的代码里一个更好的做法是使用环境变量或配置文件来管理敏感信息。# 示例使用环境变量推荐 import os username os.environ.get(‘JQ_USERNAME‘) password os.environ.get(‘JQ_PASSWORD‘) jq.auth(username, password)3.3 理解聚宽的数据结构证券代码与查询字段这是新手最容易困惑的地方之一。聚宽有自己的证券代码命名规范并且不同的数据有不同的查询字段fields。证券代码格式股票代码.交易所后缀000001.XSHE: 平安银行深交所。XSHE代表深圳证券交易所。600519.XSHG: 贵州茅台上交所。XSHG代表上海证券交易所。对于指数也有类似格式如000300.XSHG代表沪深300指数。在编写策略时我们通常先获取一个股票池的列表。jqdatasdk提供了get_all_securities函数但更常用的是get_index_stocks来获取某个指数的成分股这样更符合实际投资场景。# 获取沪深300指数的最新成分股列表 stock_list jq.get_index_stocks(‘000300.XSHG‘) print(f‘沪深300成分股数量{len(stock_list)}‘) print(stock_list[:5]) # 打印前5个查询字段不同的函数需要指定不同的fields。例如get_price: 常用[‘open‘, ‘close‘, ‘high‘, ‘low‘, ‘volume‘, ‘money‘]get_fundamentals: 查询财务数据字段极其丰富如pe_ratio(市盈率),market_cap(总市值),circulating_market_cap(流通市值) 等。务必查阅官方文档来找到你需要的具体字段名。理解并熟练运用这些代码和字段是写好策略的第一步。我建议新建一个代码片段专门用来测试和熟悉各个接口的返回格式这会让你后续的编码顺畅很多。4. 策略代码的逐行实现与解析现在我们进入核心环节将之前设计的“市值-估值-动量”三层过滤逻辑转化为可执行的代码。我会把代码分成几个功能模块并详细解释每一行代码的作用和背后的考量。4.1 模块一数据获取与预处理函数首先我们封装一个函数用于批量获取股票在某个日期的市值和市盈率数据。财务数据通常有发布延迟所以我们查询的日期query_date最好比当前日期早一些确保数据已经更新。def get_fundamental_data(stock_list, query_date): 批量获取指定日期股票的总市值和市盈率(PE) 参数 stock_list: list, 股票代码列表 query_date: datetime.date 或 str, 查询日期 返回 pd.DataFrame, 包含股票代码、总市值、市盈率的 DataFrame # 构建查询对象q 是 jqdatasdk 的查询入口 q jq.query( jq.valuation.code, # 股票代码 jq.valuation.market_cap, # 总市值单位万元 jq.valuation.pe_ratio # 市盈率PE ).filter( jq.valuation.code.in_(stock_list) # 过滤出我们股票池里的股票 ) # 执行查询获取指定日期的数据 df_fund jq.get_fundamentals(q, query_date) # 重命名列让它们更易懂 df_fund df_fund.rename(columns{‘code‘: ‘stock_code‘, ‘market_cap‘: ‘total_market_cap‘, ‘pe_ratio‘: ‘pe‘}) # 设置股票代码为索引方便后续合并数据 df_fund.set_index(‘stock_code‘, inplaceTrue) return df_fund关键点解析jq.query(...).filter(...)是聚宽财务数据查询的标准范式非常像SQL。jq.valuation是一个包含众多估值指标的表。market_cap的单位是万元这是聚宽数据的统一单位在后续计算阈值时要注意。get_fundamentals的第二个参数是日期它返回的是该日期所能获取到的最新财务数据。对于市值和PE通常是每日更新。接下来封装一个获取股票价格数据用于计算动量的函数。def get_price_data_for_momentum(stock_list, end_date, lookback_days20): 获取股票价格数据用于计算过去一段时间的涨跌幅动量 参数 stock_list: list, 股票代码列表 end_date: datetime.date 或 str, 计算截止日期 lookback_days: int, 回溯的天数交易日 返回 pd.DataFrame, 索引为股票代码列包含 ‘start_price‘, ‘end_price‘, ‘return‘ # 计算开始日期 start_date end_date - timedelta(dayslookback_days * 2) # 多取一些天数确保覆盖足够的交易日 # 初始化一个字典来存储结果 momentum_data {} for stock in stock_list: try: # 获取股票在指定时间段内的日线收盘价 price_df jq.get_price(stock, start_datestart_date, end_dateend_date, fields[‘close‘]) if price_df.empty or len(price_df) lookback_days: # 如果数据不足则跳过该股票可能是新股或停牌 continue # 获取回溯期开始和结束的收盘价 # 注意get_price 返回的数据按日期升序排列 start_price price_df[‘close‘].iloc[-lookback_days] # 第 -lookback_days 天20天前 end_price price_df[‘close‘].iloc[-1] # 最后一天end_date # 计算期间收益率 period_return (end_price - start_price) / start_price momentum_data[stock] { ‘start_price‘: start_price, ‘end_price‘: end_price, ‘return‘: period_return } except Exception as e: # 记录错误但继续处理其他股票 print(f“获取 {stock} 价格数据时出错{e}“) continue # 将字典转换为 DataFrame df_momentum pd.DataFrame.from_dict(momentum_data, orient‘index‘) df_momentum.index.name ‘stock_code‘ return df_momentum关键点解析我们采用循环获取单只股票数据的方式而不是批量获取。这是因为get_price支持单只股票的多日数据获取且逻辑清晰。对于几百只股票的池子这样操作在性能上是可以接受的。如果股票池很大如上万只则需要考虑更高效的批量获取方式或向量化计算。start_date我们故意多取了一些天数lookback_days * 2这是为了确保即使中间有节假日我们也能取到足够lookback_days个交易日的数据这是一种稳健的做法。对每只股票进行了try-except异常捕获并检查数据是否足够。这是因为股票可能在新股上市、长期停牌等情况下数据不完整。一个健壮的策略必须能处理这些边缘情况而不是直接崩溃。4.2 模块二三层过滤逻辑的实现有了数据我们就可以实现过滤逻辑了。我们将每一步过滤的结果都保存下来方便调试和查看中间结果。def apply_filters(df_fund, df_momentum): 应用三层过滤条件筛选符合条件的股票 参数 df_fund: 基本面DataFrame来自 get_fundamental_data df_momentum: 动量DataFrame来自 get_price_data_for_momentum 返回 pd.DataFrame, 最终符合条件的股票列表及关键指标 # 第一步合并基本面数据和动量数据 # 使用 inner join只保留两者都有的股票即既有财务数据又有价格数据的股票 df_combined pd.merge(df_fund, df_momentum, left_indexTrue, right_indexTrue, how‘inner‘) print(f“合并后初始股票数量{len(df_combined)}“) # 第二步市值过滤 - 选择市值大于100亿元即1,000,000万元的股票 df_size_filtered df_combined[df_combined[‘total_market_cap‘] 1000000].copy() print(f“市值过滤后100亿股票数量{len(df_size_filtered)}“) # 第三步估值过滤 - 选择市盈率大于0且小于30的股票 # PE 0 是为了排除亏损企业PE为负 df_pe_filtered df_size_filtered[(df_size_filtered[‘pe‘] 0) (df_size_filtered[‘pe‘] 30)].copy() print(f“估值过滤后0PE30股票数量{len(df_pe_filtered)}“) # 第四步动量过滤 - 选择过去20个交易日收益率为正的股票 df_momentum_filtered df_pe_filtered[df_pe_filtered[‘return‘] 0].copy() print(f“动量过滤后20日收益0股票数量{len(df_momentum_filtered)}“) # 对最终结果进行排序例如按市值从大到小排序 df_final df_momentum_filtered.sort_values(by‘total_market_cap‘, ascendingFalse) # 可以添加一些衍生列方便阅读 df_final[‘total_market_cap_billion‘] df_final[‘total_market_cap‘] / 100000 # 转换为亿元 df_final[‘return_pct‘] df_final[‘return‘] * 100 # 转换为百分比 return df_final关键点解析pd.merge是合并两个DataFrame的关键操作。left_indexTrue和right_indexTrue表示我们用索引股票代码进行合并。how‘inner‘表示取交集这是最严格的方式确保后续分析的数据完整性。在每次过滤后我们都使用了.copy()来创建数据副本。这是一个好习惯可以避免后续操作对原始数据的误修改也避免了 Pandas 可能产生的SettingWithCopyWarning警告。过滤条件使用了布尔索引这是 Pandas 筛选数据的标准且高效的方式。我们在每个过滤步骤后都打印了股票数量这就像给漏斗的每一层都装了个计数器能清晰看到每一层筛掉了多少股票对于理解和调试策略逻辑至关重要。最后我们添加了市值亿元和收益率百分比的衍生列让输出结果更直观。排序则让结果更有条理通常我们会关注市值最大的那些标的。4.3 模块三主程序流程与结果输出最后我们把所有模块串联起来形成一个完整的脚本。def main(): 主函数执行完整的选股流程 # 1. 设置参数 query_date ‘2023-10-27‘ # 假设我们分析这个日期的数据 query_date_dt datetime.strptime(query_date, ‘%Y-%m-%d‘).date() lookback_days 20 # 2. 获取股票池这里以沪深300成分股为例 print(“正在获取股票池...“) index_code ‘000300.XSHG‘ stock_pool jq.get_index_stocks(index_code, datequery_date) print(f“初始股票池{index_code}成分股数量{len(stock_pool)}“) # 3. 获取基本面数据 print(“\n正在获取基本面数据市值、PE...“) df_fundamentals get_fundamental_data(stock_pool, query_date) # 4. 获取动量数据 print(“\n正在计算动量数据20日收益率...“) df_momentum get_price_data_for_momentum(stock_pool, query_date_dt, lookback_days) # 5. 应用过滤条件 print(“\n开始应用筛选条件...“) final_stocks_df apply_filters(df_fundamentals, df_momentum) # 6. 输出结果 print(“\n“ ““*50) print(“选股策略执行完毕“) print(f“最终符合条件的股票数量{len(final_stocks_df)}“) print(““*50 “\n“) if not final_stocks_df.empty: # 打印前10只股票详情 print(“前10只符合条件的股票详情“) # 选择要展示的列 display_columns [‘total_market_cap_billion‘, ‘pe‘, ‘return_pct‘, ‘start_price‘, ‘end_price‘] print(final_stocks_df[display_columns].head(10).to_string(float_format“%.2f“)) # 也可以将结果保存到CSV文件方便后续分析或导入到其他软件 output_file f‘selected_stocks_{query_date}.csv‘ final_stocks_df.to_csv(output_file, encoding‘utf-8-sig‘) # 使用utf-8-sig避免中文乱码 print(f“\n完整结果已保存至文件{output_file}“) else: print(“警告没有股票满足所有筛选条件“) # 7. 可选简单统计摘要 if not final_stocks_df.empty: print(“\n--- 筛选结果统计摘要 ---“) print(f“平均市值亿元: {final_stocks_df[‘total_market_cap_billion‘].mean():.2f}“) print(f“平均市盈率PE: {final_stocks_df[‘pe‘].mean():.2f}“) print(f“平均20日收益率%: {final_stocks_df[‘return_pct‘].mean():.2f}“) print(f“最大20日收益率%: {final_stocks_df[‘return_pct‘].max():.2f}“) print(f“最小20日收益率%: {final_stocks_df[‘return_pct‘].min():.2f}“) if __name__ “__main__“: main()这个main函数清晰地勾勒出了整个策略的执行流程设定日期、获取股票池、抓取数据、执行过滤、输出结果。它就像一个自动化流水线你只需要调整入口的参数比如query_date,index_code, 过滤阈值就能得到不同市场环境下的选股列表。5. 策略优化、扩展与实战心得一个能跑通的策略只是起点。要让策略真正具备参考价值甚至产生阿尔法我们还需要深入思考如何优化和扩展它。这里分享几个我实践中总结的方向和心得。5.1 参数优化与敏感性分析我们策略中的1000000100亿市值、30PE上限、20动量周期这些数字都不是金科玉律。它们需要根据不同的市场风格牛市、熊市、震荡市和不同的投资目标进行调整。如何进行参数优化一个朴素但有效的方法是进行网格搜索Grid Search。例如我们可以测试市值阈值在 [50亿 100亿 200亿]PE上限在 [20, 25, 30, 35]动量周期在 [10, 20, 30] 的所有组合。对于每一组参数在历史的一段时期内例如过去3年按月或按周运行策略统计每次选股后这些股票在未来一段时间例如未来1个月的平均收益、胜率跑赢基准的比例、最大回撤等指标。# 伪代码示例参数扫描循环框架 市值阈值列表 [500000, 1000000, 2000000] # 单位万元 pe上限列表 [20, 25, 30, 35] 动量周期列表 [10, 20, 30] 结果记录 [] for 市值 in 市值阈值列表: for pe in pe上限列表: for 周期 in 动量周期列表: # 在历史多个时间点运行策略 历史收益列表 [] for 日期 in 历史日期序列: stocks 运行策略(日期, 市值阈值市值, pe上限pe, 动量周期周期) 未来收益 计算这些股票在未来N天的平均收益 历史收益列表.append(未来收益) # 计算该参数组的综合表现 平均收益 np.mean(历史收益列表) 收益波动 np.std(历史收益列表) 结果记录.append({‘市值阈值‘: 市值, ‘PE上限‘: pe, ‘动量周期‘: 周期, ‘平均收益‘: 平均收益, ‘波动‘: 收益波动}) # 找出表现最好的参数组这个过程计算量较大但能帮你理解策略对参数的敏感度。切记在历史数据上表现最优的参数在未来不一定有效。要警惕过拟合Overfitting。一个稳健的策略其表现应对参数的小幅变动不敏感且在样本外测试例如用最近一年的数据测试之前三年优化出的参数中仍有不错表现。5.2 因子扩展与逻辑深化我们的三层过滤只是入门。聚宽jqdatasdk提供了上百个财务和估值指标你可以轻松地引入更多因子构建更复杂的模型。质量因子引入净资产收益率ROE、总资产收益率ROA、毛利率等筛选盈利能力强的公司。jq.income_statement和jq.balance_sheet表中可以找到这些数据。成长因子计算营业收入增长率、净利润增长率寻找高成长性标的。这需要获取多个报告期的数据进行计算。技术因子除了简单的区间收益率可以引入 RSI相对强弱指数、MACD异同移动平均线、布林带等技术指标这些可以通过ta-lib库结合价格数据计算。风险因子计算股票的历史波动率、Beta值相对于市场的敏感度用于控制组合风险。引入新因子后策略逻辑可以从简单的“与”过滤升级为打分卡模型或回归模型。打分卡对每个因子根据股票在该因子上的表现进行排序打分例如PE最低的10%得10分次低的10%得9分以此类推然后将所有因子的分数加权求和选出总分最高的股票。回归模型使用历史数据建立因子对未来收益的线性或非线性回归模型用模型预测股票的预期收益并选择预期收益最高的。5.3 回测与绩效评估框架搭建选股策略的终极检验是历史回测。虽然jqdatasdk本身不提供回测引擎但我们可以基于它获取的数据搭建一个简单的回测框架。一个最简单的回测思路是确定回测周期例如 2018-01-01 到 2023-10-27。确定调仓周期例如每月第一个交易日调仓。模拟交易在每个调仓日运行我们的选股策略得到股票列表。假设我们等权重买入这些股票并卖出不再列表中的原有持仓。计算净值曲线记录每日投资组合的总市值变化并与基准如沪深300指数进行比较。计算绩效指标年化收益率、夏普比率、最大回撤、胜率、信息比率等。# 一个极简的回测循环框架示例 初始资金 1000000 当前资金 初始资金 持仓 {} # 字典记录 {股票代码: 持仓股数} 净值序列 [1.0] # 归一化净值从1开始 基准净值序列 [1.0] # 基准净值 for 调仓日期 in 所有调仓日列表: # 1. 卖出不在新名单中的股票 selected_stocks 运行选股策略(调仓日期) # 返回股票代码列表 for stock in list(持仓.keys()): if stock not in selected_stocks: 卖出价格 获取调仓日收盘价(stock) 当前资金 持仓[stock] * 卖出价格 del 持仓[stock] # 2. 等权重买入新名单中的股票 if selected_stocks: 每只股票分配资金 当前资金 / len(selected_stocks) for stock in selected_stocks: 买入价格 获取调仓日收盘价(stock) 可买股数 int(每只股票分配资金 / 买入价格 / 100) * 100 # 假设A股按手买 持仓[stock] 持仓.get(stock, 0) 可买股数 当前资金 - 可买股数 * 买入价格 # 3. 计算当日组合总市值和净值 当日总市值 当前资金 for stock, shares in 持仓.items(): 当日价格 获取当日收盘价(stock) 当日总市值 shares * 当日价格 当日净值 当日总市值 / 初始资金 净值序列.append(当日净值) # 4. 计算基准净值 基准指数价格 获取基准指数当日收盘价(‘000300.XSHG‘) ... # 计算基准净值搭建这样一个框架后你才能客观地回答“我的策略在过去几年真的能赚钱吗比简单持有指数强吗风险有多大”5.4 实战中的注意事项与避坑指南数据日期对齐问题巨坑财务数据的发布日期远晚于报告期。比如2023年三季报可能在10月底才发布。如果你在10月1日用query_date‘2023-10-01‘去查询pe_ratio你拿到的是基于当时已发布的最新财报计算出的PE很可能是2023年中报的数据。这意味着你的“实时”选股实际上用的是滞后的财务信息。在回测中必须模拟这种滞后避免使用未来数据Look-ahead Bias。通常的解决方法是在T日选股时使用T-1个交易日所能获得的最新财务数据聚宽函数中的date参数本身就代表“获取该日期及之前的最新数据”。停牌与退市处理我们的get_price_data_for_momentum函数简单跳过了数据不足的股票这处理了停牌。但对于退市股在历史回测中如果买入了需要在后续计算中将其价值归零。在实际操作中需要更精细的处理逻辑。交易成本上述简单回测忽略了印花税、佣金和滑点。一个严肃的策略必须考虑这些成本它们会显著侵蚀收益尤其是对于换手率较高的策略。流动性考量我们虽然用市值过滤了但更精细的做法是结合日均成交金额money字段进行过滤避免买入成交量极低、难以按理想价格成交的股票。代码健壮性网络请求可能失败数据可能缺失API可能有调用频率限制。在生产环境中你的代码需要包含重试机制、错误日志记录和告警功能。这个基于聚宽jqdatasdk的简单选股策略项目就像给你了一套乐高积木的基础颗粒和搭建手册。手册教你搭出了一座稳固的小房子三层过滤策略但房子的外观、内部结构、能否变成城堡或飞船完全取决于你如何组合、扩展这些颗粒。真正的量化工作大部分时间都花在数据清洗、逻辑验证、风险控制和绩效分析上而不仅仅是想出那个“神奇”的选股公式。从这个项目出发去尝试修改参数、添加因子、搭建回测你才会真正触摸到量化投资的门道。