├── .idea ├── ctpbee_indicator.iml ├── dictionaries │ └── .xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml ├── other.xml ├── vcs.xml └── workspace.xml ├── LICENSE ├── README.md ├── customize ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ └── api.cpython-37.pyc ├── api.py └── customize.py ├── data.json ├── examples ├── atr_strategy.py ├── boll_strategy.py ├── cci_strategy.py ├── close_strategy.py ├── ema_strategy.py ├── kd_strategy.py ├── looper_example.py ├── macd_strategy.py ├── mtm_strategy.py ├── roc_strategy.py ├── rsi_strategy.py ├── sar_strategy.py ├── sma_strategy.py ├── smma_strategy.py ├── stdDev_strategy.py ├── tema_strategy.py ├── trix_strategy.py ├── wma_strategy.py └── wr_strategy.py ├── indicator ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── indicator.cpython-37.pyc │ ├── interface.cpython-37.pyc │ ├── plot.cpython-37.pyc │ └── readfile.cpython-37.pyc ├── indicator.py ├── interface.py ├── json │ └── zn1912.SHFE.json ├── plot.py ├── readfile.py └── txt │ └── orcl-2014.txt ├── test.py └── zn1912.SHFE.json /.idea/ctpbee_indicator.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/dictionaries/.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/other.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ctpbee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ctpbee_indicator 2 | ctpbee里面实现的指标库, 能让你快速实现指标的计算和拿到值 3 | 4 | ```python 5 | from indicator.interface import Indicator 6 | from ctpbee import LooperApi, Vessel 7 | 8 | class SmaStrategy(LooperApi): 9 | 10 | def __init__(self, name): 11 | super().__init__(name) 12 | self.count = 1 13 | self.pos = 0 14 | 15 | self.info = Indicator() # 3分钟bar线 16 | self.info.open_json('indicator/json/zn1912.SHFE.json') # 读取本地数据 17 | 18 | def on_bar(self, bar): 19 | info = self.info 20 | # opens是否要保存数据(默认false不保存) 21 | info.add_bar(bar) 22 | close_price = info.close 23 | # 简单移动平均 默认 15 24 | sma = info.sma() 25 | # 加权移动平均 默认30 26 | wma = info.wma() 27 | # 指数移动平均 默认12 28 | ema = info.ema() 29 | # 随机指标 默认参数 14, 3 30 | k, d = info.kd() 31 | # 相对强度指数 默认 14, 1 32 | rsi = info.rsi() 33 | # 异同移动平均线 默认 12, 20, 9 34 | macd, signal, histo = info.macd() 35 | # 威廉指标 默认 14 36 | wr = info.wr() 37 | # 布林带 默认 20 2 38 | t, m, b = info.boll() 39 | # 默认 10, 15 40 | smma = info.smma() 41 | # 真实平均范围 默认 14 42 | atr = info.atr() 43 | # 标准偏差 默认 20 44 | stdDev = info.stdDev() 45 | # 三重指数平滑移动平均 默认 15, 1 46 | trix = info.trix() 47 | # 变化率 默认 12 48 | roc = info.roc() 49 | # 动量指标 默认 12 50 | mtm = info.mtm() 51 | # 三式移动平均 默认 25 52 | tema = info.tema() 53 | # 顺势指标 cci 默认 20 54 | cci = info.cci() 55 | # 抛物线指标 sar 默认 2, 0.02, 0.20 56 | sar = info.sar() 57 | if close_price[-1] > sma[-1]: 58 | print("True") 59 | pass 60 | else: 61 | print("False") 62 | pass 63 | 64 | ``` 65 | # example(简单列子) 66 | 67 | 例子一 68 | ```python 69 | import json 70 | from datetime import datetime, date 71 | from ctpbee import LooperApi, Vessel 72 | from ctpbee.constant import Direction 73 | from indicator.interface import Indicator 74 | 75 | 76 | def get_data(start, end, symbol, exchange, level): 77 | """ using rqdatac to make an example """ 78 | # import rqdatac as rq 79 | # from rqdatac import get_price, id_convert 80 | # username = "license" 81 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 82 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 83 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 84 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 85 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 86 | # host = "rqdatad-pro.ricequant.com" 87 | # port = 16011 88 | # rq.init(username, password, (host, port)) 89 | # symbol_rq = id_convert(symbol) 90 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 91 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 92 | # origin = data.to_dict(orient='records') 93 | # result = [] 94 | # for x in origin: 95 | # do = {} 96 | # do['open_price'] = x['open'] 97 | # do['low_price'] = x['low'] 98 | # do['high_price'] = x['high'] 99 | # do['close_price'] = x['close'] 100 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 101 | # do['symbol'] = symbol 102 | # do['local_symbol'] = symbol + "." + exchange 103 | # do['exchange'] = exchange 104 | # result.append(do) 105 | # return result 106 | 107 | def get_a_strategy(): 108 | 109 | class SmaStrategy(LooperApi): 110 | 111 | def __init__(self, name): 112 | super().__init__(name) 113 | self.count = 1 114 | self.pos = 0 115 | 116 | self.bar_3 = Indicator() # 3分钟bar线 117 | self.bar_3.open_json('indicator/json/zn1912.SHFE.json') # 读取本地数据 118 | 119 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 120 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 121 | 122 | def on_bar(self, bar): 123 | # todo: 收盘连长 124 | """ """ 125 | self.bar_3.add_bar(bar) 126 | close = self.bar_3.close 127 | 128 | if self.allow_max_price < close[-1] and self.pos > 0: 129 | self.action.sell(bar.close_price, self.pos, bar) 130 | 131 | if self.allow_low_price > close[-1] and self.pos > 0: 132 | self.action.sell(bar.close_price, self.pos, bar) 133 | 134 | # 接连三天涨 135 | if close[-1] > close[-2] > close[-3]: 136 | # 没有就买 137 | if self.pos == 0: 138 | self.action.buy(bar.close_price, 1, bar) 139 | 140 | def on_trade(self, trade): 141 | if trade.direction == Direction.LONG: 142 | self.pos += trade.volume 143 | else: 144 | self.pos -= trade.volume 145 | 146 | def init_params(self, data): 147 | """""" 148 | # print("我在设置策略参数") 149 | return SmaStrategy("double_ma") 150 | 151 | def save_data_json(data): 152 | result = {"result": data} 153 | 154 | class CJsonEncoder(json.JSONEncoder): 155 | def default(self, obj): 156 | if isinstance(obj, datetime): 157 | return obj.strftime('%Y-%m-%d %H:%M:%S') 158 | elif isinstance(obj, date): 159 | return obj.strftime('%Y-%m-%d') 160 | else: 161 | return json.JSONEncoder.default(self, obj) 162 | 163 | with open("data.json", "w") as f: 164 | json.dump(result, f, cls=CJsonEncoder) 165 | 166 | def load_data(): 167 | with open("data.json", "r") as f: 168 | data = json.load(f) 169 | return data.get("result") 170 | 171 | def run_main(data): 172 | vessel = Vessel() 173 | vessel.add_data(data) 174 | stra = get_a_strategy() 175 | vessel.add_strategy(stra) 176 | vessel.set_params({"looper": 177 | {"initial_capital": 100000, 178 | "commission": 0.005, 179 | "deal_pattern": "price", 180 | "size_map": {"ag1912.SHFE": 15}, 181 | "today_commission": 0.005, 182 | "yesterday_commission": 0.02, 183 | "close_commission": 0.005, 184 | "slippage_sell": 0, 185 | "slippage_cover": 0, 186 | "slippage_buy": 0, 187 | "slippage_short": 0, 188 | "close_pattern": "yesterday", 189 | }, 190 | "strategy": {} 191 | }) 192 | vessel.run() 193 | from pprint import pprint 194 | result = vessel.get_result() 195 | pprint(result) 196 | 197 | 198 | if __name__ == '__main__': 199 | data = load_data() 200 | for x in data: 201 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 202 | run_main(data) 203 | ``` 204 | 205 | 例子二 206 | ```python 207 | import json 208 | from datetime import datetime, date 209 | from ctpbee import LooperApi, Vessel 210 | from ctpbee.constant import Direction 211 | from indicator.interface import Indicator 212 | 213 | def get_data(start, end, symbol, exchange, level): 214 | """ using rqdatac to make an example """ 215 | # import rqdatac as rq 216 | # from rqdatac import get_price, id_convert 217 | # username = "license" 218 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 219 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 220 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 221 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 222 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 223 | # host = "rqdatad-pro.ricequant.com" 224 | # port = 16011 225 | # rq.init(username, password, (host, port)) 226 | # symbol_rq = id_convert(symbol) 227 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 228 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 229 | # origin = data.to_dict(orient='records') 230 | # result = [] 231 | # for x in origin: 232 | # do = {} 233 | # do['open_price'] = x['open'] 234 | # do['low_price'] = x['low'] 235 | # do['high_price'] = x['high'] 236 | # do['close_price'] = x['close'] 237 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 238 | # do['symbol'] = symbol 239 | # do['local_symbol'] = symbol + "." + exchange 240 | # do['exchange'] = exchange 241 | # result.append(do) 242 | # return result 243 | 244 | def get_a_strategy(): 245 | 246 | class SmaStrategy(LooperApi): 247 | 248 | def __init__(self, name): 249 | super().__init__(name) 250 | self.count = 1 251 | self.pos = 0 252 | self.bar_3 = Indicator() # 3分钟线 253 | 254 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 255 | self.allow_low_price = 4100 # 设置价格下限 当价格低出这里就卖 防止巨亏 256 | 257 | self.bar_3.open_json('indicator/json/zn1912.SHFE.json') 258 | 259 | # self.bar_3.open_csv('indicator/txt/orcl-2014.txt') 260 | 261 | def on_bar(self, bar): 262 | # todo: 简单移动平均线 263 | """ """ 264 | self.bar_3.add_bar(bar) 265 | close = self.bar_3.close 266 | # 简单移动平均线 267 | sma = self.bar_3.sma() 268 | 269 | if self.allow_max_price <= close[-1] and self.pos > 0: 270 | self.action.sell(bar.close_price, self.pos, bar) 271 | 272 | if self.allow_low_price >= close[-1] and self.pos > 0: 273 | self.action.sell(bar.close_price, self.pos, bar) 274 | 275 | # 接连两天涨 买进 276 | if close[-1] > sma[-1] and close[-2] > sma[-2]: 277 | 278 | if self.pos == 0: 279 | self.action.buy(bar.close_price, 1, bar) 280 | 281 | elif self.pos < 0: 282 | self.action.cover(bar.close_price, 1, bar) 283 | self.action.buy(bar.close_price, 1, bar) 284 | # 接连跌就卖 285 | if close[-1] < sma[-1] and close[-2] < sma[-2]: 286 | if self.pos == 0: 287 | pass 288 | elif self.pos > 0: 289 | self.action.sell(bar.close_price, 1, bar) 290 | self.action.short(bar.close_price, 1, bar) 291 | 292 | def on_trade(self, trade): 293 | if trade.direction == Direction.LONG: 294 | self.pos += trade.volume 295 | else: 296 | self.pos -= trade.volume 297 | 298 | def init_params(self, data): 299 | """""" 300 | # print("我在设置策略参数") 301 | 302 | return SmaStrategy("double_ma") 303 | 304 | def save_data_json(data): 305 | result = {"result": data} 306 | 307 | class CJsonEncoder(json.JSONEncoder): 308 | def default(self, obj): 309 | if isinstance(obj, datetime): 310 | return obj.strftime('%Y-%m-%d %H:%M:%S') 311 | elif isinstance(obj, date): 312 | return obj.strftime('%Y-%m-%d') 313 | else: 314 | return json.JSONEncoder.default(self, obj) 315 | 316 | with open("data.json", "w") as f: 317 | json.dump(result, f, cls=CJsonEncoder) 318 | 319 | def load_data(): 320 | with open("data.json", "r") as f: 321 | data = json.load(f) 322 | return data.get("result") 323 | 324 | def run_main(data): 325 | vessel = Vessel() 326 | vessel.add_data(data) 327 | stra = get_a_strategy() 328 | vessel.add_strategy(stra) 329 | vessel.set_params({"looper": 330 | {"initial_capital": 100000, 331 | "commission": 0.005, 332 | "deal_pattern": "price", 333 | "size_map": {"ag1912.SHFE": 15}, 334 | "today_commission": 0.005, 335 | "yesterday_commission": 0.02, 336 | "close_commission": 0.005, 337 | "slippage_sell": 0, 338 | "slippage_cover": 0, 339 | "slippage_buy": 0, 340 | "slippage_short": 0, 341 | "close_pattern": "yesterday", 342 | }, 343 | "strategy": {} 344 | }) 345 | vessel.run() 346 | from pprint import pprint 347 | result = vessel.get_result() 348 | pprint(result) 349 | 350 | if __name__ == '__main__': 351 | data = load_data() 352 | for x in data: 353 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 354 | run_main(data) 355 | ``` 356 | 357 | 列子三 358 | ```python 359 | import json 360 | from datetime import datetime, date 361 | from ctpbee import LooperApi, Vessel 362 | from ctpbee.constant import Direction 363 | from indicator.interface import Indicator 364 | 365 | def get_data(start, end, symbol, exchange, level): 366 | """ using rqdatac to make an example """ 367 | # import rqdatac as rq 368 | # from rqdatac import get_price, id_convert 369 | # username = "license" 370 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 371 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 372 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 373 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 374 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 375 | # host = "rqdatad-pro.ricequant.com" 376 | # port = 16011 377 | # rq.init(username, password, (host, port)) 378 | # symbol_rq = id_convert(symbol) 379 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 380 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 381 | # origin = data.to_dict(orient='records') 382 | # result = [] 383 | # for x in origin: 384 | # do = {} 385 | # do['open_price'] = x['open'] 386 | # do['low_price'] = x['low'] 387 | # do['high_price'] = x['high'] 388 | # do['close_price'] = x['close'] 389 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 390 | # do['symbol'] = symbol 391 | # do['local_symbol'] = symbol + "." + exchange 392 | # do['exchange'] = exchange 393 | # result.append(do) 394 | # return result 395 | 396 | def get_a_strategy(): 397 | 398 | class SmaStrategy(LooperApi): 399 | 400 | def __init__(self, name): 401 | super().__init__(name) 402 | self.count = 1 403 | self.pos = 0 404 | 405 | self.bar_3 = Indicator() # 3分钟线 406 | 407 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 408 | self.allow_low_price = 4100 # 设置价格下限 当价格低出这里就卖 防止巨亏 409 | 410 | self.bar_3.open_json('indicator/json/zn1912.SHFE.json') 411 | 412 | # self.bar_3.open_csv('indicator/txt/orcl-2014.txt') 413 | 414 | def on_bar(self, bar): 415 | # todo: 简单异同移动平均 macd 416 | """ """ 417 | self.bar_3.add_bar(bar) 418 | close = self.bar_3.close 419 | # 简单异同移动平均 macd 420 | macd, signal, histo = self.bar_3.macd() 421 | 422 | if self.allow_max_price <= close[-1] and self.pos > 0: 423 | self.action.sell(bar.close_price, self.pos, bar) 424 | 425 | if self.allow_low_price >= close[-1] and self.pos > 0: 426 | self.action.sell(bar.close_price, self.pos, bar) 427 | 428 | if histo[-1] > 0: 429 | if self.pos == 0: 430 | self.action.buy(bar.close_price, 1, bar) 431 | else: 432 | if self.pos > 0: 433 | self.action.sell(bar.close_price, 1, bar) 434 | self.action.short(bar.close_price, 1, bar) 435 | 436 | def on_trade(self, trade): 437 | if trade.direction == Direction.LONG: 438 | self.pos += trade.volume 439 | else: 440 | self.pos -= trade.volume 441 | 442 | def init_params(self, data): 443 | """""" 444 | # print("我在设置策略参数") 445 | 446 | return SmaStrategy("double_ma") 447 | 448 | def save_data_json(data): 449 | result = {"result": data} 450 | 451 | class CJsonEncoder(json.JSONEncoder): 452 | def default(self, obj): 453 | if isinstance(obj, datetime): 454 | return obj.strftime('%Y-%m-%d %H:%M:%S') 455 | elif isinstance(obj, date): 456 | return obj.strftime('%Y-%m-%d') 457 | else: 458 | return json.JSONEncoder.default(self, obj) 459 | 460 | with open("data.json", "w") as f: 461 | json.dump(result, f, cls=CJsonEncoder) 462 | 463 | def load_data(): 464 | with open("data.json", "r") as f: 465 | data = json.load(f) 466 | return data.get("result") 467 | 468 | def run_main(data): 469 | vessel = Vessel() 470 | vessel.add_data(data) 471 | stra = get_a_strategy() 472 | vessel.add_strategy(stra) 473 | vessel.set_params({"looper": 474 | {"initial_capital": 100000, 475 | "commission": 0.005, 476 | "deal_pattern": "price", 477 | "size_map": {"ag1912.SHFE": 15}, 478 | "today_commission": 0.005, 479 | "yesterday_commission": 0.02, 480 | "close_commission": 0.005, 481 | "slippage_sell": 0, 482 | "slippage_cover": 0, 483 | "slippage_buy": 0, 484 | "slippage_short": 0, 485 | "close_pattern": "yesterday", 486 | }, 487 | "strategy": {} 488 | }) 489 | vessel.run() 490 | from pprint import pprint 491 | result = vessel.get_result() 492 | pprint(result) 493 | 494 | if __name__ == '__main__': 495 | data = load_data() 496 | for x in data: 497 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 498 | run_main(data) 499 | ``` 500 | -------------------------------------------------------------------------------- /customize/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/customize/__init__.py -------------------------------------------------------------------------------- /customize/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/customize/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /customize/__pycache__/api.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/customize/__pycache__/api.cpython-37.pyc -------------------------------------------------------------------------------- /customize/api.py: -------------------------------------------------------------------------------- 1 | from indicator.plot import Scheduler 2 | 3 | 4 | def inited(): 5 | """ 6 | 用户判断是否满足计算指标 7 | :return: bool 8 | """ 9 | return Scheduler.inited 10 | 11 | 12 | def O(): 13 | """ 14 | Get open price time series. 15 | """ 16 | return Scheduler.ret_open 17 | 18 | 19 | def H(): 20 | """ 21 | Get high price time series. 22 | """ 23 | return Scheduler.ret_high 24 | 25 | 26 | def L(): 27 | """ 28 | Get low price time series. 29 | """ 30 | return Scheduler.ret_low 31 | 32 | 33 | def C(): 34 | """ 35 | Get low price time series 36 | :return: 37 | """ 38 | return Scheduler.ret_close 39 | 40 | 41 | def volume(): 42 | """ 43 | Get volume number 44 | :return: 45 | """ 46 | return Scheduler.ret_volume 47 | 48 | 49 | def open_csv(file: str, start_time=None, end_time=None): 50 | """ 51 | open TXT file 52 | data_type: 53 | Date,Open,High,Low,Close,Volume 54 | '2019-01-07 00:00:00', 3831.0, 3847.0, 3831.0, 3840.0, 554 55 | '2019-01-08 00:00:00', 3841.0, 3841.0, 3833.0, 3836.0, 554 56 | ... 57 | :param file: name 58 | :param start_time: 59 | :param end_time: 60 | :return: 61 | """ 62 | return Scheduler.open_csv(file, start_time, end_time) 63 | 64 | 65 | def open_json(file: str, start_time=None, end_time=None): 66 | """ 67 | open JSON file 68 | data_type: 69 | {"zn1912.SHFE": [ 70 | ["2014-01-01", 18780.0, 18780.0, 18770.0, 18775.0, 266], 71 | ["2014-01-02", 18775.0, 18780.0, 18770.0, 18770.0, 312], 72 | ... 73 | ] 74 | } 75 | :param file: name 76 | :param start_time: 77 | :param end_time: 78 | :return: 79 | """ 80 | return Scheduler.open_json(file, start_time, end_time) 81 | 82 | 83 | def open_cache(data: list): 84 | """ 85 | read CACHE data 86 | data_type: 87 | [["2014-01-01", 22, 44, 55, 55, 6666], ["2014-01-02", 22, 44, 55, 55, 6666], ...] 88 | :param data: 89 | :return: 90 | """ 91 | return Scheduler.open_cache(data) 92 | 93 | 94 | def add_bar(data, opens=False): 95 | """ 96 | new bar push in array 97 | :param data: bar 98 | :param opens: if True save file else not save (default False) 99 | :return: 100 | """ 101 | Scheduler.update_bar(data, opens) 102 | 103 | 104 | def MA(data, n=5): 105 | 106 | return Scheduler.ma(data, n) 107 | 108 | 109 | def SMA(data, n=15): 110 | 111 | return Scheduler.sma(data, n) 112 | 113 | 114 | def EMA(data, n=12, alpha=None): 115 | 116 | return Scheduler.ema(data, n, alpha) 117 | 118 | 119 | def WMA(data, n=30): 120 | return Scheduler.wma(data, n) 121 | 122 | 123 | def KD(data, n=14, f=3): 124 | return Scheduler.kd(data, n, f) 125 | 126 | 127 | def MACD(data, n=12, m=20, f=9): 128 | return Scheduler.macd(data, n, m, f) 129 | 130 | 131 | def RSI(data, n=14, l=1): 132 | return Scheduler.rsi(data, n, l) 133 | 134 | 135 | def SMMA(data, n=10, alpha=15): 136 | return Scheduler.smma(data, n, alpha) 137 | 138 | 139 | def ATR(data, n=14): 140 | return Scheduler.atr(data, n) 141 | 142 | 143 | def STD(data, n=20): 144 | return Scheduler.stdDev(data, n) 145 | 146 | 147 | def BOLL(data, n=20, m=2): 148 | return Scheduler.boll(data, n, m) 149 | 150 | 151 | def TRIX(data, n=15, m=1): 152 | return Scheduler.trix(data, n, m) 153 | 154 | 155 | def ROC(data, n=12): 156 | return Scheduler.roc(data, n) 157 | 158 | 159 | def MTM(data, n=12): 160 | return Scheduler.mtm(data, n) 161 | 162 | 163 | def TEMA(data, n=25): 164 | return Scheduler.tema(data, n) 165 | 166 | 167 | def WR(data, n=14): 168 | return Scheduler.wr(data, n) 169 | 170 | 171 | def CCI(n=20, f=0.015): 172 | return Scheduler.cci(n, f) 173 | 174 | 175 | def SAR(data, n=2, af=0.02, afmax=0.20): 176 | return Scheduler.sar(data, n, af, afmax) 177 | 178 | 179 | def HHV(data, n=10): 180 | """ 181 | 在一定周期内某一项数据的最大值 182 | :param data: 183 | :param n: 184 | :return: 185 | """ 186 | if data.lower() == "l" or data.lower() == "low": 187 | return max(Scheduler.ret_low[-1 - n:]) 188 | elif data.lower() == "v" or data.lower() == "volume": 189 | return max(Scheduler.ret_volume[-1 - n:]) 190 | elif data.lower() == "h" or data.lower() == "high": 191 | return max(Scheduler.ret_high[-1 - n:]) 192 | elif data.lower() == "c" or data.lower() == "close": 193 | return max(Scheduler.ret_close[-1 - n:]) 194 | else: 195 | return max(data[-1 - n:]) 196 | 197 | 198 | def LLV(data, n=10): 199 | """ 200 | 在一定周期内某一项数据的最小值 201 | :param data: 202 | :param n: 203 | :return: 204 | """ 205 | if data.lower() == "l" or data.lower() == "low": 206 | return min(Scheduler.ret_low[-1 - n:]) 207 | elif data.lower() == "v" or data.lower() == "volume": 208 | return min(Scheduler.ret_volume[-1 - n:]) 209 | elif data.lower() == "h" or data.lower() == "high": 210 | return min(Scheduler.ret_high[-1 - n:]) 211 | elif data.lower() == "c" or data.lower() == "close": 212 | return min(Scheduler.ret_close[-1 - n:]) 213 | else: 214 | return min(data[-1 - n:]) 215 | 216 | 217 | def REF(data, n=1): 218 | """ 219 | 昨日收盘价 ref(c,1)表示昨天的收盘价, ref(v,1)表示昨天的成交量 220 | :param data: 221 | :param n: 222 | :return: 223 | """ 224 | if data.lower() == "l" or data.lower() == "low": 225 | return Scheduler.ret_low[-1 - n] 226 | elif data.lower() == "v" or data.lower() == "volume": 227 | return Scheduler.ret_volume[-1 - n] 228 | elif data.lower() == "h" or data.lower() == "high": 229 | return Scheduler.ret_high[-1 - n] 230 | elif data.lower() == "c" or data.lower() == "close": 231 | return Scheduler.ret_close[-1 - n] 232 | else: 233 | return data[-1 - n] 234 | 235 | 236 | def CROSS(K, D): 237 | """ 238 | 金叉 死叉 239 | :param K: 预信号 240 | :param D: 周转信号 241 | :return: 242 | """ 243 | status = K - D 244 | return status 245 | 246 | 247 | def SUM(data, n=7): 248 | return sum(data[-n:]) 249 | 250 | 251 | def ZIG(data, n): 252 | """ 253 | 转向率 254 | :param data: 0:开盘价,1:最高价,2:最低价,3:收盘价,其余:数组信息 255 | :param n: 变化率 256 | :return: 257 | """ 258 | if data == 0: 259 | steering_rate = (Scheduler.ret_open[-1]-Scheduler.ret_open[-2])/Scheduler.ret_open[-2]*100 260 | elif data == 1: 261 | steering_rate = (Scheduler.ret_high[-1] - Scheduler.ret_high[-2]) / Scheduler.ret_high[-2] * 100 262 | elif data == 2: 263 | steering_rate = (Scheduler.ret_low[-1] - Scheduler.ret_low[-2]) / Scheduler.ret_low[-2] * 100 264 | elif data == 3: 265 | steering_rate = (Scheduler.ret_close[-1] - Scheduler.ret_close[-2]) / Scheduler.ret_close[-2] * 100 266 | else: 267 | steering_rate = (data[-1]-data[-2])/data[-2] 268 | if steering_rate > n: 269 | return True 270 | else: 271 | return False 272 | 273 | 274 | def MIN(self): 275 | pass 276 | -------------------------------------------------------------------------------- /customize/customize.py: -------------------------------------------------------------------------------- 1 | from indicator import interface 2 | import numpy as np 3 | 4 | 5 | class Customize: 6 | """ 7 | 自定义方法类 8 | """ 9 | def __init__(self): 10 | pass 11 | 12 | def method(self): 13 | pass 14 | -------------------------------------------------------------------------------- /examples/atr_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单atr策略 atr = info.atr() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 真实平均范围 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | close = self.bar_3.close 65 | 66 | atr = self.bar_3.atr() 67 | 68 | if self.allow_max_price < close[-1] and self.pos > 0: 69 | self.action.sell(bar.close_price, self.pos, bar) 70 | 71 | if self.allow_low_price > close[-1] and self.pos > 0: 72 | self.action.sell(bar.close_price, self.pos, bar) 73 | 74 | ############### 75 | # 暂时不写 # 76 | ############## 77 | pass 78 | 79 | def on_trade(self, trade): 80 | if trade.direction == Direction.LONG: 81 | self.pos += trade.volume 82 | else: 83 | self.pos -= trade.volume 84 | 85 | def init_params(self, data): 86 | """""" 87 | # print("我在设置策略参数") 88 | 89 | return SmaStrategy("double_ma") 90 | 91 | 92 | def save_data_json(data): 93 | result = {"result": data} 94 | 95 | class CJsonEncoder(json.JSONEncoder): 96 | def default(self, obj): 97 | if isinstance(obj, datetime): 98 | return obj.strftime('%Y-%m-%d %H:%M:%S') 99 | elif isinstance(obj, date): 100 | return obj.strftime('%Y-%m-%d') 101 | else: 102 | return json.JSONEncoder.default(self, obj) 103 | 104 | with open("../data.json", "w") as f: 105 | json.dump(result, f, cls=CJsonEncoder) 106 | 107 | 108 | def load_data(): 109 | with open("../data.json", "r") as f: 110 | data = json.load(f) 111 | return data.get("result") 112 | 113 | 114 | def run_main(data): 115 | vessel = Vessel() 116 | vessel.add_data(data) 117 | stra = get_a_strategy() 118 | vessel.add_strategy(stra) 119 | vessel.set_params({"looper": 120 | {"initial_capital": 100000, 121 | "commission": 0.005, 122 | "deal_pattern": "price", 123 | "size_map": {"ag1912.SHFE": 15}, 124 | "today_commission": 0.005, 125 | "yesterday_commission": 0.02, 126 | "close_commission": 0.005, 127 | "slippage_sell": 0, 128 | "slippage_cover": 0, 129 | "slippage_buy": 0, 130 | "slippage_short": 0, 131 | "close_pattern": "yesterday", 132 | }, 133 | "strategy": {} 134 | }) 135 | vessel.run() 136 | from pprint import pprint 137 | result = vessel.get_result() 138 | pprint(result) 139 | 140 | 141 | if __name__ == '__main__': 142 | data = load_data() 143 | for x in data: 144 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 145 | run_main(data) -------------------------------------------------------------------------------- /examples/boll_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单boll策略 top, middle, bottom = info.boll() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | # self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 布林带 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | top, middle, bottom = self.bar_3.boll() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 均线大于中线 说明是涨 73 | if bar.close_price > middle[-1]: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | 78 | elif self.pos < 0: 79 | self.action.cover(bar.close_price, 1, bar) 80 | self.action.buy(bar.close_price, 1, bar) 81 | # 跌 82 | elif bar.close_price <= middle[-1]: 83 | if self.pos == 0: 84 | pass 85 | elif self.pos > 0: 86 | self.action.sell(bar.close_price, 1, bar) 87 | self.action.short(bar.close_price, 1, bar) 88 | 89 | def on_trade(self, trade): 90 | if trade.direction == Direction.LONG: 91 | self.pos += trade.volume 92 | else: 93 | self.pos -= trade.volume 94 | 95 | def init_params(self, data): 96 | """""" 97 | # print("我在设置策略参数") 98 | 99 | return SmaStrategy("double_ma") 100 | 101 | 102 | def save_data_json(data): 103 | result = {"result": data} 104 | 105 | class CJsonEncoder(json.JSONEncoder): 106 | def default(self, obj): 107 | if isinstance(obj, datetime): 108 | return obj.strftime('%Y-%m-%d %H:%M:%S') 109 | elif isinstance(obj, date): 110 | return obj.strftime('%Y-%m-%d') 111 | else: 112 | return json.JSONEncoder.default(self, obj) 113 | 114 | with open("../data.json", "w") as f: 115 | json.dump(result, f, cls=CJsonEncoder) 116 | 117 | 118 | def load_data(): 119 | with open("../data.json", "r") as f: 120 | data = json.load(f) 121 | return data.get("result") 122 | 123 | 124 | def run_main(data): 125 | vessel = Vessel() 126 | vessel.add_data(data) 127 | stra = get_a_strategy() 128 | vessel.add_strategy(stra) 129 | vessel.set_params({"looper": 130 | {"initial_capital": 100000, 131 | "commission": 0.005, 132 | "deal_pattern": "price", 133 | "size_map": {"ag1912.SHFE": 15}, 134 | "today_commission": 0.005, 135 | "yesterday_commission": 0.02, 136 | "close_commission": 0.005, 137 | "slippage_sell": 0, 138 | "slippage_cover": 0, 139 | "slippage_buy": 0, 140 | "slippage_short": 0, 141 | "close_pattern": "yesterday", 142 | }, 143 | "strategy": {} 144 | }) 145 | vessel.run() 146 | from pprint import pprint 147 | result = vessel.get_result() 148 | pprint(result) 149 | 150 | 151 | if __name__ == '__main__': 152 | data = load_data() 153 | for x in data: 154 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 155 | run_main(data) -------------------------------------------------------------------------------- /examples/cci_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单收盘价策略 cci = info.cci 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | 8 | from ctpbee import LooperApi, Vessel 9 | from ctpbee.constant import Direction 10 | from indicator.interface import Indicator 11 | 12 | 13 | # def get_data(start, end, symbol, exchange, level): 14 | # """ using rqdatac to make an example """ 15 | # import rqdatac as rq 16 | # from rqdatac import get_price, id_convert 17 | # username = "license" 18 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 19 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 20 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 21 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 22 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 23 | # host = "rqdatad-pro.ricequant.com" 24 | # port = 16011 25 | # rq.init(username, password, (host, port)) 26 | # symbol_rq = id_convert(symbol) 27 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 28 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 29 | # origin = data.to_dict(orient='records') 30 | # result = [] 31 | # for x in origin: 32 | # do = {} 33 | # do['open_price'] = x['open'] 34 | # do['low_price'] = x['low'] 35 | # do['high_price'] = x['high'] 36 | # do['close_price'] = x['close'] 37 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 38 | # do['symbol'] = symbol 39 | # do['local_symbol'] = symbol + "." + exchange 40 | # do['exchange'] = exchange 41 | # result.append(do) 42 | # return result 43 | 44 | 45 | def get_a_strategy(): 46 | 47 | class DoubleMaStrategy(LooperApi): 48 | 49 | allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 止盈 50 | allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 止损 51 | 52 | def __init__(self, name): 53 | super().__init__(name) 54 | self.count = 1 55 | self.api = Indicator() 56 | self.api.open_json("../zn1912.SHFE.json") 57 | self.pos = 0 58 | 59 | def on_bar(self, bar): 60 | # todo: 均线 61 | """ """ 62 | am = self.api 63 | am.add_bar(bar) 64 | if not am.inited: 65 | return 66 | cci = am.cci() 67 | pass 68 | 69 | def on_trade(self, trade): 70 | if trade.direction == Direction.LONG: 71 | self.pos += trade.volume 72 | else: 73 | self.pos -= trade.volume 74 | 75 | def init_params(self, data): 76 | """""" 77 | # print("我在设置策略参数") 78 | 79 | return DoubleMaStrategy("double_ma") 80 | 81 | 82 | def save_data_json(data): 83 | result = {"result": data} 84 | 85 | class CJsonEncoder(json.JSONEncoder): 86 | def default(self, obj): 87 | if isinstance(obj, datetime): 88 | return obj.strftime('%Y-%m-%d %H:%M:%S') 89 | elif isinstance(obj, date): 90 | return obj.strftime('%Y-%m-%d') 91 | else: 92 | return json.JSONEncoder.default(self, obj) 93 | 94 | with open("../data.json", "w") as f: 95 | json.dump(result, f, cls=CJsonEncoder) 96 | 97 | 98 | def load_data(): 99 | with open("../data.json", "r") as f: 100 | data = json.load(f) 101 | return data.get("result") 102 | 103 | 104 | def run_main(data): 105 | vessel = Vessel() 106 | vessel.add_data(data) 107 | stra = get_a_strategy() 108 | vessel.add_strategy(stra) 109 | vessel.set_params({"looper": 110 | {"initial_capital": 100000, 111 | "commission": 0.005, 112 | "deal_pattern": "price", 113 | "size_map": {"ag1912.SHFE": 15}, 114 | "today_commission": 0.005, 115 | "yesterday_commission": 0.02, 116 | "close_commission": 0.005, 117 | "slippage_sell": 0, 118 | "slippage_cover": 0, 119 | "slippage_buy": 0, 120 | "slippage_short": 0, 121 | "close_pattern": "yesterday", 122 | }, 123 | "strategy": {} 124 | }) 125 | vessel.run() 126 | from pprint import pprint 127 | result = vessel.get_result() 128 | pprint(result) 129 | 130 | 131 | if __name__ == '__main__': 132 | # data = get_data(start="2019-1-5", end="2019-9-1", symbol="ag1912", exchange="SHFE", level="15m") 133 | # save_data_json(data) 134 | data = load_data() 135 | for x in data: 136 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 137 | run_main(data) 138 | -------------------------------------------------------------------------------- /examples/close_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单收盘价策略 close = info.close 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | 8 | from ctpbee import LooperApi, Vessel 9 | from ctpbee.constant import Direction 10 | from indicator.interface import Indicator 11 | 12 | 13 | # def get_data(start, end, symbol, exchange, level): 14 | # """ using rqdatac to make an example """ 15 | # import rqdatac as rq 16 | # from rqdatac import get_price, id_convert 17 | # username = "license" 18 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 19 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 20 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 21 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 22 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 23 | # host = "rqdatad-pro.ricequant.com" 24 | # port = 16011 25 | # rq.init(username, password, (host, port)) 26 | # symbol_rq = id_convert(symbol) 27 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 28 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 29 | # origin = data.to_dict(orient='records') 30 | # result = [] 31 | # for x in origin: 32 | # do = {} 33 | # do['open_price'] = x['open'] 34 | # do['low_price'] = x['low'] 35 | # do['high_price'] = x['high'] 36 | # do['close_price'] = x['close'] 37 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 38 | # do['symbol'] = symbol 39 | # do['local_symbol'] = symbol + "." + exchange 40 | # do['exchange'] = exchange 41 | # result.append(do) 42 | # return result 43 | 44 | 45 | def get_a_strategy(): 46 | 47 | class DoubleMaStrategy(LooperApi): 48 | 49 | allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 止盈 50 | allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 止损 51 | 52 | def __init__(self, name): 53 | super().__init__(name) 54 | self.count = 1 55 | self.api = Indicator() 56 | # self.api.open_json("../zn1912.SHFE.json") 57 | self.pos = 0 58 | 59 | def on_bar(self, bar): 60 | # todo: 均线 61 | """ """ 62 | am = self.api 63 | am.add_bar(bar) 64 | if not am.inited: 65 | return 66 | # 收盘 67 | close = am.close 68 | # 允许最大价格小于当前收盘价 69 | if self.allow_max_price <= close[-1] and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | # 允许最小价格大于当前收盘价 72 | if self.allow_low_price >= close[-1] and self.pos > 0: 73 | self.action.sell(bar.close_price, self.pos, bar) 74 | # 接连两天涨 75 | if close[-1] > close[-2] > close[-3]: 76 | if self.pos == 0: 77 | self.action.buy(bar.close_price, 1, bar) 78 | # 反向进行开仓 79 | elif self.pos < 0: 80 | self.action.cover(bar.close_price, 1, bar) 81 | self.action.buy(bar.close_price, 1, bar) 82 | # 接连两天降 83 | elif close[-1] < close[-2] < close[-3]: 84 | if self.pos == 0: 85 | pass 86 | # 反向进行开仓 87 | elif self.pos > 0: 88 | self.action.sell(bar.close_price, 1, bar) 89 | self.action.short(bar.close_price, 1, bar) 90 | 91 | def on_trade(self, trade): 92 | if trade.direction == Direction.LONG: 93 | self.pos += trade.volume 94 | else: 95 | self.pos -= trade.volume 96 | 97 | def init_params(self, data): 98 | """""" 99 | # print("我在设置策略参数") 100 | 101 | return DoubleMaStrategy("double_ma") 102 | 103 | 104 | def save_data_json(data): 105 | result = {"result": data} 106 | 107 | class CJsonEncoder(json.JSONEncoder): 108 | def default(self, obj): 109 | if isinstance(obj, datetime): 110 | return obj.strftime('%Y-%m-%d %H:%M:%S') 111 | elif isinstance(obj, date): 112 | return obj.strftime('%Y-%m-%d') 113 | else: 114 | return json.JSONEncoder.default(self, obj) 115 | 116 | with open("../data.json", "w") as f: 117 | json.dump(result, f, cls=CJsonEncoder) 118 | 119 | 120 | def load_data(): 121 | with open("../data.json", "r") as f: 122 | data = json.load(f) 123 | return data.get("result") 124 | 125 | 126 | def run_main(data): 127 | vessel = Vessel() 128 | vessel.add_data(data) 129 | stra = get_a_strategy() 130 | vessel.add_strategy(stra) 131 | vessel.set_params({"looper": 132 | {"initial_capital": 100000, 133 | "commission": 0.005, 134 | "deal_pattern": "price", 135 | "size_map": {"ag1912.SHFE": 15}, 136 | "today_commission": 0.005, 137 | "yesterday_commission": 0.02, 138 | "close_commission": 0.005, 139 | "slippage_sell": 0, 140 | "slippage_cover": 0, 141 | "slippage_buy": 0, 142 | "slippage_short": 0, 143 | "close_pattern": "yesterday", 144 | }, 145 | "strategy": {} 146 | }) 147 | vessel.run() 148 | from pprint import pprint 149 | result = vessel.get_result() 150 | pprint(result) 151 | 152 | 153 | if __name__ == '__main__': 154 | # data = get_data(start="2019-1-5", end="2019-9-1", symbol="ag1912", exchange="SHFE", level="15m") 155 | # save_data_json(data) 156 | data = load_data() 157 | for x in data: 158 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 159 | run_main(data) 160 | -------------------------------------------------------------------------------- /examples/ema_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单ema策略 ema = info.ema() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 移动平均线 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | ema = self.bar_3.ema() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 均线大于中线 73 | if ema[-1] > ema[-2] and ema[-1] < bar.close_price: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | if self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | # 跌 81 | elif ema[-1] < ema[-2] or ema[-1] > bar.close_price: 82 | if self.pos == 0: 83 | pass 84 | elif self.pos > 0: 85 | self.action.sell(bar.close_price, 1, bar) 86 | self.action.short(bar.close_price, 1, bar) 87 | 88 | def on_trade(self, trade): 89 | if trade.direction == Direction.LONG: 90 | self.pos += trade.volume 91 | else: 92 | self.pos -= trade.volume 93 | 94 | def init_params(self, data): 95 | """""" 96 | # print("我在设置策略参数") 97 | 98 | return SmaStrategy("double_ma") 99 | 100 | 101 | def save_data_json(data): 102 | result = {"result": data} 103 | 104 | class CJsonEncoder(json.JSONEncoder): 105 | def default(self, obj): 106 | if isinstance(obj, datetime): 107 | return obj.strftime('%Y-%m-%d %H:%M:%S') 108 | elif isinstance(obj, date): 109 | return obj.strftime('%Y-%m-%d') 110 | else: 111 | return json.JSONEncoder.default(self, obj) 112 | 113 | with open("../data.json", "w") as f: 114 | json.dump(result, f, cls=CJsonEncoder) 115 | 116 | 117 | def load_data(): 118 | with open("../data.json", "r") as f: 119 | data = json.load(f) 120 | return data.get("result") 121 | 122 | 123 | def run_main(data): 124 | vessel = Vessel() 125 | vessel.add_data(data) 126 | stra = get_a_strategy() 127 | vessel.add_strategy(stra) 128 | vessel.set_params({"looper": 129 | {"initial_capital": 100000, 130 | "commission": 0.005, 131 | "deal_pattern": "price", 132 | "size_map": {"ag1912.SHFE": 15}, 133 | "today_commission": 0.005, 134 | "yesterday_commission": 0.02, 135 | "close_commission": 0.005, 136 | "slippage_sell": 0, 137 | "slippage_cover": 0, 138 | "slippage_buy": 0, 139 | "slippage_short": 0, 140 | "close_pattern": "yesterday", 141 | }, 142 | "strategy": {} 143 | }) 144 | vessel.run() 145 | from pprint import pprint 146 | result = vessel.get_result() 147 | pprint(result) 148 | 149 | 150 | if __name__ == '__main__': 151 | data = load_data() 152 | for x in data: 153 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 154 | run_main(data) -------------------------------------------------------------------------------- /examples/kd_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单kd策略 k, d = info.kd() # kdj(j=3d-2k) 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 随机指标 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | close = self.bar_3.close 65 | k, d = self.bar_3.kd() 66 | 67 | if self.allow_max_price < close[-1] and self.pos > 0: 68 | self.action.sell(bar.close_price, self.pos, bar) 69 | 70 | if self.allow_low_price > close[-1] and self.pos > 0: 71 | self.action.sell(bar.close_price, self.pos, bar) 72 | 73 | # 金叉 74 | if k[-2] > d[-2] and k[-1] == d[-1]: 75 | # 没有就买 76 | if self.pos == 0: 77 | self.action.buy(bar.close_price, 1, bar) 78 | # 死叉 79 | if k[-2] == d[-2] and k[-1] < d[-1]: 80 | if self.pos > 0: 81 | self.action.sell(bar.close_price, 1, bar) 82 | 83 | def on_trade(self, trade): 84 | if trade.direction == Direction.LONG: 85 | self.pos += trade.volume 86 | else: 87 | self.pos -= trade.volume 88 | 89 | def init_params(self, data): 90 | """""" 91 | # print("我在设置策略参数") 92 | 93 | return SmaStrategy("double_ma") 94 | 95 | 96 | def save_data_json(data): 97 | result = {"result": data} 98 | 99 | class CJsonEncoder(json.JSONEncoder): 100 | def default(self, obj): 101 | if isinstance(obj, datetime): 102 | return obj.strftime('%Y-%m-%d %H:%M:%S') 103 | elif isinstance(obj, date): 104 | return obj.strftime('%Y-%m-%d') 105 | else: 106 | return json.JSONEncoder.default(self, obj) 107 | 108 | with open("../data.json", "w") as f: 109 | json.dump(result, f, cls=CJsonEncoder) 110 | 111 | 112 | def load_data(): 113 | with open("../data.json", "r") as f: 114 | data = json.load(f) 115 | return data.get("result") 116 | 117 | 118 | def run_main(data): 119 | vessel = Vessel() 120 | vessel.add_data(data) 121 | stra = get_a_strategy() 122 | vessel.add_strategy(stra) 123 | vessel.set_params({"looper": 124 | {"initial_capital": 100000, 125 | "commission": 0.005, 126 | "deal_pattern": "price", 127 | "size_map": {"ag1912.SHFE": 15}, 128 | "today_commission": 0.005, 129 | "yesterday_commission": 0.02, 130 | "close_commission": 0.005, 131 | "slippage_sell": 0, 132 | "slippage_cover": 0, 133 | "slippage_buy": 0, 134 | "slippage_short": 0, 135 | "close_pattern": "yesterday", 136 | }, 137 | "strategy": {} 138 | }) 139 | vessel.run() 140 | from pprint import pprint 141 | result = vessel.get_result() 142 | pprint(result) 143 | 144 | 145 | if __name__ == '__main__': 146 | data = load_data() 147 | for x in data: 148 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 149 | run_main(data) -------------------------------------------------------------------------------- /examples/looper_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | 当前回测示例 3 | 1.当前数据基于rq进行下载的 4 | 2.首先你需要调用get_data 来获得rq的数据 ,然后save_to_json保存到 json文件中去,主要在此过程中你需要手动对数据加入symbol等 5 | 3.然后通过load_data函数重复调用数据 6 | 4.调用run_main进行回测 7 | 8 | 当前的strategy是借助vnpy的 ArrayManager . 你需要对此实现一些额外的安装操作 9 | 10 | 需要额外安装的包 11 | ta-lib, rqdatac( 后面需要被取代 ?? Maybe use quantdata ) 12 | 13 | 目前暂时不够完善 ---> hope it will be a very fancy framework 14 | 15 | written by somewheve 2019-9-30 08:43 16 | 17 | """ 18 | 19 | import json 20 | from datetime import datetime, date 21 | 22 | from ctpbee import LooperApi, Vessel 23 | from ctpbee.constant import Direction 24 | from indicator.interface import Indicator 25 | 26 | 27 | # def get_data(start, end, symbol, exchange, level): 28 | # """ using rqdatac to make an example """ 29 | # import rqdatac as rq 30 | # from rqdatac import get_price, id_convert 31 | # username = "license" 32 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 33 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 34 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 35 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 36 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 37 | # host = "rqdatad-pro.ricequant.com" 38 | # port = 16011 39 | # rq.init(username, password, (host, port)) 40 | # symbol_rq = id_convert(symbol) 41 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 42 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 43 | # origin = data.to_dict(orient='records') 44 | # result = [] 45 | # for x in origin: 46 | # do = {} 47 | # do['open_price'] = x['open'] 48 | # do['low_price'] = x['low'] 49 | # do['high_price'] = x['high'] 50 | # do['close_price'] = x['close'] 51 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 52 | # do['symbol'] = symbol 53 | # do['local_symbol'] = symbol + "." + exchange 54 | # do['exchange'] = exchange 55 | # result.append(do) 56 | # return result 57 | 58 | 59 | def get_a_strategy(): 60 | 61 | class DoubleMaStrategy(LooperApi): 62 | 63 | allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 止盈 64 | allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 止损 65 | 66 | def __init__(self, name): 67 | super().__init__(name) 68 | self.count = 1 69 | self.api = Indicator() 70 | self.api.open_json("../zn1912.SHFE.json") 71 | self.pos = 0 72 | 73 | def on_bar(self, bar): 74 | # todo: 均线 和 MACD 和 BOLL 结合使用 75 | """ """ 76 | am = self.api 77 | am.add_bar(bar) 78 | # 收盘 79 | close = am.close 80 | # 压力 平均 支撑 81 | # top, middle, bottom = am.boll() 82 | # DIF DEA DIF-DEA 83 | macd, signal, histo = am.macd() 84 | 85 | if self.allow_max_price <= close[-1] and self.pos > 0: 86 | self.action.sell(bar.close_price, self.pos, bar) 87 | 88 | if self.allow_low_price >= close[-1] and self.pos > 0: 89 | self.action.sell(bar.close_price, self.pos, bar) 90 | # 金叉做多 和 均线>平均 91 | if histo[-1] > 0: 92 | if self.pos == 0: 93 | self.action.buy(bar.close_price, 1, bar) 94 | elif self.pos < 0: 95 | self.action.cover(bar.close_price, 1, bar) 96 | self.action.buy(bar.close_price, 1, bar) 97 | # 死叉做空 98 | elif histo[-1] < 0: 99 | if self.pos == 0: 100 | self.action.sell(bar.close_price, 1, bar) 101 | # 反向进行开仓 102 | elif self.pos > 0: 103 | self.action.sell(bar.close_price, 1, bar) 104 | self.action.short(bar.close_price, 1, bar) 105 | 106 | def on_trade(self, trade): 107 | if trade.direction == Direction.LONG: 108 | self.pos += trade.volume 109 | else: 110 | self.pos -= trade.volume 111 | 112 | def init_params(self, data): 113 | """""" 114 | # print("我在设置策略参数") 115 | 116 | return DoubleMaStrategy("double_ma") 117 | 118 | 119 | def save_data_json(data): 120 | result = {"result": data} 121 | 122 | class CJsonEncoder(json.JSONEncoder): 123 | def default(self, obj): 124 | if isinstance(obj, datetime): 125 | return obj.strftime('%Y-%m-%d %H:%M:%S') 126 | elif isinstance(obj, date): 127 | return obj.strftime('%Y-%m-%d') 128 | else: 129 | return json.JSONEncoder.default(self, obj) 130 | 131 | with open("data.json", "w") as f: 132 | json.dump(result, f, cls=CJsonEncoder) 133 | 134 | 135 | def load_data(): 136 | with open("data.json", "r") as f: 137 | data = json.load(f) 138 | return data.get("result") 139 | 140 | 141 | def run_main(data): 142 | vessel = Vessel() 143 | vessel.add_data(data) 144 | stra = get_a_strategy() 145 | vessel.add_strategy(stra) 146 | vessel.set_params({"looper": 147 | {"initial_capital": 100000, 148 | "commission": 0.005, 149 | "deal_pattern": "price", 150 | "size_map": {"ag1912.SHFE": 15}, 151 | "today_commission": 0.005, 152 | "yesterday_commission": 0.02, 153 | "close_commission": 0.005, 154 | "slippage_sell": 0, 155 | "slippage_cover": 0, 156 | "slippage_buy": 0, 157 | "slippage_short": 0, 158 | "close_pattern": "yesterday", 159 | }, 160 | "strategy": {} 161 | }) 162 | vessel.run() 163 | from pprint import pprint 164 | result = vessel.get_result() 165 | pprint(result) 166 | 167 | 168 | if __name__ == '__main__': 169 | # data = get_data(start="2019-1-5", end="2019-9-1", symbol="ag1912", exchange="SHFE", level="15m") 170 | # save_data_json(data) 171 | data = load_data() 172 | for x in data: 173 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 174 | run_main(data) 175 | -------------------------------------------------------------------------------- /examples/macd_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单macd策略 macd, signal, histo = info.macd() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: MACD 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | macd, signal, histo = self.bar_3.macd() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 接连三天涨 73 | if histo[-1] > 0: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | elif self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | else: 81 | if self.pos > 0: 82 | self.action.sell(bar.close_price, 1, bar) 83 | self.action.short(bar.close_price, 1, bar) 84 | 85 | def on_trade(self, trade): 86 | if trade.direction == Direction.LONG: 87 | self.pos += trade.volume 88 | else: 89 | self.pos -= trade.volume 90 | 91 | def init_params(self, data): 92 | """""" 93 | # print("我在设置策略参数") 94 | 95 | return SmaStrategy("double_ma") 96 | 97 | 98 | def save_data_json(data): 99 | result = {"result": data} 100 | 101 | class CJsonEncoder(json.JSONEncoder): 102 | def default(self, obj): 103 | if isinstance(obj, datetime): 104 | return obj.strftime('%Y-%m-%d %H:%M:%S') 105 | elif isinstance(obj, date): 106 | return obj.strftime('%Y-%m-%d') 107 | else: 108 | return json.JSONEncoder.default(self, obj) 109 | 110 | with open("../data.json", "w") as f: 111 | json.dump(result, f, cls=CJsonEncoder) 112 | 113 | 114 | def load_data(): 115 | with open("../data.json", "r") as f: 116 | data = json.load(f) 117 | return data.get("result") 118 | 119 | 120 | def run_main(data): 121 | vessel = Vessel() 122 | vessel.add_data(data) 123 | stra = get_a_strategy() 124 | vessel.add_strategy(stra) 125 | vessel.set_params({"looper": 126 | {"initial_capital": 100000, 127 | "commission": 0.005, 128 | "deal_pattern": "price", 129 | "size_map": {"ag1912.SHFE": 15}, 130 | "today_commission": 0.005, 131 | "yesterday_commission": 0.02, 132 | "close_commission": 0.005, 133 | "slippage_sell": 0, 134 | "slippage_cover": 0, 135 | "slippage_buy": 0, 136 | "slippage_short": 0, 137 | "close_pattern": "yesterday", 138 | }, 139 | "strategy": {} 140 | }) 141 | vessel.run() 142 | from pprint import pprint 143 | result = vessel.get_result() 144 | pprint(result) 145 | 146 | 147 | if __name__ == '__main__': 148 | data = load_data() 149 | for x in data: 150 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 151 | run_main(data) -------------------------------------------------------------------------------- /examples/mtm_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单mtm策略 mtm = info.mtm() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 动量指标 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | mtm = self.bar_3.mtm() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 趋势好 可能会涨 多头 73 | if mtm[-1] > 0 and mtm[-1] > mtm[-2]: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | elif self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | # 空头 81 | else: 82 | if self.pos > 0: 83 | self.action.sell(bar.close_price, 1, bar) 84 | self.action.short(bar.close_price, 1, bar) 85 | 86 | def on_trade(self, trade): 87 | if trade.direction == Direction.LONG: 88 | self.pos += trade.volume 89 | else: 90 | self.pos -= trade.volume 91 | 92 | def init_params(self, data): 93 | """""" 94 | # print("我在设置策略参数") 95 | 96 | return SmaStrategy("double_ma") 97 | 98 | 99 | def save_data_json(data): 100 | result = {"result": data} 101 | 102 | class CJsonEncoder(json.JSONEncoder): 103 | def default(self, obj): 104 | if isinstance(obj, datetime): 105 | return obj.strftime('%Y-%m-%d %H:%M:%S') 106 | elif isinstance(obj, date): 107 | return obj.strftime('%Y-%m-%d') 108 | else: 109 | return json.JSONEncoder.default(self, obj) 110 | 111 | with open("../data.json", "w") as f: 112 | json.dump(result, f, cls=CJsonEncoder) 113 | 114 | 115 | def load_data(): 116 | with open("../data.json", "r") as f: 117 | data = json.load(f) 118 | return data.get("result") 119 | 120 | 121 | def run_main(data): 122 | vessel = Vessel() 123 | vessel.add_data(data) 124 | stra = get_a_strategy() 125 | vessel.add_strategy(stra) 126 | vessel.set_params({"looper": 127 | {"initial_capital": 100000, 128 | "commission": 0.005, 129 | "deal_pattern": "price", 130 | "size_map": {"ag1912.SHFE": 15}, 131 | "today_commission": 0.005, 132 | "yesterday_commission": 0.02, 133 | "close_commission": 0.005, 134 | "slippage_sell": 0, 135 | "slippage_cover": 0, 136 | "slippage_buy": 0, 137 | "slippage_short": 0, 138 | "close_pattern": "yesterday", 139 | }, 140 | "strategy": {} 141 | }) 142 | vessel.run() 143 | from pprint import pprint 144 | result = vessel.get_result() 145 | pprint(result) 146 | 147 | 148 | if __name__ == '__main__': 149 | data = load_data() 150 | for x in data: 151 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 152 | run_main(data) -------------------------------------------------------------------------------- /examples/roc_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单roc策略 roc = info.roc() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: ROC 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | roc = self.bar_3.roc() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # roc大于0会涨 73 | if roc[-1] > 0: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | elif self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | else: 81 | if self.pos > 0: 82 | self.action.sell(bar.close_price, 1, bar) 83 | self.action.short(bar.close_price, 1, bar) 84 | 85 | def on_trade(self, trade): 86 | if trade.direction == Direction.LONG: 87 | self.pos += trade.volume 88 | else: 89 | self.pos -= trade.volume 90 | 91 | def init_params(self, data): 92 | """""" 93 | # print("我在设置策略参数") 94 | 95 | return SmaStrategy("double_ma") 96 | 97 | 98 | def save_data_json(data): 99 | result = {"result": data} 100 | 101 | class CJsonEncoder(json.JSONEncoder): 102 | def default(self, obj): 103 | if isinstance(obj, datetime): 104 | return obj.strftime('%Y-%m-%d %H:%M:%S') 105 | elif isinstance(obj, date): 106 | return obj.strftime('%Y-%m-%d') 107 | else: 108 | return json.JSONEncoder.default(self, obj) 109 | 110 | with open("../data.json", "w") as f: 111 | json.dump(result, f, cls=CJsonEncoder) 112 | 113 | 114 | def load_data(): 115 | with open("../data.json", "r") as f: 116 | data = json.load(f) 117 | return data.get("result") 118 | 119 | 120 | def run_main(data): 121 | vessel = Vessel() 122 | vessel.add_data(data) 123 | stra = get_a_strategy() 124 | vessel.add_strategy(stra) 125 | vessel.set_params({"looper": 126 | {"initial_capital": 100000, 127 | "commission": 0.005, 128 | "deal_pattern": "price", 129 | "size_map": {"ag1912.SHFE": 15}, 130 | "today_commission": 0.005, 131 | "yesterday_commission": 0.02, 132 | "close_commission": 0.005, 133 | "slippage_sell": 0, 134 | "slippage_cover": 0, 135 | "slippage_buy": 0, 136 | "slippage_short": 0, 137 | "close_pattern": "yesterday", 138 | }, 139 | "strategy": {} 140 | }) 141 | vessel.run() 142 | from pprint import pprint 143 | result = vessel.get_result() 144 | pprint(result) 145 | 146 | 147 | if __name__ == '__main__': 148 | data = load_data() 149 | for x in data: 150 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 151 | run_main(data) -------------------------------------------------------------------------------- /examples/rsi_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单相对强度指数rsi策略 rsi = info.rsi() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: RSI 相对强度指数 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | roc = self.bar_3.roc() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | ################## 73 | # 无具体资料 # 74 | ################## 75 | pass 76 | 77 | def on_trade(self, trade): 78 | if trade.direction == Direction.LONG: 79 | self.pos += trade.volume 80 | else: 81 | self.pos -= trade.volume 82 | 83 | def init_params(self, data): 84 | """""" 85 | # print("我在设置策略参数") 86 | 87 | return SmaStrategy("double_ma") 88 | 89 | 90 | def save_data_json(data): 91 | result = {"result": data} 92 | 93 | class CJsonEncoder(json.JSONEncoder): 94 | def default(self, obj): 95 | if isinstance(obj, datetime): 96 | return obj.strftime('%Y-%m-%d %H:%M:%S') 97 | elif isinstance(obj, date): 98 | return obj.strftime('%Y-%m-%d') 99 | else: 100 | return json.JSONEncoder.default(self, obj) 101 | 102 | with open("../data.json", "w") as f: 103 | json.dump(result, f, cls=CJsonEncoder) 104 | 105 | 106 | def load_data(): 107 | with open("../data.json", "r") as f: 108 | data = json.load(f) 109 | return data.get("result") 110 | 111 | 112 | def run_main(data): 113 | vessel = Vessel() 114 | vessel.add_data(data) 115 | stra = get_a_strategy() 116 | vessel.add_strategy(stra) 117 | vessel.set_params({"looper": 118 | {"initial_capital": 100000, 119 | "commission": 0.005, 120 | "deal_pattern": "price", 121 | "size_map": {"ag1912.SHFE": 15}, 122 | "today_commission": 0.005, 123 | "yesterday_commission": 0.02, 124 | "close_commission": 0.005, 125 | "slippage_sell": 0, 126 | "slippage_cover": 0, 127 | "slippage_buy": 0, 128 | "slippage_short": 0, 129 | "close_pattern": "yesterday", 130 | }, 131 | "strategy": {} 132 | }) 133 | vessel.run() 134 | from pprint import pprint 135 | result = vessel.get_result() 136 | pprint(result) 137 | 138 | 139 | if __name__ == '__main__': 140 | data = load_data() 141 | for x in data: 142 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 143 | run_main(data) -------------------------------------------------------------------------------- /examples/sar_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单抛物线sar策略 sar = info.sar() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 抛物线指标 SAR 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | sar = self.bar_3.sar() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 接连涨 73 | if sar[-1]['sar'] > sar[-2]['sar']: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | elif self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | else: 81 | if self.pos > 0: 82 | self.action.sell(bar.close_price, 1, bar) 83 | self.action.short(bar.close_price, 1, bar) 84 | 85 | def on_trade(self, trade): 86 | if trade.direction == Direction.LONG: 87 | self.pos += trade.volume 88 | else: 89 | self.pos -= trade.volume 90 | print(self.pos, '-----------') 91 | 92 | def init_params(self, data): 93 | """""" 94 | # print("我在设置策略参数") 95 | 96 | return SmaStrategy("double_ma") 97 | 98 | 99 | def save_data_json(data): 100 | result = {"result": data} 101 | 102 | class CJsonEncoder(json.JSONEncoder): 103 | def default(self, obj): 104 | if isinstance(obj, datetime): 105 | return obj.strftime('%Y-%m-%d %H:%M:%S') 106 | elif isinstance(obj, date): 107 | return obj.strftime('%Y-%m-%d') 108 | else: 109 | return json.JSONEncoder.default(self, obj) 110 | 111 | with open("../data.json", "w") as f: 112 | json.dump(result, f, cls=CJsonEncoder) 113 | 114 | 115 | def load_data(): 116 | with open("../data.json", "r") as f: 117 | data = json.load(f) 118 | return data.get("result") 119 | 120 | 121 | def run_main(data): 122 | vessel = Vessel() 123 | vessel.add_data(data) 124 | stra = get_a_strategy() 125 | vessel.add_strategy(stra) 126 | vessel.set_params({"looper": 127 | {"initial_capital": 100000, 128 | "commission": 0.005, 129 | "deal_pattern": "price", 130 | "size_map": {"ag1912.SHFE": 15}, 131 | "today_commission": 0.005, 132 | "yesterday_commission": 0.02, 133 | "close_commission": 0.005, 134 | "slippage_sell": 0, 135 | "slippage_cover": 0, 136 | "slippage_buy": 0, 137 | "slippage_short": 0, 138 | "close_pattern": "yesterday", 139 | }, 140 | "strategy": {} 141 | }) 142 | vessel.run() 143 | from pprint import pprint 144 | result = vessel.get_result() 145 | pprint(result) 146 | 147 | 148 | if __name__ == '__main__': 149 | data = load_data() 150 | for x in data: 151 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 152 | run_main(data) -------------------------------------------------------------------------------- /examples/sma_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单滑动平均线sma策略 sar = info.sma() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | # self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 抛物线指标 SAR 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | close = self.bar_3.close 65 | sma = self.bar_3.sma() 66 | 67 | if self.allow_max_price < bar.close_price and self.pos > 0: 68 | self.action.sell(bar.close_price, self.pos, bar) 69 | 70 | if self.allow_low_price > bar.close_price and self.pos > 0: 71 | self.action.sell(bar.close_price, self.pos, bar) 72 | 73 | # 连涨就买 74 | if sma[-1] > sma[-2] and close[-1] > sma[-2]: 75 | # 没有就买 76 | if self.pos == 0: 77 | self.action.buy(bar.close_price, 1, bar) 78 | elif self.pos < 0: 79 | self.action.cover(bar.close_price, 1, bar) 80 | self.action.buy(bar.close_price, 1, bar) 81 | # 跌就卖 82 | else: 83 | if self.pos > 0: 84 | self.action.sell(bar.close_price, self.pos, bar) 85 | self.action.short(bar.close_price, self.pos, bar) 86 | 87 | def on_trade(self, trade): 88 | if trade.direction == Direction.LONG: 89 | self.pos += trade.volume 90 | else: 91 | self.pos -= trade.volume 92 | 93 | def init_params(self, data): 94 | """""" 95 | # print("我在设置策略参数") 96 | 97 | return SmaStrategy("double_ma") 98 | 99 | 100 | def save_data_json(data): 101 | result = {"result": data} 102 | 103 | class CJsonEncoder(json.JSONEncoder): 104 | def default(self, obj): 105 | if isinstance(obj, datetime): 106 | return obj.strftime('%Y-%m-%d %H:%M:%S') 107 | elif isinstance(obj, date): 108 | return obj.strftime('%Y-%m-%d') 109 | else: 110 | return json.JSONEncoder.default(self, obj) 111 | 112 | with open("../data.json", "w") as f: 113 | json.dump(result, f, cls=CJsonEncoder) 114 | 115 | 116 | def load_data(): 117 | with open("../data.json", "r") as f: 118 | data = json.load(f) 119 | return data.get("result") 120 | 121 | 122 | def run_main(data): 123 | vessel = Vessel() 124 | vessel.add_data(data) 125 | stra = get_a_strategy() 126 | vessel.add_strategy(stra) 127 | vessel.set_params({"looper": 128 | {"initial_capital": 100000, 129 | "commission": 0.005, 130 | "deal_pattern": "price", 131 | "size_map": {"ag1912.SHFE": 15}, 132 | "today_commission": 0.005, 133 | "yesterday_commission": 0.02, 134 | "close_commission": 0.005, 135 | "slippage_sell": 0, 136 | "slippage_cover": 0, 137 | "slippage_buy": 0, 138 | "slippage_short": 0, 139 | "close_pattern": "yesterday", 140 | }, 141 | "strategy": {} 142 | }) 143 | vessel.run() 144 | from pprint import pprint 145 | result = vessel.get_result() 146 | pprint(result) 147 | 148 | 149 | if __name__ == '__main__': 150 | data = load_data() 151 | for x in data: 152 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 153 | run_main(data) -------------------------------------------------------------------------------- /examples/smma_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单平均指标smma策略 smma = info.smma() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 简单平均指标 SMMA 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | sar = self.bar_3.sar() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | ############### 73 | # 暂时不写 # 74 | ############### 75 | pass 76 | 77 | def on_trade(self, trade): 78 | if trade.direction == Direction.LONG: 79 | self.pos += trade.volume 80 | else: 81 | self.pos -= trade.volume 82 | print(self.pos, '-----------') 83 | 84 | def init_params(self, data): 85 | """""" 86 | # print("我在设置策略参数") 87 | 88 | return SmaStrategy("double_ma") 89 | 90 | 91 | def save_data_json(data): 92 | result = {"result": data} 93 | 94 | class CJsonEncoder(json.JSONEncoder): 95 | def default(self, obj): 96 | if isinstance(obj, datetime): 97 | return obj.strftime('%Y-%m-%d %H:%M:%S') 98 | elif isinstance(obj, date): 99 | return obj.strftime('%Y-%m-%d') 100 | else: 101 | return json.JSONEncoder.default(self, obj) 102 | 103 | with open("../data.json", "w") as f: 104 | json.dump(result, f, cls=CJsonEncoder) 105 | 106 | 107 | def load_data(): 108 | with open("../data.json", "r") as f: 109 | data = json.load(f) 110 | return data.get("result") 111 | 112 | 113 | def run_main(data): 114 | vessel = Vessel() 115 | vessel.add_data(data) 116 | stra = get_a_strategy() 117 | vessel.add_strategy(stra) 118 | vessel.set_params({"looper": 119 | {"initial_capital": 100000, 120 | "commission": 0.005, 121 | "deal_pattern": "price", 122 | "size_map": {"ag1912.SHFE": 15}, 123 | "today_commission": 0.005, 124 | "yesterday_commission": 0.02, 125 | "close_commission": 0.005, 126 | "slippage_sell": 0, 127 | "slippage_cover": 0, 128 | "slippage_buy": 0, 129 | "slippage_short": 0, 130 | "close_pattern": "yesterday", 131 | }, 132 | "strategy": {} 133 | }) 134 | vessel.run() 135 | from pprint import pprint 136 | result = vessel.get_result() 137 | pprint(result) 138 | 139 | 140 | if __name__ == '__main__': 141 | data = load_data() 142 | for x in data: 143 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 144 | run_main(data) -------------------------------------------------------------------------------- /examples/stdDev_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单标准偏差StaDev策略 staDev = info.staDev() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 标准偏差 stdDev 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | stdDev = self.bar_3.stdDev() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | ############ 73 | # 暂时不写 # 74 | ########### 75 | pass 76 | 77 | def on_trade(self, trade): 78 | if trade.direction == Direction.LONG: 79 | self.pos += trade.volume 80 | else: 81 | self.pos -= trade.volume 82 | 83 | def init_params(self, data): 84 | """""" 85 | # print("我在设置策略参数") 86 | 87 | return SmaStrategy("double_ma") 88 | 89 | 90 | def save_data_json(data): 91 | result = {"result": data} 92 | 93 | class CJsonEncoder(json.JSONEncoder): 94 | def default(self, obj): 95 | if isinstance(obj, datetime): 96 | return obj.strftime('%Y-%m-%d %H:%M:%S') 97 | elif isinstance(obj, date): 98 | return obj.strftime('%Y-%m-%d') 99 | else: 100 | return json.JSONEncoder.default(self, obj) 101 | 102 | with open("../data.json", "w") as f: 103 | json.dump(result, f, cls=CJsonEncoder) 104 | 105 | 106 | def load_data(): 107 | with open("../data.json", "r") as f: 108 | data = json.load(f) 109 | return data.get("result") 110 | 111 | 112 | def run_main(data): 113 | vessel = Vessel() 114 | vessel.add_data(data) 115 | stra = get_a_strategy() 116 | vessel.add_strategy(stra) 117 | vessel.set_params({"looper": 118 | {"initial_capital": 100000, 119 | "commission": 0.005, 120 | "deal_pattern": "price", 121 | "size_map": {"ag1912.SHFE": 15}, 122 | "today_commission": 0.005, 123 | "yesterday_commission": 0.02, 124 | "close_commission": 0.005, 125 | "slippage_sell": 0, 126 | "slippage_cover": 0, 127 | "slippage_buy": 0, 128 | "slippage_short": 0, 129 | "close_pattern": "yesterday", 130 | }, 131 | "strategy": {} 132 | }) 133 | vessel.run() 134 | from pprint import pprint 135 | result = vessel.get_result() 136 | pprint(result) 137 | 138 | 139 | if __name__ == '__main__': 140 | data = load_data() 141 | for x in data: 142 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 143 | run_main(data) -------------------------------------------------------------------------------- /examples/tema_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单三倍运动平均值tema策略 tema = info.tema() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 三倍运动平均值指标 TEMA 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | close = self.bar_3.close 65 | tema = self.bar_3.tema() 66 | 67 | if self.allow_max_price < bar.close_price and self.pos > 0: 68 | self.action.sell(bar.close_price, self.pos, bar) 69 | 70 | if self.allow_low_price > bar.close_price and self.pos > 0: 71 | self.action.sell(bar.close_price, self.pos, bar) 72 | 73 | # 三倍平均数小于收盘价 74 | if tema[-1] < close[-1]: 75 | # 没有就买 76 | if self.pos == 0: 77 | self.action.buy(bar.close_price, 1, bar) 78 | elif self.pos < 0: 79 | self.action.cover(bar.close_price, 1, bar) 80 | self.action.buy(bar.close_price, 1, bar) 81 | else: 82 | if self.pos > 0: 83 | self.action.sell(bar.close_price, 1, bar) 84 | self.action.short(bar.close_price, 1, bar) 85 | 86 | def on_trade(self, trade): 87 | if trade.direction == Direction.LONG: 88 | self.pos += trade.volume 89 | else: 90 | self.pos -= trade.volume 91 | 92 | def init_params(self, data): 93 | """""" 94 | # print("我在设置策略参数") 95 | 96 | return SmaStrategy("double_ma") 97 | 98 | 99 | def save_data_json(data): 100 | result = {"result": data} 101 | 102 | class CJsonEncoder(json.JSONEncoder): 103 | def default(self, obj): 104 | if isinstance(obj, datetime): 105 | return obj.strftime('%Y-%m-%d %H:%M:%S') 106 | elif isinstance(obj, date): 107 | return obj.strftime('%Y-%m-%d') 108 | else: 109 | return json.JSONEncoder.default(self, obj) 110 | 111 | with open("../data.json", "w") as f: 112 | json.dump(result, f, cls=CJsonEncoder) 113 | 114 | 115 | def load_data(): 116 | with open("../data.json", "r") as f: 117 | data = json.load(f) 118 | return data.get("result") 119 | 120 | 121 | def run_main(data): 122 | vessel = Vessel() 123 | vessel.add_data(data) 124 | stra = get_a_strategy() 125 | vessel.add_strategy(stra) 126 | vessel.set_params({"looper": 127 | {"initial_capital": 100000, 128 | "commission": 0.005, 129 | "deal_pattern": "price", 130 | "size_map": {"ag1912.SHFE": 15}, 131 | "today_commission": 0.005, 132 | "yesterday_commission": 0.02, 133 | "close_commission": 0.005, 134 | "slippage_sell": 0, 135 | "slippage_cover": 0, 136 | "slippage_buy": 0, 137 | "slippage_short": 0, 138 | "close_pattern": "yesterday", 139 | }, 140 | "strategy": {} 141 | }) 142 | vessel.run() 143 | from pprint import pprint 144 | result = vessel.get_result() 145 | pprint(result) 146 | 147 | 148 | if __name__ == '__main__': 149 | data = load_data() 150 | for x in data: 151 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 152 | run_main(data) -------------------------------------------------------------------------------- /examples/trix_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单三重指数平滑移动平均trix策略 trix = info.trix() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 三重指数平滑移动平均 TRIX 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | trix = self.bar_3.trix() 65 | if self.allow_max_price < bar.close_price and self.pos > 0: 66 | self.action.sell(bar.close_price, self.pos, bar) 67 | 68 | if self.allow_low_price > bar.close_price and self.pos > 0: 69 | self.action.sell(bar.close_price, self.pos, bar) 70 | 71 | ############## 72 | # 暂时不写 # 73 | ############# 74 | pass 75 | 76 | 77 | def on_trade(self, trade): 78 | if trade.direction == Direction.LONG: 79 | self.pos += trade.volume 80 | else: 81 | self.pos -= trade.volume 82 | 83 | def init_params(self, data): 84 | """""" 85 | # print("我在设置策略参数") 86 | 87 | return SmaStrategy("double_ma") 88 | 89 | 90 | def save_data_json(data): 91 | result = {"result": data} 92 | 93 | class CJsonEncoder(json.JSONEncoder): 94 | def default(self, obj): 95 | if isinstance(obj, datetime): 96 | return obj.strftime('%Y-%m-%d %H:%M:%S') 97 | elif isinstance(obj, date): 98 | return obj.strftime('%Y-%m-%d') 99 | else: 100 | return json.JSONEncoder.default(self, obj) 101 | 102 | with open("../data.json", "w") as f: 103 | json.dump(result, f, cls=CJsonEncoder) 104 | 105 | 106 | def load_data(): 107 | with open("../data.json", "r") as f: 108 | data = json.load(f) 109 | return data.get("result") 110 | 111 | 112 | def run_main(data): 113 | vessel = Vessel() 114 | vessel.add_data(data) 115 | stra = get_a_strategy() 116 | vessel.add_strategy(stra) 117 | vessel.set_params({"looper": 118 | {"initial_capital": 100000, 119 | "commission": 0.005, 120 | "deal_pattern": "price", 121 | "size_map": {"ag1912.SHFE": 15}, 122 | "today_commission": 0.005, 123 | "yesterday_commission": 0.02, 124 | "close_commission": 0.005, 125 | "slippage_sell": 0, 126 | "slippage_cover": 0, 127 | "slippage_buy": 0, 128 | "slippage_short": 0, 129 | "close_pattern": "yesterday", 130 | }, 131 | "strategy": {} 132 | }) 133 | vessel.run() 134 | from pprint import pprint 135 | result = vessel.get_result() 136 | pprint(result) 137 | 138 | 139 | if __name__ == '__main__': 140 | data = load_data() 141 | for x in data: 142 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 143 | run_main(data) -------------------------------------------------------------------------------- /examples/wma_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单加权移动平均线wma策略 wma = info.wma() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 加权移动平均线 WMA 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | wma = self.bar_3.wma() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | # 接连三天涨 73 | if wma[-1] > wma[-2]: 74 | # 没有就买 75 | if self.pos == 0: 76 | self.action.buy(bar.close_price, 1, bar) 77 | elif self.pos < 0: 78 | self.action.cover(bar.close_price, 1, bar) 79 | self.action.buy(bar.close_price, 1, bar) 80 | else: 81 | if self.pos > 0: 82 | self.action.sell(bar.close_price, 1, bar) 83 | self.action.short(bar.close_price, 1, bar) 84 | 85 | def on_trade(self, trade): 86 | if trade.direction == Direction.LONG: 87 | self.pos += trade.volume 88 | else: 89 | self.pos -= trade.volume 90 | 91 | def init_params(self, data): 92 | """""" 93 | # print("我在设置策略参数") 94 | 95 | return SmaStrategy("double_ma") 96 | 97 | 98 | def save_data_json(data): 99 | result = {"result": data} 100 | 101 | class CJsonEncoder(json.JSONEncoder): 102 | def default(self, obj): 103 | if isinstance(obj, datetime): 104 | return obj.strftime('%Y-%m-%d %H:%M:%S') 105 | elif isinstance(obj, date): 106 | return obj.strftime('%Y-%m-%d') 107 | else: 108 | return json.JSONEncoder.default(self, obj) 109 | 110 | with open("../data.json", "w") as f: 111 | json.dump(result, f, cls=CJsonEncoder) 112 | 113 | 114 | def load_data(): 115 | with open("../data.json", "r") as f: 116 | data = json.load(f) 117 | return data.get("result") 118 | 119 | 120 | def run_main(data): 121 | vessel = Vessel() 122 | vessel.add_data(data) 123 | stra = get_a_strategy() 124 | vessel.add_strategy(stra) 125 | vessel.set_params({"looper": 126 | {"initial_capital": 100000, 127 | "commission": 0.005, 128 | "deal_pattern": "price", 129 | "size_map": {"ag1912.SHFE": 15}, 130 | "today_commission": 0.005, 131 | "yesterday_commission": 0.02, 132 | "close_commission": 0.005, 133 | "slippage_sell": 0, 134 | "slippage_cover": 0, 135 | "slippage_buy": 0, 136 | "slippage_short": 0, 137 | "close_pattern": "yesterday", 138 | }, 139 | "strategy": {} 140 | }) 141 | vessel.run() 142 | from pprint import pprint 143 | result = vessel.get_result() 144 | pprint(result) 145 | 146 | 147 | if __name__ == '__main__': 148 | data = load_data() 149 | for x in data: 150 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 151 | run_main(data) -------------------------------------------------------------------------------- /examples/wr_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简单威廉姆斯wr策略 wr = info.wr() 3 | """ 4 | 5 | import json 6 | from datetime import datetime, date 7 | from ctpbee import LooperApi, Vessel 8 | from ctpbee.constant import Direction 9 | from indicator.interface import Indicator 10 | 11 | 12 | def get_data(start, end, symbol, exchange, level): 13 | """ using rqdatac to make an example """ 14 | # import rqdatac as rq 15 | # from rqdatac import get_price, id_convert 16 | # username = "license" 17 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 18 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 19 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 20 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 21 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 22 | # host = "rqdatad-pro.ricequant.com" 23 | # port = 16011 24 | # rq.init(username, password, (host, port)) 25 | # symbol_rq = id_convert(symbol) 26 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 27 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 28 | # origin = data.to_dict(orient='records') 29 | # result = [] 30 | # for x in origin: 31 | # do = {} 32 | # do['open_price'] = x['open'] 33 | # do['low_price'] = x['low'] 34 | # do['high_price'] = x['high'] 35 | # do['close_price'] = x['close'] 36 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 37 | # do['symbol'] = symbol 38 | # do['local_symbol'] = symbol + "." + exchange 39 | # do['exchange'] = exchange 40 | # result.append(do) 41 | # return result 42 | 43 | 44 | def get_a_strategy(): 45 | class SmaStrategy(LooperApi): 46 | 47 | def __init__(self, name): 48 | super().__init__(name) 49 | self.count = 1 50 | self.pos = 0 51 | 52 | self.bar_3 = Indicator() # 3分钟bar线 53 | self.bar_3.open_json('../zn1912.SHFE.json') # 读取本地数据 54 | 55 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 56 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 57 | 58 | def on_bar(self, bar): 59 | # todo: 威廉姆斯 WR 60 | """ """ 61 | self.bar_3.add_bar(bar) 62 | if not self.bar_3.inited: 63 | return 64 | wr = self.bar_3.wr() 65 | 66 | if self.allow_max_price < bar.close_price and self.pos > 0: 67 | self.action.sell(bar.close_price, self.pos, bar) 68 | 69 | if self.allow_low_price > bar.close_price and self.pos > 0: 70 | self.action.sell(bar.close_price, self.pos, bar) 71 | 72 | ############# 73 | # 暂时不写 # 74 | ############ 75 | pass 76 | 77 | def on_trade(self, trade): 78 | if trade.direction == Direction.LONG: 79 | self.pos += trade.volume 80 | else: 81 | self.pos -= trade.volume 82 | 83 | def init_params(self, data): 84 | """""" 85 | # print("我在设置策略参数") 86 | 87 | return SmaStrategy("double_ma") 88 | 89 | 90 | def save_data_json(data): 91 | result = {"result": data} 92 | 93 | class CJsonEncoder(json.JSONEncoder): 94 | def default(self, obj): 95 | if isinstance(obj, datetime): 96 | return obj.strftime('%Y-%m-%d %H:%M:%S') 97 | elif isinstance(obj, date): 98 | return obj.strftime('%Y-%m-%d') 99 | else: 100 | return json.JSONEncoder.default(self, obj) 101 | 102 | with open("../data.json", "w") as f: 103 | json.dump(result, f, cls=CJsonEncoder) 104 | 105 | 106 | def load_data(): 107 | with open("../data.json", "r") as f: 108 | data = json.load(f) 109 | return data.get("result") 110 | 111 | 112 | def run_main(data): 113 | vessel = Vessel() 114 | vessel.add_data(data) 115 | stra = get_a_strategy() 116 | vessel.add_strategy(stra) 117 | vessel.set_params({"looper": 118 | {"initial_capital": 100000, 119 | "commission": 0.005, 120 | "deal_pattern": "price", 121 | "size_map": {"ag1912.SHFE": 15}, 122 | "today_commission": 0.005, 123 | "yesterday_commission": 0.02, 124 | "close_commission": 0.005, 125 | "slippage_sell": 0, 126 | "slippage_cover": 0, 127 | "slippage_buy": 0, 128 | "slippage_short": 0, 129 | "close_pattern": "yesterday", 130 | }, 131 | "strategy": {} 132 | }) 133 | vessel.run() 134 | from pprint import pprint 135 | result = vessel.get_result() 136 | pprint(result) 137 | 138 | 139 | if __name__ == '__main__': 140 | data = load_data() 141 | for x in data: 142 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 143 | run_main(data) -------------------------------------------------------------------------------- /indicator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__init__.py -------------------------------------------------------------------------------- /indicator/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /indicator/__pycache__/indicator.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__pycache__/indicator.cpython-37.pyc -------------------------------------------------------------------------------- /indicator/__pycache__/interface.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__pycache__/interface.cpython-37.pyc -------------------------------------------------------------------------------- /indicator/__pycache__/plot.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__pycache__/plot.cpython-37.pyc -------------------------------------------------------------------------------- /indicator/__pycache__/readfile.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctpbee/ctpbee_indicator/d7a4d981eaf9e60b640d8f56b1bfb9b270269649/indicator/__pycache__/readfile.cpython-37.pyc -------------------------------------------------------------------------------- /indicator/indicator.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .readfile import File 3 | import math 4 | import operator 5 | from copy import deepcopy 6 | from functools import wraps 7 | 8 | 9 | def getAverageName(func): 10 | """ 11 | 此装饰器是获取平均平均值参数名 12 | :param func: 13 | :return: 14 | """ 15 | @wraps(func) 16 | def wrapper(self, *args, **kwargs): 17 | line = func(self, *args, **kwargs) 18 | func_name = func.__name__ 19 | self.average_message[func_name] = line 20 | return line 21 | return wrapper 22 | 23 | 24 | def getIndicatorName(func): 25 | """ 26 | 此装饰器是获取其他指标值参数名 27 | :param func: 28 | :return: 29 | """ 30 | @wraps(func) 31 | def wrapper(self, *args, **kwargs): 32 | line = func(self, *args, **kwargs) 33 | func_name = func.__name__ 34 | if func_name == "macd": 35 | self.indicator_message["MACD"] = self.macds 36 | self.indicator_message["signal"] = self.signal 37 | self.indicator_message[func_name] = self.histo 38 | elif func_name == "kd": 39 | self.indicator_message["K"] = self.k 40 | self.indicator_message["D"] = self.percD 41 | elif func_name == "boll": 42 | self.indicator_message["mid"] = self.mid 43 | self.indicator_message["top"] = self.top 44 | self.indicator_message["bottom"] = self.bottom 45 | else: 46 | self.indicator_message[func_name] = line 47 | return line 48 | return wrapper 49 | 50 | 51 | class Indicator(File): 52 | def __init__(self): 53 | super().__init__() 54 | self.inited = False # 是否满足计算要求 55 | self.average_message = {} 56 | self.indicator_message = {} 57 | 58 | def calculate(self): 59 | """ 60 | 计算指标 61 | :return: 62 | """ 63 | pass 64 | 65 | @getAverageName 66 | def ma(self, data: object, period=5): 67 | """ 68 | 均线 69 | :param data: 70 | :param period: 71 | :return: 72 | """ 73 | end = len(data) 74 | if not self.inited: 75 | if end < period: 76 | return 77 | else: 78 | self.inited = True 79 | self.ma_data = deepcopy(data) 80 | for i in range(period, end): 81 | self.ma_data = sum(data[i-period:i+1])/period 82 | return self.ma_data 83 | 84 | @getAverageName 85 | def sma(self, data:object, period=15): 86 | """ 87 | sma or ma SimpleMovingAverage 88 | 简单移动平均线 89 | :param period:距离 90 | :param data:数据 object 91 | :return:计算值 92 | """ 93 | end = len(data) 94 | if not self.inited: 95 | if end < period: 96 | return 97 | else: 98 | self.inited = True 99 | self.sma_data = deepcopy(data) 100 | close_line = data 101 | for i in range(period, end): 102 | self.sma_data[i] = sum(close_line[i - period + 1:i + 1]) / period 103 | return self.sma_data 104 | 105 | @getAverageName 106 | def ema(self, data:object, period:int, alpha=None): 107 | """ 108 | ema ExponentialMovingAverage 109 | 指数移动平均(period一般取12和26天) 110 | - self.smfactor -> 2 / (1 + period) 111 | - self.smfactor1 -> `1 - self.smfactor` 112 | - movav = prev * (1.0 - smoothfactor) + newdata * smoothfactor 113 | :param data: 114 | :param period: 115 | :return: 116 | """ 117 | end = len(data) 118 | if not self.inited: 119 | if end < period: 120 | return 121 | else: 122 | self.inited = True 123 | self.ema_data = deepcopy(data) 124 | close_line = data 125 | self.alpha = alpha 126 | if self.alpha is None: 127 | self.alpha = 2.0 / (1.0 + period) 128 | self.alpha1 = 1.0 - self.alpha 129 | prev = close_line[period-1] 130 | for i in range(period, end): 131 | self.ema_data[i] = prev = prev * self.alpha1 + close_line[i] * self.alpha 132 | return self.ema_data 133 | 134 | @getAverageName 135 | def wma(self, data:object, period=30): 136 | ''' 137 | WeightedMovingAverage 加权移动平均线 138 | A Moving Average which gives an arithmetic weighting to values with the 139 | newest having the more weight 140 | 141 | Formula: 142 | - weights = range(1, period + 1) 143 | - coef = 2 / (period * (period + 1)) 144 | - movav = coef * Sum(weight[i] * data[period - i] for i in range(period)) 145 | ''' 146 | end = len(data) 147 | if not self.inited: 148 | if end < period: 149 | return 150 | else: 151 | self.inited = True 152 | self.wma_data = deepcopy(data) 153 | close_line = data 154 | coef = 2.0 / (period * (period + 1.0)) 155 | weights = tuple(float(x) for x in range(1, period + 1)) 156 | for i in range(period, end): 157 | data = close_line[i - period + 1: i + 1] 158 | self.wma_data[i] = coef * math.fsum(map(operator.mul, data, weights)) 159 | return self.wma_data 160 | 161 | @getIndicatorName 162 | def kd(self, data:object, period=14, period_dfast=3): 163 | """ 164 | 随机振荡器 随机指标(KD) : K给出预期信号,以底部或之前的 D给出周转信号,以 D-Slow给出周转确认信号 165 | The regular (or slow version) adds an additional moving average layer and 166 | thus: 167 | 168 | - The percD line of the StochasticFast becomes the percK line 169 | - percD becomes a moving average of period_dslow of the original percD 170 | 171 | Formula: 172 | - hh = highest(data.high, period) 173 | - ll = lowest(data.low, period) 174 | - knum = data.close - ll 175 | - kden = hh - ll 176 | - k = 100 * (knum / kden) 177 | - d = MovingAverage(k, period_dfast) 178 | 179 | - d-slow = MovingAverage(d, period_dslow) 180 | See: 181 | - http://en.wikipedia.org/wiki/Stochastic_oscillator 182 | :param data: 183 | :param period: 184 | :return: 185 | """ 186 | end = len(data) 187 | if not self.inited: 188 | period = max(period, period_dfast) 189 | if end < period: 190 | return 191 | else: 192 | self.inited = True 193 | highest = deepcopy(data) 194 | lowest = deepcopy(data) 195 | for i in range(period, end): 196 | highest[i] = max(self.ret_high[i - period + 1: i + 1]) 197 | for i in range(period, end): 198 | lowest[i] = min(self.ret_low[i - period + 1: i + 1]) 199 | knum = np.array(data) - lowest 200 | kden = np.array(highest) - np.array(lowest) 201 | self.k = 100 * (knum/kden) 202 | self.d = self.sma(self.k, period=period_dfast) 203 | self.percD = self.sma(self.d, period=period_dfast) 204 | return self.k, self.percD 205 | 206 | @getIndicatorName 207 | def macd(self, data:object, period_me1=12, period_me2=26, period_signal=9): 208 | """ 209 | 移动平均趋同/偏离(异同移动平均线) MACDHisto 210 | Formula: 211 | - macd = ema(data, me1_period) - ema(data, me2_period) 212 | - signal = ema(macd, signal_period) 213 | - histo = macd - signal 214 | :param data: 215 | :param period: 216 | :return: 217 | """ 218 | end = len(data) 219 | if not self.inited: 220 | period = max(period_me1, period_me2, period_signal) 221 | if end < period: 222 | return 223 | else: 224 | self.inited = True 225 | me1 = self.ema(data, period=period_me1) 226 | me2 = self.ema(data, period=period_me2) 227 | self.macds = np.array(me1) - np.array(me2) 228 | self.signal = self.ema(self.macds, period=period_signal) 229 | self.histo = np.array(self.macds) - np.array(self.signal) 230 | return self.macds, self.signal, self.histo 231 | 232 | @getAverageName 233 | def rsi(self, data:object, period=14, lookback=1): 234 | """ 235 | rsi 相对强度指数 236 | Formula: 237 | - up = upday(data) 238 | - down = downday(data) 239 | - maup = sma(up, period) or ema(up, period) 240 | - madown = sma(down, period) or ema(down, period) 241 | - rs = maup / madown 242 | - rsi = 100 - 100 / (1 + rs) 243 | :param data: 244 | :param period: 245 | :return: 246 | """ 247 | params = ( 248 | ('period', 14), 249 | ('upperband', 70.0), 250 | ('lowerband', 30.0), 251 | ('safediv', False), 252 | ('safehigh', 100.0), 253 | ('safelow', 50.0), 254 | ('lookback', 1), 255 | ) 256 | end = len(data) 257 | if not self.inited: 258 | if end < period: 259 | return 260 | else: 261 | self.inited = True 262 | upday = deepcopy(data) 263 | downday = deepcopy(data) 264 | for i in range(period, end): 265 | upday[i] = max(data[i]-data[i-1], 0.0) 266 | for i in range(period, end): 267 | downday[i] = max(data[i-1]-data[i], 0.0) 268 | maup = self.ema(upday, period=period) 269 | madown = self.ema(downday, period=period) 270 | rs = np.array(maup) / np.array(madown) 271 | self.rsi_list = [] 272 | for i in rs: 273 | rsi = 100.0 - 100.0 / (1.0 + i) 274 | self.rsi_list.append(rsi) 275 | return self.rsi_list 276 | 277 | @getAverageName 278 | def smma(self, data:object, period:int, alpha=15): 279 | """ 280 | smma 平滑移动平均值 281 | SmoothedMovingAverage 282 | :param data: 283 | :param period: 284 | :return: 285 | """ 286 | end = len(data) 287 | if not self.inited: 288 | period = max(period, alpha) 289 | if end < period: 290 | return 291 | else: 292 | self.inited = True 293 | self.ema_data = deepcopy(data) 294 | close_line = data 295 | self.alpha = alpha 296 | if self.alpha is None: 297 | self.alpha = 2.0 / (1.0 + period) 298 | self.alpha1 = 1.0 - self.alpha 299 | 300 | prev = close_line[period - 1] 301 | for i in range(period, end): 302 | self.ema_data[i] = prev = prev * self.alpha1 + close_line[i] * self.alpha 303 | return self.ema_data 304 | 305 | @getIndicatorName 306 | def atr(self, data:object, period=14): 307 | """ 308 | 平均真实范围 309 | AverageTrueRange 310 | :param data: 311 | :param period: 312 | :return: 313 | """ 314 | end = len(data) 315 | if not self.inited: 316 | if end < period: 317 | return 318 | else: 319 | self.inited = True 320 | truehigh = [] 321 | truelow = [] 322 | truehigh = truehigh + [0] * period 323 | for h in range(period+1, end): 324 | truehigh.append(max(data[h-1], self.ret_high[h])) 325 | truelow = truelow + [0] * period 326 | for l in range(period+1, end): 327 | truelow.append(min(data[l-1], self.ret_low[l])) 328 | tr = np.array(truehigh) - np.array(truelow) 329 | atr = self.sma(tr, period=period) 330 | return atr 331 | 332 | @getIndicatorName 333 | def stdDev(self, data:object, period=20): 334 | """ 335 | StandardDeviation 标准偏差 (StdDev) StandardDeviation 336 | If 2 datas are provided as parameters, the 2nd is considered to be the 337 | mean of the first 338 | Formula: 339 | - meansquared = SimpleMovingAverage(pow(data, 2), period) 均方 340 | - squaredmean = pow(SimpleMovingAverage(data, period), 2) 平方平均 341 | - stddev = pow(meansquared - squaredmean, 0.5) # square root 342 | 343 | See: 344 | - http://en.wikipedia.org/wiki/Standard_deviation 345 | :param data: 346 | :param period: 347 | :return: 348 | """ 349 | end = len(data) 350 | if not self.inited: 351 | if end < period: 352 | return 353 | else: 354 | self.inited = True 355 | meansquared = self.sma(pow(np.array(data), 2), period) 356 | mead_data = self.sma(data, period) 357 | squaredmean = pow(mead_data, 2) 358 | self.stddev = pow(np.array(meansquared)-np.array(squaredmean), 0.5) 359 | return self.stddev 360 | 361 | @getAverageName 362 | def boll(self, data:object, period=20, devfactor=2): 363 | """ 364 | 布林带 (BollingerBands boll 。中轨为股价的平均成本,上轨和下轨可分别视为股价的压力线和支撑线。) 365 | Formula: 366 | - midband = SimpleMovingAverage(close, period) 367 | - topband = midband + devfactor * StandardDeviation(data, period) 368 | - botband = midband - devfactor * StandardDeviation(data, period) 369 | 370 | See: 371 | - http://en.wikipedia.org/wiki/Bollinger_Bands 372 | :param data: 373 | :param period: 374 | :return: top mid bottom 375 | """ 376 | end = len(data) 377 | if not self.inited: 378 | period = max(period, devfactor) 379 | if end < period: 380 | return 381 | else: 382 | self.inited = True 383 | self.mid = self.sma(data, period) 384 | self.top = np.array(self.mid) + devfactor * np.array(self.stdDev(data, period)) 385 | self.bottom = np.array(self.mid) - devfactor * np.array(self.stdDev(data, period)) 386 | 387 | return self.top, self.mid, self.bottom 388 | 389 | @getIndicatorName 390 | def AroonIndicator(self, data:object, period:int): 391 | """ 392 | Formula: 393 | - up = 100 * (period - distance to highest high) / period 394 | - down = 100 * (period - distance to lowest low) / period 395 | See: 396 | - http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon 397 | :param data: 398 | :param period: 399 | :return: 400 | """ 401 | pass 402 | 403 | @getAverageName 404 | def UltimateOscillator(self, data: object, period: int): 405 | ''' 406 | 终极振荡器 407 | Formula: 408 | # Buying Pressure = Close - TrueLow 409 | BP = Close - Minimum(Low or Prior Close) 410 | 411 | # TrueRange = TrueHigh - TrueLow 412 | TR = Maximum(High or Prior Close) - Minimum(Low or Prior Close) 413 | 414 | Average7 = (7-period BP Sum) / (7-period TR Sum) 415 | Average14 = (14-period BP Sum) / (14-period TR Sum) 416 | Average28 = (28-period BP Sum) / (28-period TR Sum) 417 | 418 | UO = 100 x [(4 x Average7)+(2 x Average14)+Average28]/(4+2+1) 419 | 420 | See: 421 | 422 | - https://en.wikipedia.org/wiki/Ultimate_oscillator 423 | - http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ultimate_oscillator 424 | ''' 425 | pass 426 | 427 | @getIndicatorName 428 | def trix(self, data: object, period: int, rocperiod=1): 429 | ''' 430 | 三重指数平滑移动平均 技术分析(Triple Exponentially Smoothed Moving Average) TR 431 | Defined by Jack Hutson in the 80s and shows the Rate of Change (%) or slope 432 | of a triple exponentially smoothed moving average 433 | 434 | Formula: 435 | - ema1 = EMA(data, period) 436 | - ema2 = EMA(ema1, period) 437 | - ema3 = EMA(ema2, period) 438 | - trix = 100 * (ema3 - ema3(-1)) / ema3(-1) 439 | 440 | The final formula can be simplified to: 100 * (ema3 / ema3(-1) - 1) 441 | 442 | The moving average used is the one originally defined by Wilder, 443 | the SmoothedMovingAverage 444 | 445 | See: 446 | - https://en.wikipedia.org/wiki/Trix_(technical_analysis) 447 | - http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:trix 448 | ''' 449 | end = len(data) 450 | if not self.inited: 451 | if end < period: 452 | return 453 | else: 454 | self.inited = True 455 | ema1 = self.ema(data, period=period) 456 | ema2 = self.ema(ema1, period=period) 457 | ema3 = self.ema(ema2, period=period) 458 | end = len(ema3) 459 | self.trix_list = ema3 460 | for i in range(period, end): 461 | self.trix_list[i] = 100.0 * (ema3[i]/ema3[i-rocperiod] - 1.0) 462 | return self.trix_list 463 | 464 | @getIndicatorName 465 | def roc(self, data: object, period=12): 466 | """ 467 | Formula: 468 | - roc = (data - data_period) / data_period 469 | 470 | See: 471 | - http://en.wikipedia.org/wiki/Momentum_(technical_analysis) 472 | :param data: 473 | :param period: 474 | :return: 475 | """ 476 | end = len(data) 477 | if not self.inited: 478 | if end < period: 479 | return 480 | else: 481 | self.inited = True 482 | self.roc_list = deepcopy(data) 483 | for i in range(period, end): 484 | self.roc_list[i] = (data[i] - data[i-period]) / data[i-period] 485 | return self.roc_list 486 | 487 | @getIndicatorName 488 | def mtm(self, data: object, period: int): 489 | """ 490 | 动量指标(MTM) Momentum 491 | Formula: 492 | - momentum = data - data_period 493 | 494 | See: 495 | - http://en.wikipedia.org/wiki/Momentum_(technical_analysis) 496 | :param data: 497 | :param period: 498 | :return: 499 | """ 500 | end = len(data) 501 | if not self.inited: 502 | if end < period: 503 | return 504 | else: 505 | self.inited = True 506 | self.momentum_list = deepcopy(data) 507 | for i in range(period, end): 508 | self.momentum_list[i] = data[i] - data[i-period] 509 | return self.momentum_list 510 | 511 | @getIndicatorName 512 | def tema(self, data: object, period: int): 513 | """ 514 | TripleExponentialMovingAverage(TEMA 试图减少与移动平均数相关的固有滞后) 515 | Formula: 516 | - ema1 = ema(data, period) 517 | - ema2 = ema(ema1, period) 518 | - ema3 = ema(ema2, period) 519 | - tema = 3 * ema1 - 3 * ema2 + ema3 520 | :param data: 521 | :param period: 522 | :return: 523 | """ 524 | end = len(data) 525 | if not self.inited: 526 | if end < period: 527 | return 528 | else: 529 | self.inited = True 530 | ema1 = self.ema(data, period) 531 | ema2 = self.ema(ema1, period) 532 | ema3 = self.ema(ema2, period) 533 | self.tema_list = 3 * np.array(ema1) - 3 * ema2 + ema3 534 | return self.tema_list 535 | 536 | @getIndicatorName 537 | def wr(self, data:object, period=14): 538 | """ 539 | WilliamsR 540 | Formula: 541 | - num = highest_period - close 542 | - den = highestg_period - lowest_period 543 | - percR = (num / den) * -100.0 544 | 545 | See: 546 | - http://en.wikipedia.org/wiki/Williams_%25R 547 | :param data: 548 | :param period: 549 | :return: 550 | """ 551 | end = len(data) 552 | if not self.inited: 553 | if end < period: 554 | return 555 | else: 556 | self.inited = True 557 | num = deepcopy(data) 558 | den = deepcopy(data) 559 | for i in range(period, end): 560 | num[i] = max(self.ret_high[i - period + 1: i + 1]) 561 | for i in range(period, end): 562 | den[i] = min(self.ret_low[i - period + 1: i + 1]) 563 | self.percR = -100 * (np.array(num) / np.array(data)) / (np.array(num) - np.array(den)) 564 | return self.percR 565 | 566 | def mean_dev(self, data, mean, period=20): 567 | """ 568 | MeanDeviation 569 | Note: 570 | - If 2 datas are provided as parameters, the 2nd is considered to be the 571 | mean of the first 572 | 573 | Formula: 574 | - mean = MovingAverage(data, period) (or provided mean) 575 | - absdeviation = abs(data - mean) 576 | - meandev = MovingAverage(absdeviation, period) 577 | 578 | See: 579 | - https://en.wikipedia.org/wiki/Average_absolute_deviation 580 | :param data: 581 | :param period: 582 | :return: 583 | """ 584 | absdev = abs(np.array(data)-np.array(mean)) 585 | meandev = self.sma(absdev, period) 586 | return meandev 587 | 588 | def cci(self, period=20, factor=0.015): 589 | """ 590 | 商品渠道指数 CommodityChannelIndex 591 | Formula: 592 | - tp = typical_price = (high + low + close) / 3 593 | - tpmean = MovingAverage(tp, period) 594 | - deviation = tp - tpmean 595 | - meandev = MeanDeviation(tp) 596 | - cci = deviation / (meandeviation * factor) 597 | 598 | See: 599 | - https://en.wikipedia.org/wiki/Commodity_channel_index 600 | :return: 601 | """ 602 | end = len(self.ret_close) 603 | if not self.inited: 604 | if end < period: 605 | return 606 | else: 607 | self.inited = True 608 | tp = (self.ret_high + self.ret_low + self.ret_close) / 3 609 | tpmean = self.sma(tp, period) 610 | dev = np.array(tp) - np.array(tpmean) 611 | meandev = self.mean_dev(tp, tpmean, period) 612 | self.cci_list = np.array(dev) / (factor*meandev) 613 | return self.cci_list 614 | 615 | def sar(self, data, period=2, i_af=0.02, afmax=0.02): 616 | """ 617 | 抛物线指标 Parabolic SAR 618 | See: 619 | - https://en.wikipedia.org/wiki/Parabolic_SAR 620 | - http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:parabolic_sar 621 | 622 | :return: 623 | """ 624 | self.sar_list = [] 625 | status = { 626 | "sar": None, 627 | "tr": None, 628 | "af": 0.0, 629 | "ep": 0.0 630 | } 631 | num = len(data) 632 | 633 | sar = (self.ret_high[0] + self.ret_low[0]) / 2.0 634 | status['sar'] = sar 635 | status['af'] = i_af 636 | if data[1] >= data[0]: 637 | status['tr'] = False 638 | status['ep'] = self.ret_low[0] 639 | else: 640 | status['tr'] = True 641 | status['ep'] = self.ret_high[0] 642 | 643 | for i in range(num): 644 | n = i - period + 1 645 | m = n + 1 646 | 647 | hi = self.ret_high[m] 648 | lo = self.ret_low[m] 649 | 650 | tr = status['tr'] 651 | sar = status['sar'] 652 | 653 | if(tr and sar >= lo) or (not tr and sar <= hi): 654 | tr = not tr 655 | sar = status['ep'] 656 | ep = hi if tr else lo 657 | af = i_af 658 | else: 659 | ep = status['ep'] 660 | af = status['af'] 661 | 662 | if tr: 663 | if hi > ep: 664 | ep = hi 665 | af = min(af + i_af, afmax) 666 | else: 667 | if lo < ep: 668 | ep = lo 669 | af = min(af + i_af, afmax) 670 | sar = sar + af * (ep - sar) 671 | 672 | if tr: # long trade 673 | lo1 = self.ret_low[n] 674 | if sar > lo or sar > lo1: 675 | sar = min(lo, lo1) # sar not above last 2 lows -> lower 676 | else: 677 | hi1 = self.ret_high[n] 678 | if sar < hi or sar < hi1: 679 | sar = max(hi, hi1) 680 | status['tr'] = tr 681 | status['sar'] = sar 682 | status['ep'] = ep 683 | status['af'] = af 684 | self.sar_list.append(status) 685 | return self.sar_list -------------------------------------------------------------------------------- /indicator/interface.py: -------------------------------------------------------------------------------- 1 | from .plot import Scheduler 2 | 3 | 4 | class Indicator: 5 | 6 | @property 7 | def inited(self): 8 | """ 9 | 用户判断是否满足计算指标 10 | :return: bool 11 | """ 12 | return Scheduler.inited 13 | 14 | @property 15 | def open(self): 16 | """ 17 | Get open price time series. 18 | """ 19 | return Scheduler.ret_open 20 | 21 | @property 22 | def high(self): 23 | """ 24 | Get high price time series. 25 | """ 26 | return Scheduler.ret_high 27 | 28 | @property 29 | def low(self): 30 | """ 31 | Get low price time series. 32 | """ 33 | return Scheduler.ret_low 34 | 35 | @property 36 | def close(self): 37 | """ 38 | Get low price time series 39 | :return: 40 | """ 41 | return Scheduler.ret_close 42 | 43 | @property 44 | def volume(self): 45 | """ 46 | Get volume number 47 | :return: 48 | """ 49 | return Scheduler.ret_volume 50 | 51 | def open_csv(self, file: str, start_time=None, end_time=None): 52 | """ 53 | open TXT file 54 | data_type: 55 | Date,Open,High,Low,Close,Volume 56 | '2019-01-07 00:00:00', 3831.0, 3847.0, 3831.0, 3840.0, 554 57 | '2019-01-08 00:00:00', 3841.0, 3841.0, 3833.0, 3836.0, 554 58 | ... 59 | :param file: name 60 | :param start_time: 61 | :param end_time: 62 | :return: 63 | """ 64 | return Scheduler.open_csv(file, start_time, end_time) 65 | 66 | def open_json(self, file: str, start_time=None, end_time=None): 67 | """ 68 | open JSON file 69 | data_type: 70 | {"zn1912.SHFE": [ 71 | ["2014-01-01", 18780.0, 18780.0, 18770.0, 18775.0, 266], 72 | ["2014-01-02", 18775.0, 18780.0, 18770.0, 18770.0, 312], 73 | ... 74 | ] 75 | } 76 | :param file: name 77 | :param start_time: 78 | :param end_time: 79 | :return: 80 | """ 81 | return Scheduler.open_json(file, start_time, end_time) 82 | 83 | def open_cache(self, data: list): 84 | """ 85 | read CACHE data 86 | data_type: 87 | [["2014-01-01", 22, 44, 55, 55, 6666], ["2014-01-02", 22, 44, 55, 55, 6666], ...] 88 | :param data: 89 | :return: 90 | """ 91 | return Scheduler.open_cache(data) 92 | 93 | def add_bar(self, data, opens=False): 94 | """ 95 | new bar push in array 96 | :param data: bar 97 | :param opens: if True save file else not save (default False) 98 | :return: 99 | """ 100 | Scheduler.update_bar(data, opens) 101 | 102 | def ma(self, n=15): 103 | if not self.inited: 104 | return 105 | data = Scheduler.ret_close 106 | return Scheduler.ma(data, n) 107 | 108 | def sma(self, n=15): 109 | data = Scheduler.ret_close 110 | return Scheduler.sma(data, n) 111 | 112 | def ema(self, n=12, alpha=None): 113 | data = Scheduler.ret_close 114 | return Scheduler.ema(data, n, alpha) 115 | 116 | def wma(self, n=30): 117 | data = Scheduler.ret_close 118 | return Scheduler.wma(data, n) 119 | 120 | def kd(self, n=14, f=3): 121 | data = Scheduler.ret_close 122 | return Scheduler.kd(data, n, f) 123 | 124 | def macd(self, n=12, m=20, f=9): 125 | data = Scheduler.ret_close 126 | return Scheduler.macd(data, n, m, f) 127 | 128 | def rsi(self, n=14, l=1): 129 | data = Scheduler.ret_close 130 | return Scheduler.rsi(data, n, l) 131 | 132 | def smma(self, n=10, alpha=15): 133 | data = Scheduler.ret_close 134 | return Scheduler.smma(data, n, alpha) 135 | 136 | def atr(self, n=14): 137 | data = Scheduler.ret_close 138 | return Scheduler.atr(data, n) 139 | 140 | def stdDev(self, n=20): 141 | data = Scheduler.ret_close 142 | return Scheduler.stdDev(data, n) 143 | 144 | def boll(self, n=20, m=2): 145 | data = Scheduler.ret_close 146 | return Scheduler.boll(data, n, m) 147 | 148 | def trix(self, n=15, m=1): 149 | data = Scheduler.ret_close 150 | return Scheduler.trix(data, n, m) 151 | 152 | def roc(self, n=12): 153 | data = Scheduler.ret_close 154 | return Scheduler.roc(data, n) 155 | 156 | def mtm(self, n=12): 157 | data = Scheduler.ret_close 158 | return Scheduler.mtm(data, n) 159 | 160 | def tema(self, n=25): 161 | data = Scheduler.ret_close 162 | return Scheduler.tema(data, n) 163 | 164 | def wr(self, n=14): 165 | data = Scheduler.ret_close 166 | return Scheduler.wr(data, n) 167 | 168 | def cci(self, n=20, f=0.015): 169 | return Scheduler.cci(n, f) 170 | 171 | def sar(self, n=2, af=0.02, afmax=0.20): 172 | data = Scheduler.ret_close 173 | return Scheduler.sar(data, n, af, afmax) 174 | 175 | def UltimateOscillator(self): 176 | pass 177 | 178 | def AroonIndicator(self): 179 | pass 180 | 181 | def plot(self, width=8, height=6, color="k", lw=0.5): 182 | Scheduler.plot(width=width, height=height, color=color, lw=lw) 183 | 184 | 185 | api = Indicator -------------------------------------------------------------------------------- /indicator/json/zn1912.SHFE.json: -------------------------------------------------------------------------------- 1 | {"zn1912.SHFE": [ 2 | ["2014-01-01", 18780.0, 18780.0, 18770.0, 18775.0, 266], 3 | ["2014-01-01", 18775.0, 18780.0, 18770.0, 18770.0, 312], 4 | ["2014-01-01", 18770.0, 18775.0, 18770.0, 18770.0, 172], 5 | ["2014-01-01", 18770.0, 18775.0, 18770.0, 18775.0, 78], 6 | ["2014-01-01", 18775.0, 18775.0, 18770.0, 18775.0, 88], 7 | ["2014-01-01", 18775.0, 18780.0, 18770.0, 18780.0, 224], 8 | ["2014-01-01", 18780.0, 18785.0, 18775.0, 18785.0, 294], 9 | ["2014-01-01", 18785.0, 18790.0, 18780.0, 18780.0, 422], 10 | ["2014-01-01", 18780.0, 18785.0, 18775.0, 18775.0, 376], 11 | ["2014-01-01", 18775.0, 18780.0, 18775.0, 18775.0, 118], 12 | ["2014-01-01", 18775.0, 18780.0, 18775.0, 18780.0, 24], 13 | ["2014-01-01", 18780.0, 18780.0, 18765.0, 18770.0, 442], 14 | ["2014-01-01", 18770.0, 18770.0, 18760.0, 18760.0, 360], 15 | ["2014-01-01", 18760.0, 18765.0, 18760.0, 18760.0, 484], 16 | ["2014-01-01", 18760.0, 18760.0, 18750.0, 18755.0, 498], 17 | ["2014-01-01", 18750.0, 18755.0, 18750.0, 18755.0, 352], 18 | ["2014-01-01", 18755.0, 18760.0, 18750.0, 18755.0, 342], 19 | ["2014-01-01", 18755.0, 18760.0, 18750.0, 18750.0, 128], 20 | ["2014-01-01", 18750.0, 18750.0, 18745.0, 18750.0, 424], 21 | ["2014-01-01", 18750.0, 18755.0, 18745.0, 18750.0, 256], 22 | ["2014-01-01", 18750.0, 18770.0, 18750.0, 18770.0, 750], 23 | ["2014-01-01", 18770.0, 18770.0, 18765.0, 18770.0, 84], 24 | ["2014-01-01", 18770.0, 18770.0, 18760.0, 18760.0, 154], 25 | ["2014-01-01", 18760.0, 18765.0, 18760.0, 18765.0, 26] 26 | ]} -------------------------------------------------------------------------------- /indicator/plot.py: -------------------------------------------------------------------------------- 1 | """ 2 | plot显示线 3 | """ 4 | from .indicator import Indicator 5 | 6 | colors = { 7 | "sma": "b", 8 | "ema": "r", 9 | "wma": "c", 10 | "rsi": "g", 11 | "smma": "r", 12 | "atr": "w", 13 | "stddev": "k", 14 | "trix": "c", 15 | "mtm": "y", 16 | "tema": "m", 17 | "wr": "r", 18 | "macd": "g", 19 | "MACD": "r", 20 | "signal": "b", 21 | "K": "g", 22 | "D": "r", 23 | "mid": "g", 24 | "top": "r", 25 | "bottom": "b" 26 | } 27 | 28 | 29 | class ShowLine(Indicator): 30 | # def __new__(cls, *args, **kwargs): 31 | # if not hasattr(cls, "_instance"): 32 | # obj = super(ShowLine, cls) 33 | # cls._instance = obj.__new__(cls, *args, **kwargs) 34 | # return cls._instance 35 | 36 | def __init__(self): 37 | super().__init__() 38 | 39 | def plot(self, width=8, height=6, color="k", lw=0.5): 40 | try: 41 | from matplotlib import pyplot as plt 42 | from matplotlib.widgets import MultiCursor 43 | import matplotlib.dates as mdate 44 | except ImportError: 45 | raise ImportError("please pip install matplotlib") 46 | # 一个画布 47 | fig = plt.figure(figsize=(width, height)) 48 | # 画布分块 块1 49 | ax1 = fig.add_subplot(211) 50 | datetime = self.ret_date 51 | volume = self.ret_volume 52 | close = self.ret_close 53 | # 柱 54 | ax1.bar(datetime, volume, color='y', label='volume') 55 | ax1.set_ylabel('volume') 56 | ax2 = ax1.twinx() 57 | 58 | # 线 59 | ax2.plot(datetime, close, "#000000", label="CLOSE") 60 | if self.average_message: 61 | for average_line in self.average_message: 62 | ax2.plot(datetime, self.average_message[average_line], colors[average_line], label=average_line) 63 | 64 | ax2.set_ylabel('price') 65 | # 标题 66 | plt.title("CTPBEE") 67 | # 网格 68 | plt.grid(True) 69 | # 图列 70 | plt.legend() 71 | # 显示时间间隔 72 | ax1.xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d %H:%M:%S')) 73 | # plt.xticks(pd.date_range(datetime[0], datetime[-1])) 74 | 75 | # 块2 76 | ax3 = plt.subplot(212) 77 | # 柱形图 78 | if self.indicator_message: 79 | for indicator_line in self.indicator_message: 80 | plt.plot(datetime, self.indicator_message[indicator_line], colors[indicator_line], label=indicator_line) 81 | # 网格 82 | plt.grid(True) 83 | plt.title("indicator") 84 | plt.legend() 85 | ax3.xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d %H:%M:%S')) # %H:%M:%S 86 | # plt.xticks(pd.date_range(datetime[0], datetime[-1])) 87 | multi = MultiCursor(fig.canvas, (ax1, ax3), color=color, lw=lw, useblit=True, linestyle=':', horizOn=True) 88 | plt.show() 89 | 90 | 91 | Scheduler = ShowLine() -------------------------------------------------------------------------------- /indicator/readfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import csv 4 | import json 5 | import time 6 | import numpy as np 7 | from datetime import datetime, date 8 | 9 | 10 | class ReadFile: 11 | def __init__(self): 12 | self.count = 0 # 数量 13 | self.ret_data = [] # 总数据 14 | self.ret_open = [] # 开盘价 15 | self.ret_low = [] # 最低价 16 | self.ret_high = [] # 最高价 17 | self.ret_date = [] # 时间 18 | self.ret_close = [] # 收盘价 19 | self.ret_volume = [] # 成交量 20 | self.open_file_name = None # 文件名 21 | self.open_file_start = None # 开始时间 22 | # self.inited = False # 是否满足计算要求 23 | 24 | def update_bar(self, datas: dict, switch=False): 25 | """ 26 | :param data: 数据类型 27 | [time, open, high, low, close, volume] 28 | [1883823344, 22, 44, 55, 55, 6666] 29 | :param switch: 开关 30 | :return: 31 | """ 32 | if not datas: 33 | raise Warning("type error or type is None") 34 | if isinstance(datas, dict): 35 | data = [datas["datetime"], datas["open_price"], datas["high_price"], datas["low_price"], datas["close_price"], 36 | 1] 37 | else: 38 | try: 39 | datas = datas._to_dict() 40 | except: 41 | raise TypeError("只支持 dict和BarData这个两种数据") 42 | data = [datas["datetime"], datas["open_price"], datas["high_price"], datas["low_price"], 43 | datas["close_price"], 44 | 1] 45 | if switch: 46 | 47 | if isinstance(data[0], datetime): 48 | data[0] = data[0].strftime('%Y-%m-%d %H:%M:%S') 49 | elif isinstance(data[0], date): 50 | data[0] = data[0].strftime('%Y-%m-%d') 51 | else: 52 | time_local = time.localtime(float(data[0]) / 1000) 53 | data[0] = time.strftime("%Y-%m-%d %H:%M:%S", time_local) 54 | 55 | if self.open_file_name.endswith(".csv"): 56 | with open(self.open_file_name, 'a+', newline='') as f: 57 | w_data = csv.writer(f) 58 | w_data.writerows(data) 59 | if self.open_file_name.endswith(".json"): 60 | with open(self.open_file_name, 'r') as jr: 61 | r_json = json.loads(jr.read()) 62 | r_name = [name for name in r_json][0] 63 | r_json[r_name].append(data) 64 | with open(self.open_file_name, 'w') as jw: 65 | json.dump(r_json, jw) 66 | 67 | if self.open_file_name.endswith(".txt"): 68 | with open(self.open_file_name, 'a+') as t: 69 | txt = "\n" + str(data).strip("[]") 70 | t.write(txt) 71 | 72 | else: 73 | max_value = 60 74 | if self.count > max_value: 75 | self.ret_close = self.ret_close[-max_value:] 76 | self.ret_high = self.ret_high[-max_value:] 77 | self.ret_low = self.ret_low[-max_value:] 78 | self.ret_open = self.ret_open[-max_value:] 79 | self.ret_volume = self.ret_volume[-max_value:] 80 | self.count += 1 81 | # if not self.inited: 82 | # if self.count > 30: 83 | # self.inited = True 84 | self.ret_close = np.append(self.ret_close, data[4]) 85 | self.ret_high = np.append(self.ret_high, data[2]) 86 | self.ret_low = np.append(self.ret_low, data[3]) 87 | self.ret_open = np.append(self.ret_open, data[1]) 88 | self.ret_volume = np.append(self.ret_volume, data[5]) 89 | 90 | def save_file(self, data): 91 | """保存数据""" 92 | pass 93 | 94 | def path(self, file): 95 | if not file: 96 | raise FileExistsError("文件名不能为空") 97 | modpath = os.path.dirname(os.path.abspath(sys.argv[0])) 98 | datapath = os.path.join(modpath, file) 99 | self.open_file_name = datapath 100 | return datapath 101 | 102 | def data_columns(self, data: str, start_time=None, end_time=None): 103 | self.ret_data = data 104 | self.ret_volume = data[4] 105 | self.ret_open = data[0] 106 | self.ret_low = data[2] 107 | self.ret_high = data[1] 108 | self.ret_close = data[3] 109 | self.count = len(data[4]) 110 | return self.ret_close 111 | 112 | def open_csv(self, file: str, start_time=None, end_time=None): 113 | """ 114 | 读取txt文件 115 | data_type: 116 | Date,Open,High,Low,Close,Volume 117 | '2019-01-07 00:00:00', 3831.0, 3847.0, 3831.0, 3840.0, 554 118 | '2019-01-08 00:00:00', 3841.0, 3841.0, 3833.0, 3836.0, 554 119 | ... 120 | :param file: 文件名 121 | :param start_time: 开始读取时间 122 | :param end_time: 结束时间 123 | :return: array对象 124 | """ 125 | datapath = self.path(file) 126 | data = np.loadtxt(datapath, skiprows=2, dtype=float, delimiter=',', usecols=(1, 2, 3, 4, 5), unpack=True) 127 | ret_close = self.data_columns(data, start_time, end_time) 128 | return ret_close 129 | 130 | def open_json(self, file: str, start_time=None, end_time=None): 131 | """ 132 | 读取json文件 133 | data_type: 134 | {"zn1912.SHFE": [ 135 | ["2014-01-01", 18780.0, 18780.0, 18770.0, 18775.0, 266], 136 | ["2014-01-02", 18775.0, 18780.0, 18770.0, 18770.0, 312], 137 | ... 138 | ] 139 | } 140 | :param file: 文件名 141 | :param start_time: 142 | :param end_time: 143 | :return: 144 | """ 145 | datapath = self.path(file) 146 | data_str = open(datapath).read() 147 | data_loads = json.loads(data_str) 148 | for data_name, data_all in data_loads.items(): 149 | data_lines = data_all 150 | datas = np.array(data_lines) 151 | data = np.array([datas[:, 1], datas[:, 2], datas[:, 3], datas[:, 4], datas[:, 5]], dtype=float) 152 | ret_close = self.data_columns(data, start_time, end_time) 153 | return ret_close 154 | 155 | def open_cache(self, data:list): 156 | """ 157 | 读取cache数据 158 | :param data: 159 | [[1883823344, 22, 44, 55, 55, 6666], [1883823345, 22, 44, 55, 55, 6666], ...] 160 | :return: 161 | """ 162 | datas = np.array(data) 163 | data_array = np.array([datas[:, 1], datas[:, 2], datas[:, 3], datas[:, 4], datas[:, 5]], dtype=float) 164 | ret_close = self.data_columns(data_array) 165 | return ret_close 166 | 167 | 168 | File = ReadFile 169 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | """ 2 | 当前回测示例 3 | 1.当前数据基于rq进行下载的 4 | 2.首先你需要调用get_data 来获得rq的数据 ,然后save_to_json保存到 json文件中去,主要在此过程中你需要手动对数据加入symbol等 5 | 3.然后通过load_data函数重复调用数据 6 | 4.调用run_main进行回测 7 | 当前的strategy是借助vnpy的 ArrayManager . 你需要对此实现一些额外的安装操作 8 | 需要额外安装的包 9 | ta-lib, rqdatac( 后面需要被取代 ?? Maybe use quantdata ) 10 | 目前暂时不够完善 ---> hope it will be a very fancy framework 11 | written by somewheve 2019-9-30 08:43 12 | """ 13 | 14 | import json 15 | from datetime import datetime, date 16 | from ctpbee import LooperApi, Vessel 17 | from ctpbee.constant import Direction 18 | from indicator.interface import api 19 | 20 | 21 | def get_data(start, end, symbol, exchange, level): 22 | """ using rqdatac to make an example """ 23 | # import rqdatac as rq 24 | # from rqdatac import get_price, id_convert 25 | # username = "license" 26 | # password = "NK-Ci7vnLsRiPPWYwxvvPYdYM90vxN60qUB5tVac2mQuvZ8f9Mq8K_nnUqVspOpi4BLTkSLgq8OQFpOOj7L" \ 27 | # "t7AbdBZEBqRK74fIJH5vsaAfFQgl-tuB8l03axrW8cyN6-nBUho_6Y5VCRI63Mx_PN54nsQOpc1psIGEz" \ 28 | # "gND8c6Y=bqMVlABkpSlrDNk4DgG-1QXNknJtk0Kkw2axvFDa0E_XPMqOcBxifuRa_DFI2svseXU-8A" \ 29 | # "eLjchnTkeuvQkKh6nrfehVDiXjoMeq5sXgqpbgFAd4A5j2B1a0gpE3cb5kXb42n13fGwFaGris" \ 30 | # "8-eKzz_jncvuAamkJEQQV0aLdiw=" 31 | # host = "rqdatad-pro.ricequant.com" 32 | # port = 16011 33 | # rq.init(username, password, (host, port)) 34 | # symbol_rq = id_convert(symbol) 35 | # data = get_price(symbol_rq, start_date=start, end_date=end, frequency=level, fields=None, 36 | # adjust_type='pre', skip_suspended=False, market='cn', expect_df=False) 37 | # origin = data.to_dict(orient='records') 38 | # result = [] 39 | # for x in origin: 40 | # do = {} 41 | # do['open_price'] = x['open'] 42 | # do['low_price'] = x['low'] 43 | # do['high_price'] = x['high'] 44 | # do['close_price'] = x['close'] 45 | # do['datetime'] = datetime.strptime(str(x['trading_date']), "%Y-%m-%d %H:%M:%S") 46 | # do['symbol'] = symbol 47 | # do['local_symbol'] = symbol + "." + exchange 48 | # do['exchange'] = exchange 49 | # result.append(do) 50 | # return result 51 | 52 | 53 | def get_a_strategy(): 54 | 55 | class SmaStrategy(LooperApi): 56 | 57 | def __init__(self, name): 58 | super().__init__(name) 59 | self.count = 1 60 | self.pos = 0 61 | self.bar_5 = api() # 5分钟bar线 62 | self.bar_3 = api() # 3分钟bar线 63 | self.bar_3.open_json('indicator/json/zn1912.SHFE.json') # 读取本地数据 64 | self.bar_5.open_json('indicator/json/zn1912.SHFE.json') 65 | 66 | self.allow_max_price = 5000 # 设置价格上限 当价格达到这个就卖出 防止突然跌 67 | self.allow_low_price = 2000 # 设置价格下限 当价格低出这里就卖 防止巨亏 68 | 69 | # self.bar_3.open_csv('indicator/txt/orcl-2014.txt') 70 | 71 | def on_bar(self, bar): 72 | # todo: 简单移动平均线 73 | """ """ 74 | self.bar_3.add_bar(bar) 75 | # if not self.bar_3.inited: 76 | # return 77 | close = self.bar_3.close 78 | # 简单移动平均线 79 | # sma = self.bar_3.sma() 80 | # 加权移动 81 | # wma = self.bar_3.wma() 82 | # k d 83 | # k, d = self.bar_3.kd() 84 | # std 85 | # std = self.bar_3.bar_3.stdDev() 86 | # boll 87 | # t, m, b = self.bar_3.boll() 88 | # roc 89 | # roc = self.bar_3.roc() 90 | # mtm 91 | # mtm = self.bar_3.mtm() 92 | # wr 93 | # wr = self.bar_3.wr() 94 | # sar 95 | # sar = self.bar_3.sar() 96 | # macd 97 | macd, signal, histo = self.bar_3.macd() 98 | # rsi 99 | # rsi = self.bar_3.rsi() 100 | # atr 101 | # atr = self.bar_3.atr() 102 | # tema 103 | # tema = self.bar_3.tema() 104 | # ema 105 | # ema = self.bar_3.ema() 106 | # trix = self.bar_3.trix() 107 | # smma = self.bar_3.smma() 108 | # cci 109 | # cci = self.bar_3.cci() 110 | 111 | if self.allow_max_price < close[-1] and self.pos > 0: 112 | self.action.sell(bar.close_price, self.pos, bar) 113 | 114 | if self.allow_low_price > close[-1] and self.pos > 0: 115 | self.action.sell(bar.close_price, self.pos, bar) 116 | 117 | if histo[-1] > 0: 118 | if self.pos == 0: 119 | self.action.buy(bar.close_price, 1, bar) 120 | else: 121 | if self.pos > 0: 122 | self.action.sell(bar.close_price, 1, bar) 123 | self.action.short(bar.close_price, 1, bar) 124 | 125 | def on_trade(self, trade): 126 | if trade.direction == Direction.LONG: 127 | self.pos += trade.volume 128 | else: 129 | self.pos -= trade.volume 130 | 131 | def init_params(self, data): 132 | """""" 133 | # print("我在设置策略参数") 134 | 135 | class MacdStrategy(LooperApi): 136 | # todo: 简单异同移动平均 macd 137 | boll_window = 18 138 | boll_dev = 3.4 139 | cci_window = 10 140 | atr_window = 30 141 | sl_multiplier = 5.2 142 | fixed_size = 1 143 | 144 | boll_up = 0 145 | boll_down = 0 146 | cci_value = 0 147 | atr_value = 0 148 | 149 | intra_trade_high = 0 150 | intra_trade_low = 0 151 | long_stop = 0 152 | short_stop = 0 153 | 154 | parameters = ["boll_window", "boll_dev", "cci_window", 155 | "atr_window", "sl_multiplier", "fixed_size"] 156 | variables = ["boll_up", "boll_down", "cci_value", "atr_value", 157 | "intra_trade_high", "intra_trade_low", "long_stop", "short_stop"] 158 | 159 | def __init__(self, name): 160 | super().__init__(name) 161 | self.pos = 0 162 | 163 | def on_bar(self, bar): 164 | api.open_csv('indicator/txt/orcl-2014.txt') 165 | api.add_bar(bar, opens=True) 166 | close = api.close 167 | macd = api.macd() 168 | # 如果当前macd大于0就买 169 | if macd[-1] > 0: 170 | if self.pos == 0: 171 | pass 172 | elif self.pos > 0: 173 | self.action.cover(bar.close_price, 1, bar) 174 | self.action.buy(bar.close_price, 1, bar) 175 | # 如果小于就卖 176 | else: 177 | if self.pos > 0: 178 | self.action.sell(bar.close_price, 1, bar) 179 | self.action.short(bar.close_price, 1, bar) 180 | 181 | def on_trade(self, trade): 182 | if trade.direction == Direction.LONG: 183 | self.pos += trade.volume 184 | else: 185 | self.pos -= trade.volume 186 | 187 | def on_order(self, order): 188 | pass 189 | 190 | return SmaStrategy("double_ma") 191 | # return MacdStrategy("double_ma") 192 | 193 | 194 | def save_data_json(data): 195 | result = {"result": data} 196 | 197 | class CJsonEncoder(json.JSONEncoder): 198 | def default(self, obj): 199 | if isinstance(obj, datetime): 200 | return obj.strftime('%Y-%m-%d %H:%M:%S') 201 | elif isinstance(obj, date): 202 | return obj.strftime('%Y-%m-%d') 203 | else: 204 | return json.JSONEncoder.default(self, obj) 205 | 206 | with open("data.json", "w") as f: 207 | json.dump(result, f, cls=CJsonEncoder) 208 | 209 | 210 | def load_data(): 211 | with open("data.json", "r") as f: 212 | data = json.load(f) 213 | return data.get("result") 214 | 215 | 216 | def run_main(data): 217 | vessel = Vessel() 218 | vessel.add_data(data) 219 | stra = get_a_strategy() 220 | vessel.add_strategy(stra) 221 | vessel.set_params({"looper": 222 | {"initial_capital": 100000, 223 | "commission": 0.005, 224 | "deal_pattern": "price", 225 | "size_map": {"ag1912.SHFE": 15}, 226 | "today_commission": 0.005, 227 | "yesterday_commission": 0.02, 228 | "close_commission": 0.005, 229 | "slippage_sell": 0, 230 | "slippage_cover": 0, 231 | "slippage_buy": 0, 232 | "slippage_short": 0, 233 | "close_pattern": "yesterday", 234 | }, 235 | "strategy": {} 236 | }) 237 | vessel.run() 238 | from pprint import pprint 239 | result = vessel.get_result() 240 | pprint(result) 241 | 242 | 243 | if __name__ == '__main__': 244 | # data = get_data(start="2019-1-5", end="2019-9-1", symbol="ag1912", exchange="SHFE", level="15m") 245 | # save_data_json(data) 246 | 247 | data = load_data() 248 | for x in data: 249 | x['datetime'] = datetime.strptime(str(x['datetime']), "%Y-%m-%d %H:%M:%S") 250 | run_main(data) 251 | 252 | -------------------------------------------------------------------------------- /zn1912.SHFE.json: -------------------------------------------------------------------------------- 1 | {"zn1912.SHFE": [ 2 | ["2014-01-01", 18780.0, 18780.0, 18770.0, 18775.0, 266], 3 | ["2014-01-01", 18775.0, 18780.0, 18770.0, 18770.0, 312], 4 | ["2014-01-01", 18770.0, 18775.0, 18770.0, 18770.0, 172], 5 | ["2014-01-01", 18770.0, 18775.0, 18770.0, 18775.0, 78], 6 | ["2014-01-01", 18775.0, 18775.0, 18770.0, 18775.0, 88], 7 | ["2014-01-01", 18775.0, 18780.0, 18770.0, 18780.0, 224], 8 | ["2014-01-01", 18780.0, 18785.0, 18775.0, 18785.0, 294], 9 | ["2014-01-01", 18785.0, 18790.0, 18780.0, 18780.0, 422], 10 | ["2014-01-01", 18780.0, 18785.0, 18775.0, 18775.0, 376], 11 | ["2014-01-01", 18775.0, 18780.0, 18775.0, 18775.0, 118], 12 | ["2014-01-01", 18775.0, 18780.0, 18775.0, 18780.0, 24], 13 | ["2014-01-01", 18780.0, 18780.0, 18765.0, 18770.0, 442], 14 | ["2014-01-01", 18770.0, 18770.0, 18760.0, 18760.0, 360], 15 | ["2014-01-01", 18760.0, 18765.0, 18760.0, 18760.0, 484], 16 | ["2014-01-01", 18760.0, 18760.0, 18750.0, 18755.0, 498], 17 | ["2014-01-01", 18750.0, 18755.0, 18750.0, 18755.0, 352], 18 | ["2014-01-01", 18755.0, 18760.0, 18750.0, 18755.0, 342], 19 | ["2014-01-01", 18755.0, 18760.0, 18750.0, 18750.0, 128], 20 | ["2014-01-01", 18750.0, 18750.0, 18745.0, 18750.0, 424], 21 | ["2014-01-01", 18750.0, 18755.0, 18745.0, 18750.0, 256], 22 | ["2014-01-01", 18750.0, 18770.0, 18750.0, 18770.0, 750], 23 | ["2014-01-01", 18770.0, 18770.0, 18765.0, 18770.0, 84], 24 | ["2014-01-01", 18770.0, 18770.0, 18760.0, 18760.0, 154], 25 | ["2014-01-01", 18760.0, 18765.0, 18760.0, 18765.0, 26] 26 | ]} --------------------------------------------------------------------------------