量化学习中的一点编程体会

在我的 19 年的年度学习计划中,量化交易是其中的一项大的工程,是自己下定决心要攻克的一个难题。应该说 19 年是我的量化学习年,为了强化自己的决定,我付费在年初参加了邢不行的量化学习课程,到现在已经过了一个多月,自己从没有摸过 python , 到能用 python 编写简单的量化程序。除了认真学习课程外,也下了很大的功夫和精力。

我的第一个布林策略也已经运行了一段时间了,程序的改进也一直在进行。从测试的情况看,效果应该还不错。

在改进程序的过程中,我对最初的量化程序进行了重构,尽量将量化策略和相关的交易所代码分离。这样一个量化策略写完,只要适配一下交易所的代码,就可以在另外的交易所上运行了。

在编程的过程中,对于一些常见问题的解决方法,有了一些体会。我把它写下来。

  • 程序运行的参数全部使用配置文件,这样运行程序时,使用不同的配置文件就可以了。
oscardeMacBook-Pro:oscbot oscar$ ./okex_boll.py 
Usage: okex_boll.py -c 策略配置文件 
okex 布林线策略
okex_boll.py: error: 请指定策略配置文件!

我的主程序代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-

from bots.adaptation.trend_okex import TrendOkex
from bots.exchanges.okex_level import OkexLevel
from bots.algo.boll import BollAlgo
from bots.util.log import config_log
from bots.util.util import check_network, get_config
import logging

from optparse import OptionParser

parser = OptionParser(usage="%prog -c 策略配置文件 \nokex 布林线策略\n")

parser.add_option("-c", "--configfile",
                  action="store",
                  type='string',
                  dest="configfile",
                  help="指定策略运行配置文件"
                  )

(options, args) = parser.parse_args()

if not options.configfile:
    parser.error('请指定策略配置文件!')

options = get_config(options.configfile)

config_log(options['name'], options['log'])

if not check_network():
    print('网络错误,无法连接 google.com 请先检查网络或设置代理')
    exit(1)

logging.info('use config:%s', options['algo'])

ok = OkexLevel(options['algo']['trade'], options['algo']['base'], auths=options['api'])

tokex = TrendOkex(ok)

boll_algo = BollAlgo(tokex, para=[options['algo']['n'], options['algo']['m']], name=options['name'],
                     interval=options['algo']['interval'])

boll_algo.run()

我把所有策略的配置文件放在程序的 configs 目录下,运行产生的 log ,放在 logs 目录下。

配置文件示例:

{
  "name": "okex_boll",
  "log": "./logs/okex_boll.log",
  "algo": {
    "trade": "eth",
    "base": "usdt",
    "interval": 30,
    "n": 200,
    "m": 2
  },
  "api": {
    "name": "okex",
    "key": "**************",
    "secret": "******************",
    "pass": "***********"
  }
}

上面的布林参数我已经改过了,请不要照抄使用!

  • 程序运行的 log 是非常重要的,在程序有问题的时候,我们需要它来查找 bug.

以下是配置 log 的代码

def config_log(name='oscbot',logfile=''):
    """
    设置 log 
    :param name:
    :return:
    """
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)  # Log等级总开关

    logger.name = name

    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")

    # log to console
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    console.setFormatter(formatter)
    logger.addHandler(console)

    # log to file
    if logfile == '':
        logfile = './' + name + '.log'
    fh = logging.FileHandler(logfile, mode='a')
    fh.setLevel(logging.INFO)  # 输出到file的log等级的开关
    fh.setFormatter(formatter)
    logger.addHandler(fh)

    # log to 钉钉
    config = json_config('config.json')
    dd = DingDing(robot_id=config['dingding']['robot_id'])
    formatter = logging.Formatter('%(name)s - %(message)s')
    dd.setFormatter(formatter)
    logger.addHandler(dd)
  • 在写交易所的代码过程中,下单取帐户数据要考虑失败重试,我使用 tenacity 库使得这部分的代码不会太繁琐。
from tenacity import retry, wait_exponential, stop_after_attempt
    @retry(wait=wait_exponential(multiplier=1, max=10), reraise=True, stop=stop_after_attempt(6))
    def get_kicker(self):
        try:
            return self.spotAPI.get_specific_ticker(self.instrument_id)
        except Exception as e:
            logging.error('取末成交订单失败:%s', e, extra={'dingding': True})
            logging.error(e, exc_info=True)
            raise e

需要了解的话,可以搜索一下它的用法。

  • 为了加快速度,很多情况下从交易所取得的数据,可以缓存下来,供以后使用。所以我在代码中使用了 lru_cache
from functools import lru_cache

@lru_cache(maxsize=32)
@retry(wait=wait_exponential(multiplier=1, max=10), reraise=True, stop=stop_after_attempt(6))
def level_config_info(api,instrument_id):
    try:
        return api.get_specific_config_info(instrument_id)
    except Exception as e:
        logging.warning('取杠杆配置信息报错:%s', e, extra={'dingding': True})
        logging.error(e, exc_info=True)
        raise e

# 杠杆配置信息
def level_info(self,refresh=False):
        if refresh:
            level_config_info.cache_clear()
        return level_config_info(self.levelAPI,self.instrument_id)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352