文档
测试

强势股挑选策略

POST

说明 / 示例

```py #encoding:gbk ''' 策略(小市值) 沪深全部A股,4个月调仓一次: 01 选择市值最小的200只股票 02 均线多头排列MA5>MA20>MA60 #03 ROE > 5% & PB > 2 选择符合这三个条件的股票 ''' import pandas as pd import numpy as np import talib import datetime pd.set_option('expand_frame_repr', False) # 不换行 pd.set_option('display.max_rows', 5000) # 最多显示数据的行数 pd.set_option('display.unicode.ambiguous_as_wide', True) # 中文字段对齐 pd.set_option('display.unicode.east_asian_width', True) pd.set_option('display.float_format', lambda x: '%.3f' % x) def init(ContextInfo): #设置选股的备选股票池如"沪深300","沪深A股" ContextInfo.trade_code_list = ContextInfo.get_stock_list_in_sector('沪深300') #print(len(ContextInfo.trade_code_list)) ContextInfo.set_universe(ContextInfo.trade_code_list) ContextInfo.accID = '410038217334' ContextInfo.data_info_level = 2 # 参数 ContextInfo.g_days = 0 # 记录交易天数 ContextInfo.stocks_list = [] # 参数 ContextInfo.choice_nums = 20 # 待挑选小市值股票数量 ContextInfo.changecircle = 20 #调仓周期设定 ContextInfo.market_lengths = 65 # 行情数据长度 #ContextInfo.ROE_rate = 0.00 # roe最小值 #ContextInfo.PB_value = 8 # PB最小值 def handlebar(ContextInfo): g=ContextInfo; _nd=datetime.datetime.now() #print() d = ContextInfo.barpos #当前K线索引号 td=timetag_to_datetime(ContextInfo.get_bar_timetag(d),'%Y%m%d %H:%M:%S')#当前K线时间 td_strptime = datetime.datetime.strptime(td,'%Y%m%d %H:%M:%S')#转换成日期格式 delta=datetime.timedelta(days=40) yd_strptime = td_strptime - delta #获取财务因子的初始时间 yd = datetime.datetime.strftime(yd_strptime,'%Y%m%d %H:%M:%S') start_time = yd[:8] end_time = td[:8] if ContextInfo.g_days % ContextInfo.changecircle == 0: print('{} 开始选股: '.format(end_time)) #股票行情数据 stock_close_panel =ContextInfo.get_market_data(['close'], stock_code=ContextInfo.trade_code_list, skip_paused=True, period='1d', count=1) stock_close_se = stock_close_panel.ix[:,0,0] # ============= 选股条件01: 200只小市值股票 =============== stocks_list = is_selected_condition01(ContextInfo, stock_close_se, start_time, end_time) # =========== 选股条件02:均线多头排列MA5>MA20>MA60 ============ stocks_list = is_selected_condition02(ContextInfo, stocks_list) #print(stocks_list) ContextInfo.stocks_list=stocks_list if ContextInfo.g_days % ContextInfo.changecircle == 1: # 每四个月等权重买入一次 print('{} 等权重买入: '.format(end_time)) print("买入股票数量: ", len(ContextInfo.stocks_list)) if len(ContextInfo.stocks_list) == 0: return g_everyStock = round(get_totalvalue(ContextInfo.accID,'STOCK')/len(ContextInfo.stocks_list), 0) - 100 for stock in ContextInfo.stocks_list: order_target_value(stock, g_everyStock, ContextInfo, ContextInfo.accID) if (ContextInfo.g_days % ContextInfo.changecircle) == (ContextInfo.changecircle - 1): # 每四个月清仓一次 print('{} 清仓: '.format(end_time)) for stock in ContextInfo.stocks_list: order_target_value(stock, 0, ContextInfo, ContextInfo.accID) ContextInfo.g_days += 1 #log(g,start_time,end_time) #按时间节点过滤打印日记 def log(ContextInfo,*args): _nd=datetime.datetime.now() pos = ContextInfo.barpos #当前K线索引号 tds=timetag_to_datetime(ContextInfo.get_bar_timetag(pos),'%Y%m%d %H:%M:%S')#当前K线时间 td = datetime.datetime.strptime(tds,'%Y%m%d %H:%M:%S')#转换成日期格式 if _nd.year==td.year and _nd.month==td.month and _nd.day==td.day: for arg in args: print(arg) def get_totalvalue(accountid,datatype): """ 获取账户可用资金 """ result=0 resultlist=get_trade_detail_data(accountid,datatype,"ACCOUNT") for obj in resultlist: result=obj.m_dAvailable #:可用金额 return result def is_selected_condition01(ContextInfo, stock_close_se, start_time, end_time): """ 选股条件01: 选择市值最小的200只股票 01 ContextInfo: 全局变量 02 stock_close_se:股票收盘价 03 finance_data_panel:财务数据 构建股票名、总股本、流通股本、限售股本、总市值、流通市值dataframe, 并按照总市值大小进行先后排名 return: list """ # 获取财务数据:总股本、流动股本 finance_field_list = ['CAPITALSTRUCTURE.total_capital', 'CAPITALSTRUCTURE.circulating_capital', 'CAPITALSTRUCTURE.restrict_circulating_capital'] finance_data_panel = ContextInfo.get_financial_data(finance_field_list, ContextInfo.trade_code_list, start_time, end_time) #print('财务数据:',finance_data_panel) stock_finance = pd.DataFrame() _list = []; for st in ContextInfo.trade_code_list: if not stock_close_se[st] is None: _list.append(st) print('_list:',len(_list)) print('trade_code_list:',len(ContextInfo.trade_code_list)) for stock in _list: #须要解决收盘价为none的错误 _ltg=ContextInfo.get_last_volume(stock) _total=ContextInfo.get_total_share(stock) stock_finance.loc[stock, '股票名称'] = ContextInfo.get_stock_name(stock) stock_finance.loc[stock, '总股本'] = _total stock_finance.loc[stock, '流通股本'] = _ltg stock_finance.loc[stock, '限售股本'] = _total-_ltg #print('close:',stock_close_se[stock]) stock_finance.loc[stock, '总市值'] = _total * stock_close_se[stock] stock_finance.loc[stock, '流通市值'] = _ltg * stock_close_se[stock] stock_finance.loc[stock, '限售市值'] = (_total-_ltg) * stock_close_se[stock] stock_finance = stock_finance.sort_values(by='总市值', ascending=True) stock_finance = stock_finance.apply(lambda x: transform_format(x), axis=1) stock_finance = stock_finance.iloc[0: ContextInfo.choice_nums] #print(stock_finance) return list(stock_finance.index) def is_selected_condition02(ContextInfo, stocks_list): """ 选股条件02: 均线多头排列MA5>MA20>MA60 返回值:list """ market_data = ContextInfo.get_market_data(['close'], stock_code=stocks_list, skip_paused = True, period='1d', dividend_type='front', count=ContextInfo.market_lengths) market_data_df = market_data.ix[:, :, 0] selected_list = [] for stock in stocks_list: stock_df = pd.DataFrame(market_data_df[stock]) stock_df['ma_5']=stock_df[stock].shift(1).rolling(window=5).mean()# 注意,此时的均线是对于前一天的均线 stock_df['ma_20']=stock_df[stock].shift(1).rolling(window=20).mean()# 注意,此时的均线是对于前一天的均线 stock_df['ma_60']=stock_df[stock].shift(1).rolling(window=60).mean()# 注意,此时的均线是对于前一天的均线 if stock_df.ix[-1, 'ma_5'] > stock_df.ix[-1, 'ma_20'] and stock_df.ix[-1, 'ma_20'] > stock_df.ix[-1, 'ma_60']: selected_list.append(stock) return selected_list def is_selected_condition03(ContextInfo, stocks_list, stock_close_se, start_time, end_time): """ 选股条件03: ROE > 8% & PB > 5 返回值:list """ # PERSHAREINDEX.s_fa_bps:每股净资产 、ASHAREBALANCESHEET.tot_assets: 资产总计、 ASHAREBALANCESHEET.tot_liab 负债合计 ASHAREINCOME.net_profit_incl_min_int_inc: 净利润 finance_field_list = ['PERSHAREINDEX.s_fa_bps', 'ASHAREBALANCESHEET.tot_assets', 'ASHAREBALANCESHEET.tot_liab', 'ASHAREINCOME.net_profit_incl_min_int_inc'] finance_data_panel = ContextInfo.get_financial_data(finance_field_list, stocks_list, start_time, end_time) stock_df = pd.DataFrame() for stock in stocks_list: df = finance_data_panel[stock].dropna(axis=0,how='any') if df.empty: continue if len(df) == 0: continue stock_df.loc[stock, 'ROE'] = df.iloc[-1, 3] / (df.iloc[-1, 1] - df.iloc[-1, 2]) # 净利润 / (资产总计-负债合计) stock_df.loc[stock, 'PB'] = stock_close_se[stock] / df.iloc[-1, 0] # 股价 / 每股净资产 stock_df = stock_df[(stock_df['ROE'] > ContextInfo.ROE_rate) & (stock_df['PB'] > ContextInfo.PB_value)] print(list(stock_df.index)) return list(stock_df.index) def is_suspended_data(stocks_list): """ 去除当前停牌的数据 return: list """ pass return stocks_list def transform_format(x): """ 调整格式 """ x['总市值'] = str(round(x['总市值'] * 0.00000001, 0)) + ' 亿' x['流通市值'] = str(round(x['流通市值'] * 0.00000001, 0)) + ' 亿' x['限售市值'] = str(round(x['限售市值'] * 0.0001, 2)) + ' 万' return x ```