class Single_bar: """ 用来生成单品种的K线 """ def __init__(self, strategy: StrategyTemplate, vt_symbol: str): """""" # 和portfolio的接口 self.portfolio = strategy self.vt_symbol = vt_symbol # 需要合成的K线周期设置 self.bar_interval = self.portfolio.bar_interval self.bar_frequency = self.portfolio.bar_frequency # K线合成工具和储存容器 self.bg = BarGenerator(self.on_bar, self.bar_interval, self.on_5min_bar, self.bar_frequency) self.am = ArrayManager() # K线合成计数 self.bar_count = 0 def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.bar_count += 1 self.am.update_bar(bar)
class MaSignal(CtaSignal): """""" def __init__(self, fast_window: int, slow_window: int): """""" super(MaSignal, self).__init__() self.fast_window = fast_window self.slow_window = slow_window self.bg = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am = ArrayManager() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.am.update_bar(bar) if not self.am.inited: self.set_signal_pos(0) fast_ma = self.am.sma("c", self.fast_window) slow_ma = self.am.sma("c", self.slow_window) if fast_ma > slow_ma: self.set_signal_pos(1) elif fast_ma < slow_ma: self.set_signal_pos(-1) else: self.set_signal_pos(0)
class CorrelationMonitor(QWidget): signal_new_corr = QtCore.pyqtSignal((dt.datetime, float, float)) signal_process = QtCore.pyqtSignal(int) class DataFetcher(QThread): def __init__(self, parent=None): super().__init__(parent) from KRData.HKData import HKFuture self.hf = HKFuture() self.finished.connect(self.parent().show_data_fetch_finished) def run(self) -> None: parent = self.parent() if parent: parent.raw_data['HSI'] = self.hf.get_main_contract_bars('HSI', start='20190101') def __init__(self): super().__init__() self.interval = 1 self.raw_data = {} self.period = 0 self._selected_row = 0 self.data_fetcher = self.DataFetcher(self) self.hkm = HKMarket() self.data_fetcher.start() self.init_ui() def init_ui(self): self.setWindowTitle('相关性对比') self.setAcceptDrops(True) self.target_chart_widget = KLineWidget() # self.target_chart_widget.interval_combo.setEnabled(False) self.source_chart_widget = MarketDataChartWidget() self.compare_btn = QPushButton('历史数据对照') self.interval_combo = QComboBox() for i in [1, 5, 10, 15, 30, 60]: self.interval_combo.addItem(f'{i} min', i) self.save_btn = QPushButton('保存数据') # self.compare_btn.clicked.connect(self.calc_corr) # self.forward_num = QtWidgets.QLineEdit('30') # self.target_chart_widget.indicator_combo.currentTextChanged.connect(self.source_chart_widget.change_indicator) self.corr_table = QTableWidget() self.corr_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.corr_table.setSelectionMode(QAbstractItemView.SingleSelection) self.corr_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.corr_table.verticalHeader().setVisible(False) self.corr_table.setSortingEnabled(True) # self.corr_table.cellDoubleClicked.connect(self.show_corr_chart) self.process_bar = QtWidgets.QProgressBar() self.vb = QHBoxLayout() inner_vb = QVBoxLayout() inner_vb.addWidget(self.target_chart_widget) btn_hbox = QHBoxLayout() btn_hbox.addWidget(self.compare_btn, 3) btn_hbox.addWidget(self.interval_combo, 1) # btn_hbox.addWidget(self.forward_num, 2) btn_hbox.addWidget(self.process_bar, 5) btn_hbox.addWidget(self.save_btn, 1) inner_vb.addLayout(btn_hbox) inner_vb.addWidget(self.source_chart_widget) self.vb.addLayout(inner_vb, 8) self.vb.addWidget(self.corr_table, 2) self.setLayout(self.vb) self.resize(1500, 1000) self.init_signal() def init_signal(self): def change_interval(index): val = self.interval_combo.itemData(index) self.interval = val self.show_corr_chart(self._selected_row, 0) self.interval_combo.currentIndexChanged.connect(change_interval) self.compare_btn.clicked.connect(self.calc_corr) self.target_chart_widget.indicator_combo.currentTextChanged.connect(self.source_chart_widget.change_indicator) self.corr_table.cellDoubleClicked.connect(self.show_corr_chart) self.source_chart_widget.signal_new_bar_request.connect(self.update_bars_backward) self.signal_process.connect(self.process_bar.setValue) self.signal_new_corr.connect(self.insert_corr) self.save_btn.clicked.connect(self.save_corr_data) def update_bars_backward(self, n): source_data = self.raw_data['HSI'] last_bar = self.bar_generator.last_bar if last_bar is None: return start = last_bar.datetime end = source_data.datetime.shift(-n)[start] data = source_data[start:end] for _, d in data.iterrows(): b = BarData('KRData', d.code, Exchange.HKFE, d.datetime, None, d.volume, 0, d.open, d.high, d.low, d.close) self.bar_generator.update_bar(b) def calc_corr(self): if not self.data_fetcher.isFinished(): QMessageBox.critical(self, 'DataFetcher', '数据未加载完毕!', QMessageBox.Ok) return import scipy.stats as st target_data = self.target_chart_widget.datas source_data = self.raw_data['HSI'] apply_func_dict = {'datetime': 'last', 'code': 'first', 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum', 'trade_date': 'first' } ktype = {'1min': '1T', '5min': '5T', '15min': '15T', '30min': '30T', '60min': '60T', '1day': '1D'}.get(self.target_chart_widget.period) if ktype: self.data = source_data.resample(ktype).apply(apply_func_dict) self.data.dropna(thresh=2, inplace=True) self.data.datetime = self.data.index else: self.data = source_data target_values = target_data.close.values self.process_bar.setValue(0) @numba.jit def corr(nd): return st.pearsonr(nd, target_values) self.period = len(target_data) # ret = source_data.close.rolling(self.period).apply(corr) table = self.corr_table table.clearContents() table.setColumnCount(3) # table.setRowCount(len(ret)) table.setHorizontalHeaderLabels(['datetime', 'corr', 'p']) count = len(self.data) corr_data = [] for i in range(self.period, count, 10): data = (self.data.datetime[i], *corr(self.data.close.values[i - self.period:i])) process_value = (i + 10) * 100 // count self.signal_process.emit(process_value) self.signal_new_corr.emit(*data) corr_data.append(data) else: self.corr_data = pd.DataFrame(corr_data, columns=['datetime', 'corr', 'p']) def insert_corr(self, d, corr, p): table = self.corr_table r = table.rowCount() table.insertRow(r) dt_cell = QTableWidgetItem() dt_cell.setFlags(QtCore.Qt.ItemIsEnabled) dt_cell.setData(Qt.DisplayRole, str(d)) dt_cell.setTextAlignment(QtCore.Qt.AlignCenter) corr_cell = QTableWidgetItem() corr_cell.setFlags(QtCore.Qt.ItemIsEnabled) corr_cell.setData(Qt.DisplayRole, 0 if np.isnan(corr) else corr) corr_cell.setTextAlignment(QtCore.Qt.AlignCenter) p_cell = QTableWidgetItem() p_cell.setFlags(QtCore.Qt.ItemIsEnabled) p_cell.setData(Qt.DisplayRole, p) p_cell.setTextAlignment(QtCore.Qt.AlignCenter) table.setItem(r, 0, dt_cell) table.setItem(r, 1, corr_cell) table.setItem(r, 2, p_cell) def show_corr_chart(self, r, c): self._selected_row = r _end = self.corr_table.item(r, 0).text() source_data = self.raw_data['HSI'] forward = 1 start = self.data.shift(self.period).asof(_end).datetime end = self.data.shift(-forward).asof(_end).datetime data = source_data.loc[start:end] self.source_chart_widget.clear_all() # barList = [] if self.interval >= 60: self.bar_generator = BarGenerator(None, 1, self.source_chart_widget.update_bar, Interval.HOUR) else: self.bar_generator = BarGenerator(None, self.interval, self.source_chart_widget.update_bar, Interval.MINUTE) for _, d in data.iterrows(): b = BarData('KRData', d.code, Exchange.HKFE, d.datetime, None, d.volume, 0, d.open, d.high, d.low, d.close) self.bar_generator.update_bar(b) if d.datetime == parser.parse(_end): last_bar = self.source_chart_widget._manager.get_bar(self.source_chart_widget.last_ix) self.source_chart_widget.add_splitLine(last_bar.datetime) # barList.append(b) # self.source_chart_widget.update_all(barList, [], []) # self.source_chart_widget.add_splitLine(barList[-forward].datetime, offset=0.5) def save_corr_data(self): if not hasattr(self, 'self.corr_data'): return target_data = self.target_chart_widget.datas target_start = target_data.iloc[0].datetime target_end = target_data.iloc[-1].datetime s = {} s['start'] = target_start s['end'] = target_end s['symbol'] = self.target_chart_widget.symbol_line.text() s['period'] = self.target_chart_widget.period s['source'] = self.target_chart_widget.data_source s['data'] = self.corr_data # data.to_excel(f'{target_start}-{target_end}.xls', sheet_name=self.target_chart_widget.period) import pickle with open(f'{target_start.strftime("%Y%m%dT%H%M%S")}_{target_end.strftime("%Y%m%dT%H%M%S")}.pkl', 'wb') as f: pickle.dump(s, f) def load_corr_data(self, file_name): if not self.data_fetcher.isFinished(): QMessageBox.critical(self, 'DataFetcher', '数据未加载完毕!', QMessageBox.Ok) return import pickle with open(file_name, 'rb') as f: s = pickle.load(f) self.target_chart_widget.symbol_line.setText(s['symbol']) self.target_chart_widget.datetime_from.setDateTime(s['start']) self.target_chart_widget.datetime_to.setDateTime(s['end']) self.target_chart_widget.interval_combo.setCurrentText(s['period']) if s['source'] == 'HK': self.target_chart_widget.source_HK_btn.setChecked(True) elif s['source'] == 'IB': self.target_chart_widget.source_IB_btn.setChecked(True) self.corr_table.clearContents() self.corr_table.setColumnCount(3) # table.setRowCount(len(ret)) self.corr_table.setHorizontalHeaderLabels(['datetime', 'corr', 'p']) for _, d in s['data'].iterrows(): self.insert_corr(d['datetime'], d['corr'], d['p']) source_data = self.raw_data['HSI'] apply_func_dict = {'datetime': 'last', 'code': 'first', 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum', 'trade_date': 'first' } ktype = {'1min': '1T', '5min': '5T', '15min': '15T', '30min': '30T', '60min': '60T', '1day': '1D'}.get(self.target_chart_widget.period) if ktype: self.data = source_data.resample(ktype).apply(apply_func_dict) self.data.dropna(thresh=2, inplace=True) self.data.datetime = self.data.index else: self.data = source_data self.target_chart_widget.query_btn.click() self.period = len(self.target_chart_widget.datas) def show_data_fetch_finished(self): QMessageBox.information(self, 'DataFetcher', '数据加载完毕!', QMessageBox.Ok) def closeEvent(self, a0: QCloseEvent) -> None: self.target_chart_widget.closeEvent(a0) self.source_chart_widget.closeEvent(a0) super().closeEvent(a0) def dragEnterEvent(self, a0: QDragEnterEvent) -> None: super().dragEnterEvent(a0) if a0.mimeData().hasFormat('text/plain'): a0.accept() else: a0.ignore() def dropEvent(self, a0: QDropEvent) -> None: super().dropEvent(a0) file_name = a0.mimeData().text().lstrip('file:/') self.load_corr_data(file_name)
class MACDSignal: """""" def __init__(self, strategy: StrategyTemplate, vt_symbol: str): """""" self.portfolio = strategy self.vt_symbol = vt_symbol self.fast_period = self.portfolio.fast_period self.slow_period = self.portfolio.slow_period self.signal_period = self.portfolio.signal_period self.trailing_percent = self.portfolio.trailing_percent self.fixed_size = self.portfolio.fixed_size self.bar_interval = self.portfolio.bar_interval self.bar_frequency = self.portfolio.bar_frequency self.macd_value = 0 self.intra_trade_high = 0 self.intra_trade_low = 0 self.bg = BarGenerator(self.on_bar, self.bar_interval, self.on_5min_bar, self.bar_frequency) self.am = ArrayManager() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.am.update_bar(bar) if not self.am.inited: return self.portfolio.cancel_all() am = self.am macd, macd_signal, _ = am.macd(self.fast_period, self.slow_period, self.signal_period, array=True) long_trend = (macd[-2] < macd_signal[-2]) and (macd[-1] > macd_signal[-1]) short_trend = (macd[-2] > macd_signal[-2]) and (macd[-1] < macd_signal[-1]) symbol_pos = self.portfolio.get_pos(self.vt_symbol) if symbol_pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if long_trend: open_order = self.portfolio.buy(self.vt_symbol, bar.close_price + 5, self.fixed_size) elif short_trend: open_order = self.portfolio.short(self.vt_symbol, bar.close_price - 5, self.fixed_size) elif symbol_pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price long_stop = self.intra_trade_high * (1 - self.trailing_percent / 100) # if bar.close_price <= long_stop: # close_order = self.portfolio.sell(self.vt_symbol, bar.close_price - 5, abs(symbol_pos)) # self.limit_orders.append(close_order) if short_trend: close_order = self.portfolio.sell(self.vt_symbol, bar.close_price - 5, abs(symbol_pos)) elif symbol_pos < 0: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.intra_trade_high = bar.high_price short_stop = self.intra_trade_low * (1 + self.trailing_percent / 100) # if bar.close_price >= short_stop: # close_order = self.portfolio.cover(self.vt_symbol, bar.high_price + 5, abs(symbol_pos)) # self.limit_orders.append(close_order) if long_trend: close_order = self.portfolio.cover(self.vt_symbol, bar.high_price + 5, abs(symbol_pos))
class KingKeltnerStrategy(CtaTemplate): """""" author = '中科云集' kk_length = 11 kk_dev = 1.6 trailing_percent = 0.8 fixed_size = 1 kk_up = 0 kk_down = 0 intra_trade_high = 0 intra_trade_low = 0 long_vt_orderids = [] short_vt_orderids = [] vt_orderids = [] parameters = ['kk_length', 'kk_dev', 'fixed_size'] variables = ['kk_up', 'kk_down'] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(KingKeltnerStrategy, self).__init__( cta_engine, strategy_name, vt_symbol, setting ) self.bg = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" for orderid in self.vt_orderids: self.cancel_order(orderid) self.vt_orderids.clear() am = self.am am.update_bar(bar) if not am.inited: return self.kk_up, self.kk_down = am.keltner(self.kk_length, self.kk_dev) if self.pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price self.send_oco_order(self.kk_up, self.kk_down, self.fixed_size) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price vt_orderids = self.sell(self.intra_trade_high * (1 - self.trailing_percent / 100), abs(self.pos), True) self.vt_orderids.extend(vt_orderids) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) vt_orderids = self.cover(self.intra_trade_low * (1 + self.trailing_percent / 100), abs(self.pos), True) self.vt_orderids.extend(vt_orderids) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ if self.pos != 0: if self.pos > 0: for short_orderid in self.short_vt_orderids: self.cancel_order(short_orderid) elif self.pos < 0: for buy_orderid in self.long_vt_orderids: self.cancel_order(buy_orderid) for orderid in (self.long_vt_orderids + self.short_vt_orderids): if orderid in self.vt_orderids: self.vt_orderids.remove(orderid) self.put_event() def send_oco_order(self, buy_price, short_price, volume): """""" self.long_vt_orderids = self.buy(buy_price, volume, True) self.short_vt_orderids = self.short(short_price, volume, True) self.vt_orderids.extend(self.long_vt_orderids) self.vt_orderids.extend(self.short_vt_orderids) def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class DemoStrategy(CtaTemplate): """ 策略学习 """ author = "蒋越希" # 定义界面可以配置的参数 fast_window = 10 slow_window = 20 parameters = [ # 快速窗口 "fast_window", # 慢速窗口 "slow_window" ] # 定义变量 fast_ma0 = 0.0 fast_ma1 = 0.0 slow_ma0 = 0.0 slow_ma1 = 0.0 variables = [ "fast_ma0", "fast_ma1", "slow_ma0", "slow_ma1", ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): super(DemoStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) # 在on_window_bar参数里合成K线 self.bg = BarGenerator(self.on_bar, window=5, on_window_bar=self.on_5min_bar, interval=Interval.MINUTE) self.am = ArrayManager() def on_init(self): """ 策略初始化 :return: """ self.write_log("策略初始化") # 10 天 self.load_bar(10) def on_start(self): """ 启动 :return: """ self.write_log("启动") def on_stop(self): """ 策略停止 :return: """ self.write_log("策略停止") def on_tick(self, tick: TickData): """TICK""" self.bg.update_tick(tick) def on_5min_bar(self, bar: BarData): """ 5分钟K线 :param bar: :return: """ am = self.am am.update_bar(bar) if not am.inited: return # 快移动均线 fast_ma = am.sma(self.fast_window, array=True) self.fast_ma0 = fast_ma[-1] self.fast_ma1 = fast_ma[-2] # 慢速移动均线 slow_ma = am.sma(self.slow_window, array=True) self.slow_ma0 = slow_ma[-1] self.slow_ma1 = slow_ma[-2] # 判断均线交叉 # 金叉 cross_over = (self.fast_ma0 >= self.slow_ma0) and (self.fast_ma1 < self.slow_ma1) # 死叉 cross_below = (self.fast_ma0 <= self.slow_ma0) and (self.fast_ma1 > self.slow_ma1) if cross_over: price = bar.close_price + 5 if not self.pos: # 如果没有仓位 # 买入开仓(看涨) self.buy(price, 1) elif self.pos < 0: # 买入平仓 self.cover(price, 1) self.buy(price, 1) elif self.pos > 0: # 如果是 多, 不操作 pass elif cross_below: price = bar.close_price - 5 if not self.pos: # 做空 卖出开仓(看跌) self.short(price, 1) elif self.pos > 0: self.sell(price, 1) self.short(price, 1) self.put_event() def on_bar(self, bar: BarData): """ K 线更新 :param bar: :return: """ self.bg.update_bar(bar)
class StatisticalArbitrageStrategy(SpreadStrategyTemplate): """""" author = "用Python的交易员" open_window = 1 boll_window = 40 boll_dev = 4.9 fixed_pos = 10 payup = 10.0 increase_price = 0.0 # 超价 interval = 5 spread_pos = 0.0 boll_up = 0.0 boll_down = 0.0 boll_mid = 0.0 parameters = [ "boll_window", "boll_dev", "fixed_pos", "payup", "interval", "increase_price" ] variables = ["spread_pos", "boll_up", "boll_down", "boll_mid"] def __init__(self, strategy_engine, strategy_name: str, spread: SpreadData, setting: dict): """""" super().__init__(strategy_engine, strategy_name, spread, setting) self.bg = BarGenerator(self.on_open_spread_bar, self.open_window, self.on_open_spread_bar) self.am = ArrayManager() self.spread_pos = 0.0 self.boll_up = 0.0 self.boll_down = 0.0 self.boll_mid = 0.0 def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") self.put_event() def on_spread_data(self): """ Callback when spread price is updated. 收到差价推送后,合成价差TICK数据 """ #这里的价差tick tick = self.get_spread_tick() self.on_spread_tick(tick) def on_spread_tick(self, tick: TickData): """ Callback when new spread tick data is generated. """ self.bg.update_tick(tick) def on_spread_bar(self, bar: BarData): """ Callback when new spread bar data is generated. """ self.bg.update_bar(bar) def on_open_spread_bar(self, bar: BarData): """ Callback when spread bar data is generated. 目前的策略逻辑: 1、当价差价格大于布林上轨,以当前收盘加低10的价格下单(以市价下单保证成交),当价格跌破中轨时平仓 (做空) 2、当价差价格小于布林下轨,以当前收盘价加10的价格下单,当价格高于中轨时平仓 (做多) 策略优化方向: 1、把目前在分钟价差K线逻辑移到 tick逻辑中实盘,增加细腻度 2、仓位分为四次加减仓,第一次上穿时,开一份,第二次上穿的价格要高于第一次一定比较时,开第二份,一直到满四份。 (这两个参数,一个是份数,一个是跨度(格距)),目的解决如果出现单边短时趋势抗单时爆仓(最后都会回归中轨) 3、回到中轨全部平仓位 """ # 把老算法先停止, self.stop_all_algos() self.am.update_bar(bar) if not self.am.inited: return self.boll_mid = self.am.sma(self.boll_window) self.boll_up, self.boll_down = self.am.boll(self.boll_window, self.boll_dev) if not self.spread_pos: if bar.close_price >= self.boll_up: self.start_short_algo(bar.close_price - self.increase_price, self.fixed_pos, payup=self.payup, interval=self.interval) elif bar.close_price <= self.boll_down: self.start_long_algo(bar.close_price + self.increase_price, self.fixed_pos, payup=self.payup, interval=self.interval) elif self.spread_pos < 0: if bar.close_price <= self.boll_mid: self.start_long_algo(bar.close_price + self.increase_price, abs(self.spread_pos), payup=self.payup, interval=self.interval) else: if bar.close_price >= self.boll_mid: self.start_short_algo(bar.close_price - self.increase_price, abs(self.spread_pos), payup=self.payup, interval=self.interval) self.put_event() def on_spread_pos(self): """ Callback when spread position is updated. """ self.spread_pos = self.get_spread_pos() self.put_event() def on_spread_algo(self, algo: SpreadAlgoTemplate): """ Callback when algo status is updated. """ pass def on_order(self, order: OrderData): """ Callback when order status is updated. """ pass def on_trade(self, trade: TradeData): """ Callback when new trade data is received. """ pass
class BollChannelStrategy(CtaTemplate): """""" author = "中科云集" boll_window = 18 boll_dev = 3.4 cci_window = 10 atr_window = 30 sl_multiplier = 5.2 fixed_size = 1 boll_up = 0 boll_down = 0 cci_value = 0 atr_value = 0 intra_trade_high = 0 intra_trade_low = 0 long_stop = 0 short_stop = 0 parameters = [ "boll_window", "boll_dev", "cci_window", "atr_window", "sl_multiplier", "fixed_size" ] variables = [ "boll_up", "boll_down", "cci_value", "atr_value", "intra_trade_high", "intra_trade_low", "long_stop", "short_stop" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(BollChannelStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_15min_bar(self, bar: BarData): """""" self.cancel_all() am = self.am am.update_bar(bar) if not am.inited: return self.boll_up, self.boll_down = am.boll(self.boll_window, self.boll_dev) self.cci_value = am.cci(self.cci_window) self.atr_value = am.atr(self.atr_window) if self.pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.cci_value > 0: self.buy(self.boll_up, self.fixed_size, True) elif self.cci_value < 0: self.short(self.boll_down, self.fixed_size, True) elif self.pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier self.sell(self.long_stop, abs(self.pos), True) elif self.pos < 0: self.intra_trade_high = bar.high_price self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier self.cover(self.short_stop, abs(self.pos), True) self.put_event() def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class MultiTimeframeStrategy(CtaTemplate): """""" author = "中科云集" rsi_signal = 20 rsi_window = 14 fast_window = 5 slow_window = 20 fixed_size = 1 rsi_value = 0 rsi_long = 0 rsi_short = 0 fast_ma = 0 slow_ma = 0 ma_trend = 0 parameters = [ "rsi_signal", "rsi_window", "fast_window", "slow_window", "fixed_size" ] variables = [ "rsi_value", "rsi_long", "rsi_short", "fast_ma", "slow_ma", "ma_trend" ] def __init__(self, cta_engine, strategy_name, vt_symbol, setting): """""" super(MultiTimeframeStrategy, self).__init__(cta_engine, strategy_name, vt_symbol, setting) self.rsi_long = 50 + self.rsi_signal self.rsi_short = 50 - self.rsi_signal self.bg5 = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am5 = ArrayManager() self.bg15 = BarGenerator(self.on_bar, 15, self.on_15min_bar) self.am15 = ArrayManager() def on_init(self): """ Callback when strategy is inited. """ self.write_log("策略初始化") self.load_bar(10) def on_start(self): """ Callback when strategy is started. """ self.write_log("策略启动") def on_stop(self): """ Callback when strategy is stopped. """ self.write_log("策略停止") def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg5.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg5.update_bar(bar) self.bg15.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.cancel_all() self.am5.update_bar(bar) if not self.am5.inited: return if not self.ma_trend: return self.rsi_value = self.am5.rsi(self.rsi_window) if self.pos == 0: if self.ma_trend > 0 and self.rsi_value >= self.rsi_long: self.buy(bar.close_price + 5, self.fixed_size) elif self.ma_trend < 0 and self.rsi_value <= self.rsi_short: self.short(bar.close_price - 5, self.fixed_size) elif self.pos > 0: if self.ma_trend < 0 or self.rsi_value < 50: self.sell(bar.close_price - 5, abs(self.pos)) elif self.pos < 0: if self.ma_trend > 0 or self.rsi_value > 50: self.cover(bar.close_price + 5, abs(self.pos)) self.put_event() def on_15min_bar(self, bar: BarData): """""" self.am15.update_bar(bar) if not self.am15.inited: return self.fast_ma = self.am15.sma("c", self.fast_window) self.slow_ma = self.am15.sma("c", self.slow_window) if self.fast_ma > self.slow_ma: self.ma_trend = 1 else: self.ma_trend = -1 def on_order(self, order: OrderData): """ Callback of new order data update. """ pass def on_trade(self, trade: TradeData): """ Callback of new trade data update. """ self.put_event() def on_stop_order(self, stop_order: StopOrder): """ Callback of stop order update. """ pass
class TredningFollowingSignal: """""" def __init__(self, strategy: StrategyTemplate, vt_symbol: str): """""" self.portfolio = strategy self.vt_symbol = vt_symbol self.atr_window = self.portfolio.atr_window self.atr_ma_window = self.portfolio.atr_ma_window self.rsi_window = self.portfolio.rsi_window self.rsi_entry = self.portfolio.rsi_entry self.trailing_percent = self.portfolio.trailing_percent self.fixed_size = self.portfolio.fixed_size self.atr_value = 0 self.atr_ma = 0 self.rsi_value = 0 self.rsi_buy = 50 + self.rsi_entry self.rsi_sell = 50 - self.rsi_entry self.intra_trade_high = 0 self.intra_trade_low = 0 self.limit_orders = [] self.bg = BarGenerator(self.on_bar, 5, self.on_5min_bar) self.am = ArrayManager() def on_tick(self, tick: TickData): """ Callback of new tick data update. """ self.bg.update_tick(tick) def on_bar(self, bar: BarData): """ Callback of new bar data update. """ self.bg.update_bar(bar) def on_5min_bar(self, bar: BarData): """""" self.am.update_bar(bar) if not self.am.inited: return self.portfolio.cancel_all() am = self.am atr_array = am.atr(self.atr_window, array=True) self.atr_value = atr_array[-1] self.atr_ma = atr_array[-self.atr_ma_window:].mean() self.rsi_value = am.rsi(self.rsi_window) symbol_pos = self.portfolio.get_pos(self.vt_symbol) if symbol_pos == 0: self.intra_trade_high = bar.high_price self.intra_trade_low = bar.low_price if self.atr_value > self.atr_ma: if self.rsi_value > self.rsi_buy: open_order = self.portfolio.buy(self.vt_symbol, bar.close_price + 5, self.fixed_size) self.limit_orders.append(open_order) elif self.rsi_value < self.rsi_sell: open_order = self.portfolio.short(self.vt_symbol, bar.close_price - 5, self.fixed_size) elif symbol_pos > 0: self.intra_trade_high = max(self.intra_trade_high, bar.high_price) self.intra_trade_low = bar.low_price long_stop = self.intra_trade_high * (1 - self.trailing_percent / 100) if bar.close_price <= long_stop: close_order = self.portfolio.sell(self.vt_symbol, bar.close_price - 5, abs(symbol_pos)) self.limit_orders.append(close_order) elif symbol_pos < 0: self.intra_trade_low = min(self.intra_trade_low, bar.low_price) self.intra_trade_high = bar.high_price short_stop = self.intra_trade_low * (1 + self.trailing_percent / 100) if bar.close_price >= short_stop: close_order = self.portfolio.cover(self.vt_symbol, bar.high_price + 5, abs(symbol_pos)) self.limit_orders.append(close_order)