From ffcd43f92ceedae14f9c3b51c80062782005a4f2 Mon Sep 17 00:00:00 2001 From: woldy Date: Wed, 31 Jan 2024 13:01:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8D=E7=9F=A5=E9=81=93=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=BA=86=E4=BA=9B=E5=95=A5,=E5=8F=8D=E6=AD=A3=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E4=B8=80=E4=B8=8B=E5=90=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/finhack_structure.sql | 183 +++++++++++++++++- finhack/__init__.py | 2 +- finhack/core/core.py | 17 +- finhack/core/loader/base_loader.py | 1 + finhack/factor/default/alphaEngine.py | 1 - finhack/factor/default/default_factor.py | 10 +- finhack/factor/default/factorAnalyzer.py | 45 +++-- .../empty_project/data/config/args.conf | 3 +- .../empty_project/strategy/ChatGPTStrategy.py | 77 ++++++++ .../strategy/ChatGPTStrategy1.py | 73 +++++++ .../strategy/SmallCapStrategy.py | 3 +- setup.py | 2 +- 12 files changed, 386 insertions(+), 31 deletions(-) create mode 100644 finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy.py create mode 100644 finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy1.py diff --git a/database/finhack_structure.sql b/database/finhack_structure.sql index 3604098..f1e38a4 100644 --- a/database/finhack_structure.sql +++ b/database/finhack_structure.sql @@ -1 +1,182 @@ -mysqldump: Got error: 1045: Access denied for user 'root'@'localhost' (using password: NO) when trying to connect +-- MySQL dump 10.13 Distrib 8.0.30, for Linux (x86_64) +-- +-- Host: localhost Database: finhack +-- ------------------------------------------------------ +-- Server version 8.0.30 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `auto_train` +-- + +DROP TABLE IF EXISTS `auto_train`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `auto_train` ( + `id` int NOT NULL AUTO_INCREMENT, + `start_date` varchar(10) DEFAULT NULL, + `valid_date` varchar(10) DEFAULT NULL, + `end_date` varchar(10) DEFAULT NULL, + `features` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `label` varchar(255) DEFAULT NULL, + `shift` int DEFAULT NULL, + `param` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `loss` varchar(255) DEFAULT NULL, + `algorithm` varchar(255) DEFAULT NULL, + `filter` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '', + `score` double(10,10) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=12675 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `backtest` +-- + +DROP TABLE IF EXISTS `backtest`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `backtest` ( + `id` int NOT NULL AUTO_INCREMENT, + `instance_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `features_list` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `train` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `strategy` varchar(255) DEFAULT NULL, + `start_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `end_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `init_cash` double(100,5) DEFAULT NULL, + `args` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `history` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `returns` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `logs` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `total_value` double(100,5) DEFAULT NULL, + `alpha` double(100,5) DEFAULT NULL, + `beta` double(100,5) DEFAULT NULL, + `annual_return` double(100,5) DEFAULT NULL, + `cagr` double(100,5) DEFAULT NULL, + `annual_volatility` double(100,5) DEFAULT NULL, + `info_ratio` double(100,5) DEFAULT NULL, + `downside_risk` double(100,5) DEFAULT NULL, + `R2` double(100,5) DEFAULT NULL, + `sharpe` double(100,5) DEFAULT NULL, + `sortino` double(100,5) DEFAULT NULL, + `calmar` double(100,5) DEFAULT NULL, + `omega` double(100,5) DEFAULT NULL, + `max_down` double(100,5) DEFAULT NULL, + `SQN` double(100,5) DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `filter` varchar(255) DEFAULT '', + `win` double(100,5) DEFAULT NULL, + `server` varchar(255) DEFAULT NULL, + `trade_num` int DEFAULT NULL, + `runtime` varchar(255) DEFAULT NULL, + `starttime` varchar(100) DEFAULT NULL, + `endtime` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `benchReturns` mediumtext, + `roto` double(100,5) DEFAULT NULL, + `simulate` int DEFAULT '0', + `benchmark` varchar(255) DEFAULT NULL, + `strategy_code` text, + PRIMARY KEY (`id`), + UNIQUE KEY `instence_id` (`instance_id`) +) ENGINE=InnoDB AUTO_INCREMENT=388626 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `factors_analysis` +-- + +DROP TABLE IF EXISTS `factors_analysis`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `factors_analysis` ( + `id` int NOT NULL AUTO_INCREMENT, + `factor_name` varchar(255) DEFAULT NULL, + `days` varchar(255) DEFAULT NULL, + `pool` varchar(255) DEFAULT NULL, + `start_date` varchar(10) DEFAULT NULL, + `end_date` varchar(10) DEFAULT NULL, + `formula` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `IC` float(10,5) DEFAULT NULL, + `IR` float(10,5) DEFAULT NULL, + `IRR` float(10,5) DEFAULT NULL, + `score` float(10,5) DEFAULT NULL, + `max_up_corr` float(10,7) DEFAULT NULL, + `hash` varchar(255) DEFAULT NULL, + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2388 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `factors_list` +-- + +DROP TABLE IF EXISTS `factors_list`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `factors_list` ( + `id` int NOT NULL AUTO_INCREMENT, + `factor_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `indicators` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `func_name` varchar(255) DEFAULT NULL, + `code` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `return_fileds` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `md5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `check_type` int DEFAULT '0', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'activate', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2406 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `factors_mining` +-- + +DROP TABLE IF EXISTS `factors_mining`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `factors_mining` ( + `id` int NOT NULL AUTO_INCREMENT, + `factor_name` varchar(255) DEFAULT NULL, + `days` varchar(255) DEFAULT NULL, + `pool` varchar(255) DEFAULT NULL, + `start_date` varchar(10) DEFAULT NULL, + `end_date` varchar(10) DEFAULT NULL, + `formula` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `IC` float(20,5) DEFAULT NULL, + `IR` float(20,5) DEFAULT NULL, + `IRR` float(20,5) DEFAULT NULL, + `score` float(10,5) DEFAULT NULL, + `hash` varchar(255) DEFAULT NULL, + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `hash` (`hash`(32)) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=31156 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2024-01-31 13:01:19 diff --git a/finhack/__init__.py b/finhack/__init__.py index 2c64bbd..0887130 100644 --- a/finhack/__init__.py +++ b/finhack/__init__.py @@ -1 +1 @@ -__version__ = '0.0.1.dev8' +__version__ = '0.0.1.dev9' diff --git a/finhack/core/core.py b/finhack/core/core.py index 837ed11..e9aa068 100644 --- a/finhack/core/core.py +++ b/finhack/core/core.py @@ -12,7 +12,7 @@ class Core: - def __init__(self,project_path=''): + def __init__(self,project_path='',args=True): self.project_path=project_path self.usage=""" @@ -26,13 +26,18 @@ def __init__(self,project_path=''): finhack trainer auto --vendor=lightgbm #自动进行lightgbm训练 finhack -h -------------------------------""" - self.generate_args() - self.check_project() + if args: + self.generate_args() + self.check_project() self.check_env() self.refresh_runtime() - self.append_args() - self.generate_global() - self.init_logger() + if args: + self.append_args() + self.generate_global() + self.init_logger() + else: + sys.path.append(self.project_path+'/data/cache/') + def init_logger(self): from runtime.constant import LOGS_DIR diff --git a/finhack/core/loader/base_loader.py b/finhack/core/loader/base_loader.py index 89ede79..037123f 100644 --- a/finhack/core/loader/base_loader.py +++ b/finhack/core/loader/base_loader.py @@ -52,6 +52,7 @@ def background(self,args): def run(self): klass=self.klass + klass.args=self.args klass.run() diff --git a/finhack/factor/default/alphaEngine.py b/finhack/factor/default/alphaEngine.py index 2922243..40c1fc2 100755 --- a/finhack/factor/default/alphaEngine.py +++ b/finhack/factor/default/alphaEngine.py @@ -784,7 +784,6 @@ def calc(formula='',df=pd.DataFrame(),name="alpha",check=False,replace=False): df=factorManager.getFactors(factor_list=col_list,cache=True) else: df=df.sort_index() - if diff_date>0 and diff_date<100: dt=datetime.datetime.strptime(str(max_date),'%Y%m%d') diff --git a/finhack/factor/default/default_factor.py b/finhack/factor/default/default_factor.py index 940c3fd..4b0b75a 100644 --- a/finhack/factor/default/default_factor.py +++ b/finhack/factor/default/default_factor.py @@ -32,4 +32,12 @@ def show(self): def analys(self): factor_name=self.args.factor - factorAnalyzer.alphalens(factor_name) \ No newline at end of file + factorAnalyzer.alphalens(factor_name) + + def alpha(self): + formula=self.args.formula + print(formula) + df_alpha=alphaEngine.calc(formula=formula,name="alpha",check=True,replace=False) + print(df_alpha) + + factorAnalyzer.alphalens(factor_name='alpha',df=df_alpha) \ No newline at end of file diff --git a/finhack/factor/default/factorAnalyzer.py b/finhack/factor/default/factorAnalyzer.py index 3a35f60..a6501c8 100755 --- a/finhack/factor/default/factorAnalyzer.py +++ b/finhack/factor/default/factorAnalyzer.py @@ -24,16 +24,19 @@ def all_corr(): - def alphalens(factor_name): - + def alphalens(factor_name='alpha',df=pd.DataFrame(),notebook=False): df_industry=AStock.getStockIndustry() + if df.empty: + df=factorManager.getFactors(factor_list=['close',factor_name]) + else: + df_close=factorManager.getFactors(factor_list=['close']) + + df_close[factor_name]=df + df=df_close - # df_all.index=df_all['date'] - # price.index = pd.to_datetime(price.index) - # assets = df_all.set_index( [df_all.index,df_all['symbol']], drop=True,append=False, inplace=False) - df=factorManager.getFactors(factor_list=['close',factor_name]) + # 假设 df 是您提供的 DataFrame,我们首先重置索引 df = df.reset_index().merge(df_industry, on='ts_code') df['industry'] = df['industry'].fillna('其他') @@ -94,7 +97,7 @@ def alphalens(factor_name): #plt.show() # 分位数累积收益 - #cumulative_returns_by_qt = al.performance.cumulative_returns_by_quantile(factor_data, period=1) + #Wcumulative_returns_by_qt = al.performance.cumulative_returns_by_quantile(factor_data, period=1) #al.plotting.plot_cumulative_returns_by_quantile(cumulative_returns_by_qt, period=1) #plt.show() @@ -111,19 +114,25 @@ def alphalens(factor_name): #al.plotting.plot_monthly_ic_heatmap(mean_monthly_ic) #plt.show() - print("\nmean_return_by_qt") - print(mean_return_by_qt) - print("\nic_by_day") - print(ic_by_day) - print("\nquantile_returns") - print(quantile_returns) - print("\nautocorrelation") - print(autocorrelation) - print("\nmean_monthly_ic") - print(mean_monthly_ic) + + if notebook: + full_tear_sheet = al.tears.create_full_tear_sheet(factor_data, long_short=True, group_neutral=False, by_group=False) + print(full_tear_sheet) + else: + + print("\nmean_return_by_qt") + print(mean_return_by_qt) + print("\nic_by_day") + print(ic_by_day) + print("\nquantile_returns") + print(quantile_returns) + print("\nautocorrelation") + print(autocorrelation) + print("\nmean_monthly_ic") + print(mean_monthly_ic) # print('---') - # print(full_tear_sheet) + #al.plotting.plot_quantile_returns_bar(mean_return_by_qt) pass diff --git a/finhack/widgets/templates/empty_project/data/config/args.conf b/finhack/widgets/templates/empty_project/data/config/args.conf index 2a1b34a..2aa5ed6 100644 --- a/finhack/widgets/templates/empty_project/data/config/args.conf +++ b/finhack/widgets/templates/empty_project/data/config/args.conf @@ -8,6 +8,7 @@ testarg2=this is also a test key [factor] factor= +formula= [trainer] @@ -29,7 +30,7 @@ max_f=128 [backtest] cash=10000,20000,50000,100000,200000,500000,1000000 -p=3 +p=2 [trader] strategy=DemoStrategy diff --git a/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy.py b/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy.py new file mode 100644 index 0000000..83dc6f3 --- /dev/null +++ b/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy.py @@ -0,0 +1,77 @@ +''' +我理解您对先前策略的担忧。让我们尝试一个不同的策略,这次我们将使用动量和反转因子结合市值和流动性指标,来寻找可能的投资机会。该策略将试图捕捉那些近期表现良好且具备合理市值和流动性的股票,同时也考虑到那些可能即将反转的股票。 + +以下是新策略的大致框架: + +动量和反转因子:使用例如12个月的价格变动率作为动量因子,以及近期的价格下跌作为可能的反转信号。 +市值和流动性:选取市值较大且交易量健康的股票,以确保流动性和稳定性。 +技术指标:使用如MACD等技术指标来辅助判断市场趋势和交易时机。 +以下是根据这些原则修改的策略代码: + +''' +import datetime +import os +import random +from finhack.factor.default.factorManager import factorManager +from finhack.market.astock.astock import AStock + +# 初始化函数,设定股票、基准等 +def initialize(context): + set_benchmark('000001.SH') + set_option('use_real_price', True) + set_option('order_volume_ratio', 1) + set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock') + set_slippage(PriceRelatedSlippage(0.00246), type='stock') + + g.stocknum = 10 + g.days = 0 + g.refresh_rate = 10 + run_daily(trade, time="09:30") + log.info('Initial setup completed') + + g.factors = factorManager.getFactors(['MACD_0', 'RSI_14_0', 'ATR_14_0', 'totalMv_0', 'volumeRatio_0', 'pe_0', 'pb_0']) + g.factors=g.factors.reset_index() + +def trade(context): + if g.days % g.refresh_rate == 0: + sell_all_stocks(context) + cash_per_stock = context.portfolio.cash / g.stocknum + + now_date = context.current_dt.strftime('%Y%m%d') + df = g.factors.query("trade_date == '{}'".format(now_date)) + + # 多因子筛选逻辑 + df = filter_stocks(df) + stock_list = df.head(g.stocknum)['ts_code'].tolist() + + # 买入股票 + buy_stocks(context, stock_list, cash_per_stock) + + g.days = 1 + else: + g.days += 1 + +def sell_all_stocks(context): + sell_list = list(context.portfolio.positions.keys()) + if len(sell_list) > 0 : + for stock in sell_list: + order_target_value(stock, 0) + +def buy_stocks(context, stock_list, cash_per_stock): + for stock in stock_list: + if len(context.portfolio.positions.keys()) < g.stocknum: + order_value(stock, cash_per_stock) + +def filter_stocks(df): + # 应用筛选条件 + filtered_df = df.copy() + filtered_df = filtered_df[filtered_df['MACD_0'] > 0] # 正MACD值,表明上升趋势 + filtered_df = filtered_df[filtered_df['RSI_14_0'] < 70] # RSI值低于70,避免超买状态 + filtered_df = filtered_df[filtered_df['totalMv_0'] > 1e5] # 选择市值较大的股票 + filtered_df = filtered_df[filtered_df['volumeRatio_0'] > 1] # 成交量比率大于1 + filtered_df = filtered_df[(filtered_df['pe_0'] > 0) & (filtered_df['pe_0'] < 50)] # 合理的市盈率范围 + filtered_df = filtered_df[(filtered_df['pb_0'] > 0) & (filtered_df['pb_0'] < 2)] # 合理的市净率范围 + + # 根据MACD值排序 + filtered_df = filtered_df.sort_values(by='MACD_0', ascending=False) + return filtered_df diff --git a/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy1.py b/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy1.py new file mode 100644 index 0000000..59a8fae --- /dev/null +++ b/finhack/widgets/templates/empty_project/strategy/ChatGPTStrategy1.py @@ -0,0 +1,73 @@ +''' +理解您的要求,我将为您提供一个更复杂和专业的量化交易策略,这将基于您提供的股票因子,并适应您的量化回测框架。这个策略将侧重于多因子选择股票,并结合动量和价值因子,同时考虑股票的市值大小和技术指标,以期实现更好的交易表现。 + +这个策略的基本思路是: +使用多个因子(如市盈率、市净率、市值、MACD等)综合评估股票。 +选择表现最佳的股票进行买入,并定期调整持仓。 +利用技术指标作为辅助决策工具,如使用均线判断市场趋势。 +以下是完整的示例策略代码: + +''' +import datetime +import os +import random +from finhack.factor.default.factorManager import factorManager +from finhack.market.astock.astock import AStock + +# 初始化函数,设定股票、基准等 +def initialize(context): + set_benchmark('000001.SH') + set_option('use_real_price', True) + set_option('order_volume_ratio', 1) + set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock') + set_slippage(PriceRelatedSlippage(0.00246), type='stock') + + g.stocknum = 10 + g.days = 0 + g.refresh_rate = 10 + run_daily(trade, time="09:30") + log.info('Initial setup completed') + + g.factors = factorManager.getFactors(['pe_0', 'MACD_0', 'peTtm_0', 'pb_0', 'totalMv_0', 'MA_90_0','close_0']) + g.factors=g.factors.reset_index() + +def trade(context): + if g.days % g.refresh_rate == 0: + sell_all_stocks(context) + cash_per_stock = context.portfolio.cash / g.stocknum + + now_date = context.current_dt.strftime('%Y%m%d') + df = g.factors.query("trade_date == '{}'".format(now_date)) + + # 多因子筛选逻辑 + df = filter_stocks(df) + stock_list = df.head(g.stocknum)['ts_code'].tolist() + + # 买入股票 + buy_stocks(context, stock_list, cash_per_stock) + + g.days = 1 + else: + g.days += 1 + +def sell_all_stocks(context): + sell_list = list(context.portfolio.positions.keys()) + if len(sell_list) > 0 : + for stock in sell_list: + order_target_value(stock, 0) + +def buy_stocks(context, stock_list, cash_per_stock): + for stock in stock_list: + if len(context.portfolio.positions.keys()) < g.stocknum: + order_value(stock, cash_per_stock) + +def filter_stocks(df): + # 基于市盈率、市净率、MACD、市值和90日均线的简单多因子模型 + df_filtered = df[df['pe_0'] > 0] + df_filtered = df_filtered[df_filtered['pb_0'] < 2] + df_filtered = df_filtered[df_filtered['MACD_0'] < 0] + df_filtered = df_filtered[df_filtered['peTtm_0'] < df_filtered['pe_0']] + df_filtered = df_filtered[df_filtered['totalMv_0'] > 1e5] # 筛选市值较大的股票 + df_filtered = df_filtered[df_filtered['close_0'] > df_filtered['MA_90_0']] # 当前价格高于90日均线 + df_filtered = df_filtered.sort_values(by='totalMv_0', ascending=True) + return df_filtered \ No newline at end of file diff --git a/finhack/widgets/templates/empty_project/strategy/SmallCapStrategy.py b/finhack/widgets/templates/empty_project/strategy/SmallCapStrategy.py index a8e0699..08104e2 100644 --- a/finhack/widgets/templates/empty_project/strategy/SmallCapStrategy.py +++ b/finhack/widgets/templates/empty_project/strategy/SmallCapStrategy.py @@ -55,7 +55,8 @@ def trade(context): ## 选股 now_date=context.current_dt.strftime('%Y%m%d') - df = g.factors.query(f"trade_date =='{now_date}' & pe_0 > 0 & pb_0 < 2 & MACD_0<0 & peTtm_010") + df = g.factors[g.factors.trade_date==now_date] + df = g.factors.query(f"pe_0 > 0 & pb_0 < 2 & MACD_0<0 & peTtm_010") df=df.sort_values(by='totalMv_0',ascending=True, inplace=False) stock_list = df.head(g.stocknum)['ts_code'].tolist() diff --git a/setup.py b/setup.py index bead80d..54d206c 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import os root_dir = 'finhack' -version='0.0.1.dev8' +version='0.0.1.dev9' for subdir, dirs, files in os.walk(root_dir): if not '__init__.py' in files: