def is_stop(self, code, date): """ 判断是否需要止盈,盈利超过指定值,则止盈 :param code: 股票代码 :param date: 日期 :return: True - 止盈,False - 不止盈 """ holding_stock = self.account.get_holding(code) print('止盈判断:%s' % code, flush=True) print(holding_stock, flush=True) dm = DataModule() if holding_stock is not None: df_daily = dm.get_k_data(code, autype=None, begin_date=date, end_date=date) if df_daily.index.size > 0: df_daily.set_index(['date'], 1, inplace=True) profit = (holding_stock['volume'] * df_daily.loc[date]['close'] - holding_stock['cost']) \ * 100 / holding_stock['cost'] return profit >= self.max_profit return False
def train_model(user_image: Image, style_image: Image): """Trains a Deep Learning model to extract the stylings from `style_image` and applies them onto `user_image` then returns `user_image`. Args: user_image (Image): Image you want to apply styles onto. style_image (Image): Image you want to extract styles from. Returns: user_image (Image): `user_image` with styling applied. """ image_processor = ImageProcessor(maximum_image_size=(512, 512)) print(f"user_image.size: {user_image.size} | style_image.size: {style_image.size}") image_size = image_processor.get_common_image_size(user_image, style_image) # device = torch.device("cuda" if torch.cuda.is_available() else "cpu") device = "cpu" user_image = image_processor.prepare_images(user_image, image_size) style_image = image_processor.prepare_images(style_image, image_size) normalization_mean = torch.tensor([0.485, 0.456, 0.406]).to(image_processor.device) normalization_std = torch.tensor([0.229, 0.224, 0.225]).to(image_processor.device) datamodule = DataModule(user_image, style_image) model = StyleTransferModel( user_image=user_image, style_image=style_image, normalization_mean=normalization_mean, normalization_std=normalization_std, ) cnn = models.vgg19(pretrained=True).features.to(device).eval() model._build_model_and_loss_functions(base_cnn_model=cnn) print("Training...") tb_logger = pl_loggers.TensorBoardLogger("logs/") trainer_params = {"max_epochs": 6000} if device != "cpu": print("Using a gpu!") trainer_params["gpus"] = 1 trainer = pl.Trainer(**trainer_params) trainer.fit(model, datamodule) sample = user_image.to(device) model.to(device) image = model(sample) image = image_processor.save_image( image, "output.png", "Sample Output", display_image=True ) return image
def compute(self, begin_date, end_date): """ 计算指定时间段内所有股票的该因子的值,并保存到数据库中 :param begin_date: 开始时间 :param end_date: 结束时间 """ dm = DataModule() frc = FinanceReportCrawler() code_report_dict = frc.get_code_reports() codes = set(code_report_dict.keys()) for code in codes: dailies = dm.get_k_data(code, autype=None, begin_date=begin_date, end_date=end_date) # 如果没有合适的数据 if dailies.index.size == 0: continue # 业绩报告列表 reports = code_report_dict[code] dailies.set_index(['date'], inplace=True) update_requests = [] for current_date in dailies.index: # 用来保存最后一个公告日期小于等于当前日期的财报 last_report = None for report in reports: announced_date = report['announced_date'] # 如果公告日期大于当前调整日,则结束循环 if announced_date > current_date: break last_report = report # 如果找到了正确时间范围的年报, 则计算PE if last_report is not None: pe = dailies.loc[current_date]['close'] / last_report['eps'] pe = round(pe, 3) print('%s, %s, %s, eps: %5.2f, pe: %6.2f' % (code, current_date, last_report['announced_date'], last_report['eps'], pe), flush=True) update_requests.append( UpdateOne( {'code': code, 'date': current_date}, {'$set': {'code': code, 'date': current_date, 'pe': pe}}, upsert=True)) if len(update_requests) > 0: save_result = self.collection.bulk_write(update_requests, ordered=False) print('股票代码: %s, 因子: %s, 插入:%4d, 更新: %4d' % (code, self.name, save_result.upserted_count, save_result.modified_count), flush=True)
def __init__(self, strategy_option, begin_date=None, end_date=None): self.strategy_option = strategy_option if begin_date is None: self.begin_date = self.strategy_option.begin_date() else: self.begin_date = begin_date if end_date is None: self.end_date = self.strategy_option.end_date() else: self.end_date = end_date self.dm = DataModule() self.code_daily_cache = dict()
def __init__(self, strategy_option, begin_date=None, end_date=None): self.strategy_option = strategy_option if begin_date is None: self.begin_date = self.strategy_option.begin_date() else: self.begin_date = begin_date if end_date is None: self.end_date = self.strategy_option.end_date() else: self.end_date = end_date self.dm = DataModule() self.code_daily_cache = dict() self.logger = QuantLogger('backtest') self.candidatesLogger = QuantLogger('candidates')
def compute(self, begin_date, end_date): codes = get_all_codes() dm = DataModule() for code in codes: df_daily = dm.get_k_data(code, begin_date=begin_date, end_date=end_date) if df_daily.index.size == 0: continue # 当日放量下跌 df_daily['change'] = df_daily['close'] - df_daily['pre_close'] df_daily = df_daily[df_daily['change'] < 0] df_daily['last_volume'] = df_daily['volume'].shift(1) df_daily.dropna(inplace=True) df_daily['volume_change'] = round(df_daily['volume']/df_daily['last_volume'], 2) df_daily = df_daily[df_daily['volume_change'] > 1.5] # 收的阴线实体不大 df_daily['entity'] = round(abs((df_daily['open'] -df_daily['close'])) * 100/df_daily['close'], 2) df_daily = df_daily[df_daily['entity'] < 3] # 大部分时间在昨日之上运行 df_daily.set_index(['date'], 1, inplace=True) update_requests = [] for date in df_daily.index: # 大部分时间在昨日之上运行 pre_close = df_daily.loc[date]['pre_close'] df_minute = dm.get_k_data(code, period='M1', begin_date=date, end_date=date) df_minute = df_minute[df_minute['close'] > pre_close] if df_minute.index.size > 150: update_requests.append(UpdateOne({ 'code': code, 'date': date}, {'$set': {'code': code, 'date': date}}, upsert=True)) if len(update_requests) > 0: save_result = self.collection.bulk_write(update_requests, ordered=False) print('股票代码: %s, 因子: %s, 插入:%4d, 更新: %4d' % (code, self.name, save_result.upserted_count, save_result.modified_count), flush=True)
def is_stop(self, code, date): """ 判断股票在当前日期是否需要止损 :param code: 股票代码 :param date: 日期 :return: True - 止损, False - 不止损 """ holding_stock = self.account.get_holding(code) print('止损判断:%s' % code, flush=True) print(holding_stock, flush=True) dm = DataModule() if holding_stock is not None: df_daily = dm.get_k_data(code, autype=None, begin_date=date, end_date=date) if df_daily.index.size > 0: df_daily.set_index(['date'], 1, inplace=True) profit = (holding_stock['volume'] * df_daily.loc[date]['close'] - holding_stock['cost']) \ * 100 / holding_stock['cost'] return (profit < 0) & (abs(profit) >= abs(self.max_loss)) return False
def compute(self, begin_date, end_date): print(self.name, flush=True) dm = DataModule() df_daily = dm.get_k_data() print(df_daily)
def get_option_stocks(self): """ 实现股票池选股逻辑,找到指定日期范围的候选股票 条件:0 < PE < 30, 按从小到大排序,剔除停牌后,取前100个;再平衡周期:7个交易日 :return: tuple,再平衡的日期列表,以及一个dict(key: 再平衡日, value: 当期的股票列表) """ factor_module = FactorModule() dm = DataModule() # 因为上证指数没有停牌不会缺数,所以用它作为交易日历, szzz_hq_df = dm.get_k_data('000001', index=True, begin_date=self.begin_date, end_date=self.end_date) all_dates = list(szzz_hq_df['date']) # 缓存股票和其对应有交易的日期 code_dates_cache = dict() # 调整日和其对应的股票 rebalance_date_codes_dict = dict() rebalance_dates = [] # 保存上一期的股票池 last_phase_codes = [] # 所有的交易日数 dates_count = len(all_dates) # 用再平衡周期作为步长循环 for index in range(0, dates_count, self.interval): # 当前的调整日 rebalance_date = all_dates[index] # 获取本期符合条件的备选股票 df_pe = factor_module.get_single_date_factors('pe', rebalance_date) df_pe.sort_values('pe', ascending=True, inplace=True) # 只保留小于30的数据 df_pe = df_pe[(0 < df_pe['pe']) & (df_pe['pe'] < 30)] df_pe.set_index(['code'], inplace=True) this_phase_option_codes = list(df_pe.index)[0:100] print(this_phase_option_codes, flush=True) # 本期入选的股票代码列表 this_phase_codes = [] # 找到在上一期的股票池,但是当前停牌的股票,保留在当期股票池中 if len(last_phase_codes) > 0: for code in last_phase_codes: if code not in list(code_dates_cache.keys()): daily_ks = dm.get_k_data(code, autype=None, begin_date=self.begin_date, end_date=self.end_date) daily_ks.set_index(['date'], inplace=True) code_dates_cache[code] = list(daily_ks.index) if rebalance_date not in code_dates_cache[code]: this_phase_codes.append(code) print('上期停牌的股票:', flush=True) print(this_phase_codes, flush=True) # 剩余的位置用当前备选股票的 option_size = len(this_phase_option_codes) if option_size > (100 - len(this_phase_codes)): this_phase_codes += this_phase_option_codes[ 0:100 - len(this_phase_codes)] else: this_phase_codes += this_phase_option_codes # 当期股票池作为下次循环的上期股票池 last_phase_codes = this_phase_codes # 保存到返回结果中 rebalance_date_codes_dict[rebalance_date] = this_phase_codes rebalance_dates.append(rebalance_date) print('当前最终的备选票:%s' % rebalance_date, flush=True) print(this_phase_codes, flush=True) return rebalance_dates, rebalance_date_codes_dict
def compute(self, begin_date, end_date): """ 计算指定时间段内所有股票的该因子的值,并保存到数据库中 :param begin_date: 开始时间 :param end_date: 结束时间 """ dm = DataModule() # 获取所有股票 codes = get_all_codes() for code in codes: print('计算市盈率, %s' % code) df_daily = dm.get_k_data(code, autype=None, begin_date=begin_date, end_date=end_date) if df_daily.index.size > 0: df_daily.set_index(['date'], 1, inplace=True) update_requests = [] for date in df_daily.index: finance_report = DB_CONN['finance_report'].find_one( { 'code': code, 'report_date': { '$regex': '\d{4}-12-31' }, 'announced_date': { '$lte': date } }, sort=[('announced_date', DESCENDING)]) if finance_report is None: continue # 计算滚动市盈率并保存到daily_k中 eps = 0 if finance_report['eps'] != '-': eps = finance_report['eps'] # 计算PE if eps != 0: pe = round(df_daily.loc[date]['close'] / eps, 3) print('%s, %s, %s, eps: %5.2f, pe: %6.2f' % (code, date, finance_report['announced_date'], finance_report['eps'], pe), flush=True) update_requests.append( UpdateOne({ 'code': code, 'date': date }, { '$set': { 'code': code, 'date': date, 'pe': pe } }, upsert=True)) if len(update_requests) > 0: save_result = self.collection.bulk_write(update_requests, ordered=False) print('股票代码: %s, 因子: %s, 插入:%4d, 更新: %4d' % (code, self.name, save_result.upserted_count, save_result.modified_count), flush=True)
def __init__(self): self.holding = dict() self.holding_codes = set() self.dm = DataModule()
def analyze(self): # 初始化对数据管理子系统接口的调用 dm = DataModule() # 初始化对因子管理子系统接口的调用 fm = FactorModule() # 获取分析周期内的 all_dates = get_trading_dates(self.begin_date, self.end_date) # 首档和末档,股票代码和后复权价格的Dictionary top_dailies = dict() bottom_dailies = dict() # 暂存上一个调整 last_adjust_date = None # 设置沪深300的首日值 hs300_k = dm.get_k_data('000300', index=True, begin_date=all_dates[0], end_date=all_dates[0]) self.hs300_first_value = hs300_k.loc[0]['close'] # 计算每日收益 for index in range(0, len(all_dates), self.interval): adjust_date = all_dates[index] # 获取因子值,按照指定的顺序排序 df_factor = fm.get_single_date_factors(self.factor, adjust_date) if df_factor.index.size == 0: continue df_factor.sort_values(self.factor, ascending=self.ascending, inplace=True) # 将股票代码设为index df_factor.set_index(['code'], inplace=True) # 获取当日所有股票的行情 df_dailies = dm.get_one_day_k_data(autype='hfq', date=adjust_date) # 将code设为index df_dailies.set_index(['code'], inplace=True) # 计算收益 self.compute_profit(last_adjust_date, df_dailies, top_dailies, bottom_dailies, adjust_date) # 删除停牌股票 df_dailies = df_dailies[df_dailies['is_trading']] # 计算每当包含的股票数 total_size = df_dailies.index.size single_position_count = int(total_size / self.position) # 调整首档组合 self.adjust_top_position(top_dailies, df_factor, df_dailies, single_position_count) # 调整末档组合 self.adjust_bottom_position(bottom_dailies, df_factor, df_dailies, single_position_count) # 保存上一个调整日 last_adjust_date = adjust_date # 生成零投资组合的组合收益 self.profit_df[ 'portfolio'] = self.profit_df['top'] - self.profit_df['bottom'] self.draw()
def compute_profit(self, last_adjust_date, df_dailies, top_dailies, bottom_dailies, adjust_date): """ 计算收益 :param last_adjust_date: 上一个调整日 :param df_dailies: :param top_dailies: :param bottom_dailies: :param adjust_date: 当前调整日 :return: """ # 只有存在上一个调整日,才计算上期的收益 if last_adjust_date is not None: # 计算首档收益 top_profit = self.compute_average_profit(df_dailies, top_dailies) # 计算末档收益 bottom_profit = self.compute_average_profit( df_dailies, bottom_dailies) # 计算组合收益 portfolio_profit = top_profit[0] - bottom_profit[0] # 添加结果的DataFrame中 self.profit_df.loc[last_adjust_date] = { 'top': top_profit[0], 'bottom': bottom_profit[0], 'portfolio': portfolio_profit } # 计算累积收益(复利方式) # 首档 top_cumulative_profit = round( (self.last_top_net_value * (1 + top_profit[0] / 100) - 1) * 100, 2) self.last_top_net_value *= (1 + top_profit[0] / 100) # 末档 bottom_cumulative_profit = round( (self.last_bottom_net_value * (1 + bottom_profit[0] / 100) - 1) * 100, 2) self.last_bottom_net_value *= (1 + bottom_profit[0] / 100) # 组合 portfolio_cumulative_profit = round( (self.last_portfolio_net_value * (1 + portfolio_profit / 100) - 1) * 100, 2) self.last_portfolio_net_value *= (1 + portfolio_profit / 100) # 计算沪深300的累计收益 dm = DataModule() hs300_k = dm.get_k_data('000300', index=True, begin_date=adjust_date, end_date=adjust_date) hs300_k.set_index(['date'], 1, inplace=True) hs300_profit = (hs300_k.loc[adjust_date]['close'] - self.hs300_first_value) / self.hs300_first_value self.cumulative_profit.loc[last_adjust_date] = { 'top': top_cumulative_profit, 'bottom': bottom_cumulative_profit, 'portfolio': portfolio_cumulative_profit, 'hs300': hs300_profit } self.count_df.loc[last_adjust_date] = { 'top': top_profit[1], 'bottom': bottom_profit[1] }
def statistic_profit(self): """ 统计股票池的收益 """ # 设定评测周期 rebalance_dates, codes_dict = self.get_option_stocks() dm = DataModule() # 用DataFrame保存收益 df_profit = DataFrame(columns=['profit', 'hs300']) df_profit.loc[rebalance_dates[0]] = {'profit': 0, 'hs300': 0} # 获取沪深300在统计周期内的第一天的值 hs300_k = dm.get_k_data('000300', index=True, begin_date=rebalance_dates[0], end_date=rebalance_dates[0]) hs300_begin_value = hs300_k.loc[hs300_k.index[0]]['close'] # 通过净值计算累计收益 net_value = 1 for _index in range(1, len(rebalance_dates) - 1): last_rebalance_date = rebalance_dates[_index - 1] current_rebalance_date = rebalance_dates[_index] # 获取上一期的股票池 codes = codes_dict[last_rebalance_date] # 统计当前的收益 profit_sum = 0 # 参与统计收益的股票个数 profit_code_count = 0 for code in codes: daily_ks = dm.get_k_data(code, autype='hfq', begin_date=last_rebalance_date, end_date=current_rebalance_date) index_size = daily_ks.index.size # 如果没有数据,则跳过,长期停牌 if index_size == 0: continue # 买入价 in_price = daily_ks.loc[daily_ks.index[0]]['close'] # 卖出价 out_price = daily_ks.loc[daily_ks.index[index_size - 1]]['close'] # 股票池内所有股票的收益 profit_sum += (out_price - in_price) / in_price profit_code_count += 1 profit = round(profit_sum / profit_code_count, 4) hs300_k_current = dm.get_k_data('000300', index=True, begin_date=current_rebalance_date, end_date=current_rebalance_date) hs300_close = hs300_k_current.loc[ hs300_k_current.index[0]]['close'] # 计算净值和累积收益 net_value = net_value * (1 + profit) df_profit.loc[current_rebalance_date] = { 'profit': round((net_value - 1) * 100, 4), 'hs300': round((hs300_close - hs300_begin_value) * 100 / hs300_begin_value, 4) } print(df_profit) # 绘制曲线 df_profit.plot(title='Stock Pool Profit Statistic', kind='line') # 显示图像 plt.show()
def compute(self, begin_date=None, end_date=None): """ 计算指定日期内的信号 :param begin_date: 开始日期 :param end_date: 结束日期 """ codes = get_all_codes() dm = DataModule() for code in codes: try: df_dailies = dm.get_k_data(code, autype='hfq', begin_date=begin_date, end_date=end_date) if df_dailies.index.size == 0: continue # 计算MA10 df_dailies['ma'] = df_dailies['close'].rolling(10).mean() # 计算当日收盘和MA10的差值 df_dailies['delta'] = df_dailies['close'] - df_dailies['ma'] # 删除不再使用的ma和close列 df_dailies.drop(['ma', 'close'], 1, inplace=True) # 判断突破类型 index_size = df_dailies.index.size breaks = [0] for index in range(1, index_size): # 如果当前日期为停牌状态,则后面连续11日不参与计算 if df_dailies.loc[ df_dailies.index[index]]['is_trading'] is False: count = 10 while count > 0: index += 1 count -= 1 breaks.append(0) index += 1 last = df_dailies.loc[df_dailies.index[index - 1]]['delta'] current = df_dailies.loc[df_dailies.index[index]]['delta'] # 向上突破设为1,向下突破设为-1,不是突破设为0 break_direction = 1 if last <= 0 < current else -1 if last >= 0 > current else 0 breaks.append(break_direction) # 设置突破信号 df_dailies['break'] = breaks # 将日期作为索引 df_dailies.set_index(['date'], 1, inplace=True) # 删除不再使用的trade_status和delta数据列 df_dailies.drop(['is_trading', 'delta'], 1, inplace=True) # 只保留突破的日期 df_dailies = df_dailies[df_dailies['break'] != 0] # 将信号保存到数据库 update_requests = [] for index in df_dailies.index: doc = { 'code': code, 'date': index, # 方向,向上突破 up,向下突破 down 'direction': 'up' if df_dailies.loc[index]['break'] == 1 else 'down' } update_requests.append( UpdateOne(doc, {'$set': doc}, upsert=True)) if len(update_requests) > 0: update_result = self.collection.bulk_write(update_requests, ordered=False) print('%s, upserted: %4d, modified: %4d' % (code, update_result.upserted_count, update_result.modified_count), flush=True) except: traceback.print_exc()
def __init__(self, account, strategy_option): BasePosition.__init__(self, account, strategy_option) self.dm = DataModule()
def __init__(self): self.dm = DataModule()
def __init__(self, account, max_loss): BaseStopLoss.__init__(self, account) self.max_loss = max_loss self.dm = DataModule()
def compute(self, begin_date=None, end_date=None): """ 计算指定时间段内所有股票的该因子的值,并保存到数据库中 :param begin_date: 开始时间 :param end_date: 结束时间 """ dm = DataModule() # 如果没有指定日期范围,则默认为计算当前交易日的数据 if begin_date is None: begin_date = datetime.now().strftime('%Y-%m-%d') if end_date is None: end_date = datetime.now().strftime('%Y-%m-%d') dates = get_trading_dates(begin_date, end_date) for date in dates: # 查询出股票在某一交易日的总股本 df_basics = dm.get_stock_basic_at(date) if df_basics.index.size == 0: continue # 将索引改为code df_basics.set_index(['code'], 1, inplace=True) # 查询出股票在某一个交易日的收盘价 df_dailies = dm.get_one_day_k_data(autype=None, date=date) if df_dailies.index.size == 0: continue # 将索引设为code df_dailies.set_index(['code'], 1, inplace=True) update_requests = [] for code in df_dailies.index: try: # 股价 close = df_dailies.loc[code]['close'] # 总股本 total_shares = df_basics.loc[code]['totals'] # 总市值 = 股价 * 总股本 total_capital = round(close * total_shares, 2) print('%s, %s, mkt_cap: %15.2f' % (code, date, total_capital), flush=True) update_requests.append( UpdateOne( {'code': code, 'date': date}, {'$set': {'code': code, 'date': date, self.name: total_capital}}, upsert=True)) except: print('计算规模因子时发生异常,股票代码:%s,日期:%s' % (code, date), flush=True) if len(update_requests) > 0: save_result = self.collection.bulk_write(update_requests, ordered=False) print('股票代码: %s, 因子: %s, 插入:%4d, 更新: %4d' % (code, self.name, save_result.upserted_count, save_result.modified_count), flush=True)
def __init__(self, begin_date, end_date): self.begin_date = begin_date self.end_date = end_date self.dm = DataModule() self.code_daily_cache = dict()
def __init__(self, account, max_profit, profit_drawdown): BaseStopProfit.__init__(self, account) self.max_profit = max_profit self.profit_drawdown = profit_drawdown self.dm = DataModule()
def compute(self, begin_date, end_date): """ 计算指定日期内的信号 :param begin_date: 开始日期 :param end_date: 结束日期 """ all_codes = get_all_codes() dm = DataModule() N = 20 k = 2 for code in all_codes: try: df_daily = dm.get_k_data(code, autype='hfq', begin_date=begin_date, end_date=end_date) # 计算MB,盘后计算,这里用当日的Close df_daily['MID'] = df_daily['close'].rolling(N).mean() # 计算STD20 df_daily['std'] = df_daily['close'].rolling(N).std() # 计算UP df_daily['UP'] = df_daily['MID'] + k * df_daily['std'] # 计算down df_daily['DOWN'] = df_daily['MID'] - k * df_daily['std'] # 将日期作为索引 df_daily.set_index(['date'], inplace=True) # 上轨和中轨右移一位 shifted_up = df_daily['UP'].shift(1) shifted_middle = df_daily['MID'].shift(1) # 收盘价突破或者跌破中轨的幅度占上轨和中轨宽度的比例 ref_line = (df_daily['close'] - shifted_middle) / (shifted_up - shifted_middle) ref_prev = ref_line.shift(1) # 找到时间窗口内的最小值 min_val = ref_line.rolling(10).min() # 找到时间窗口内最低点前的最大值 max_leading_value = ref_line.rolling(10).apply( lambda vec: vec[:np.argmin(vec) + 1].max().astype(float), raw=True) # 中轨支撑的作用的范围 delta = 0.15 # 判断是否存在中轨支撑反弹的信号,要求: # 时间窗口的最低点之前的最大值大于delta,最小值的绝对值小于delta,就有一个穿越阈值分界线的动作; # 当前日期在也在阈值之上,表示又从最低点穿越到阈值分界线之上; # 而判断前一日在阈值分界线之下,表示穿越是在当前交易日完成 m_rebound_mask = (abs(min_val) <= delta) & (ref_line > delta) & (ref_prev <= delta) & \ (max_leading_value > delta) # 将信号保存到数据库 update_requests = [] df_daily['m_rebound_mask'] = m_rebound_mask df_daily = df_daily[df_daily['m_rebound_mask']] for date in df_daily.index: doc = {'code': code, 'date': date, 'signal': 'mid_rebound'} update_requests.append( UpdateOne(doc, {'$set': doc}, upsert=True)) if len(update_requests) > 0: update_result = self.collection.bulk_write(update_requests, ordered=False) print('%s, upserted: %4d, modified: %4d' % (code, update_result.upserted_count, update_result.modified_count), flush=True) except: traceback.print_exc()