ricequant / rqalpha

A extendable, replaceable Python algorithmic backtest && trading framework supporting multiple securities
http://rqalpha.io
Other
5.39k stars 1.62k forks source link

运行策略方式的讨论 #110

Closed cliff007 closed 7 years ago

cliff007 commented 7 years ago

rsi.py :

from rqalpha.api import *

import talib

# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
def init(context):

    # 选择我们感兴趣的股票
    context.s1 = "000001.XSHE"
    context.s2 = "601988.XSHG"
    context.s3 = "000068.XSHE"
    context.stocks = [context.s1, context.s2, context.s3]

    context.TIME_PERIOD = 14
    context.HIGH_RSI = 85
    context.LOW_RSI = 30
    context.ORDER_PERCENT = 0.3
    print(context)

# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
    # 开始编写你的主要的算法逻辑

    # bar_dict[order_book_id] 可以拿到某个证券的bar信息
    # context.portfolio 可以拿到现在的投资组合状态信息

    # 使用order_shares(id_or_ins, amount)方法进行落单

    # TODO: 开始编写你的算法吧!
    # print(context.stocks)

    # 对我们选中的股票集合进行loop,运算每一只股票的RSI数值
    for stock in context.stocks:
        # 读取历史数据
        prices = history_bars(stock, context.TIME_PERIOD+1, '1d', 'close')

        # 用Talib计算RSI值
        rsi_data = talib.RSI(prices, timeperiod=context.TIME_PERIOD)[-1]

        cur_position = context.portfolio.positions[stock].quantity
        # 用剩余现金的30%来购买新的股票
        target_available_cash = context.portfolio.cash * context.ORDER_PERCENT

        # 当RSI大于设置的上限阀值,清仓该股票
        if rsi_data > context.HIGH_RSI and cur_position > 0:
            order_target_value(stock, 0)

        # 当RSI小于设置的下限阀值,用剩余cash的一定比例补仓该股
        if rsi_data < context.LOW_RSI:
            logger.info("target available cash caled: " + str(target_available_cash))
            # 如果剩余的现金不够一手 - 100shares,那么会被ricequant 的order management system reject掉
            order_value(stock, target_available_cash)

if __name__ == "__main__":
    from rqalpha import run

    config = {
        "base": {
            "strategy_file": "./rsi.py",
            "securities": ["stock"],
            "start_date": "2014-01-09",
            "end_date": "2016-01-01",
            "frequency": "1d",
            "stock_starting_cash": 100000,
            "benchmark": '000300.XSHG',
        },
        "extra": {
            "log_level": "error",
        },
        # 参见《8.API-参数配置 — rqalpha 2.1.pdf》page2里对Mod启动参数的说明
        "mod": {
            "sys_progress": {
                "enabled": True,
                "show": True,
            },
            "sys_simulation": {
                "commission_multiplier": 0.01,
                "matching_type": "next_bar",
            },
            # 以下设置回测结果的输出文件和是否plot结果
            "sys_analyser": {
                "output_file": "cliffresult.pkl",
                "report_save_path": "./",  # 指定路径,生成跟algo同名的文件夹,下面一些列csv, xlsx文件
                "plot": True,
            }
        },
    }

    run(config)
cliff007 commented 7 years ago

以上是完全copy样本策略里的rsi.py代码,只是在代码后面加上了if name == "main":开始的一段config和run(config),求测试python2.7下如何能跑成功

wh1100717 commented 7 years ago

我编辑了一下你的代码,是这个意思吗?

cliff007 commented 7 years ago

上面两部分代码合成在同一个文件里,不是分开的,我的问题是:

1、 alog的script(.py)文件里在注释或任何地方有中文字符出现的话(包括诸如print u"你好"之类的u开头的字符串),不能加入像 # -- coding: UTF-8 -- 之类的文件编码申明字符,否则会导致algo无法编译执行 2、 在alog的script(.py)文件里尝试用if name == "main" 来写config并run(config),还是败在了中文编码上,没法正确执行 3、 只能独立新建一个test.py文件来写config并run(config),在这个test.py文件里,可以有# -- coding: UTF-8 -- 这样的申明(这种做法下alog的script(.py)文件里是可以有中文字符注释的) 4、 但如果alog的script(.py)文件里是全英文的话(不出现任何中文字符),if name == "main" 来写config并run(config)是能正确执行的

cliff007 commented 7 years ago

zipline是传递函数 rqalpha是传递整个algo文件内容 这会导致后者对于algo文件的解析多出很多意外

wh1100717 commented 7 years ago

@cliff007 确实传递源码的这种方式有些情况下会出现一些问题,在策略开发阶段会有一些不方便,尤其是使用ipython notebook 的时候。

zipline 在 Ipython notebook 下使用确实比较方便, 这块后续会讨论出具体的方案以后会在该issue下贴出来,并且排期实现。

wh1100717 commented 7 years ago

@cliff007 zipline 有三种方式,Command-line interface, IPython Notebookrun_algorithm

RQAlpha 有两种方式,Command-lien interface代码中引入RQAlpha库的方式

经过讨论,提供如下运行策略的API:

# 以策略文件路径的方式来运行
run_file(strategy_file_path, config=None)

# 以策略源码的方式来运行
run_code(strategy_code, config=None)

# 以策略函数的方式来运行
run_func(**kwargs)

有了第三种方式,代码可以这么写:

from rqalpha.api import *

def init(context):
    context.s1 = "IF88"
    subscribe(context.s1)
    logger.info("Interested in: " + str(context.s1))

def handle_bar(context, bar_dict):
    buy_open(context.s1, 1)

# 这里可以使用 __config__ 也可以使用 config
__config__ = {
    "base": {
        "securities": "future",
        "start_date": "2015-01-09",
        "end_date": "2015-03-09",
        "frequency": "1d",
        "matching_type": "current_bar",
        "future_starting_cash": 1000000,
        "benchmark": None,
    },
    "extra": {
        "log_level": "error",
    },
    "mod": {
        "sys_progress": {
            "enabled": True,
            "show": True,
        },
    }
}

if __name__ == '__main__':
  from rqalpha import run_func
  run_func(**globals())
  # 当然,也可以显式指定参数
  run_func(init=init, handle_bar=handle_bar, before_trading=None, config=__config__)

然后 RQAlpha 自动获取传入的参数 init | handle_bar | __config__ | config 等变量,并运行程序

wh1100717 commented 7 years ago

@cliff007 http://rqalpha.io/zh_CN/latest/intro/run_algorithm.html