backtrader的策略模板,结合“积木式”的策略模块(全系统代码下载)。

关于backtrader的api,backtrader里的文档,最先讲的概念是如何读数,就是line的概念。0表示当前的数据,-1表示前一个bar的数据,依此类推,当然这种取法,在机器学习,或者风险平价的场景里会很麻烦,我们可能需要去过去半年的所有数据,来计算权重。机器学习里可能有几百个因子,因为我们没有使用backtrader的指标体系。

我们主要关心Strategy提供的api:

buy, sell, close,cancel, get_position,这四个函数比较简单,就是买、卖、平仓和取消订单,返回当前持仓,基本的功能好理解。

order_target_size, 到指定股数。

order_target_value, 到指定市值。

order_target_percent,到指定比例(仓位)。

我们做多资产组合,轮动,用得最多的就是这个order_target_percent。比如我们的WeightEqually,

等权分配,那么就是order_garget_percent(1/N)。

这些函数的key都是data,与我们传统的回测使用symbol不同。当然它提供了name和data的映射。

getdatabyname(name), 这里的name,一般我们在add_data的时候,就使用的symbol,这就对应上了。

其实一个策略这些交易函数就够了,其余写策略就是计算因子,判断规则或者使用机器学习来建模。

图片

这是星球群里的一个讨论,挺有意思,我的回复。其实backtrader也好,或者未来再出现一个更好的引擎,我们要更换起来都很容易。

图片

星球合伙人计划:感兴趣的同学,请星球私信我。

吾日三省吾身

关于人脉,拉长周期看本质就是价值交换。

类比投资来看,你的实力,你的底牌就是人际交往的基本面

但不意味着,你就不需要朋友,关键时候不需要别人帮你说句话。有时候,有这么一句话,会带来很多事情的转折。

一个好汉三个帮。

首先,绝对实力无敌的人少数,多数人最多算是一个努力,上进的普通人罢了。有一些成绩,担任一些职务

这时候,你会结识差不多圈层的一群人。

吃饭,喝点小酒,聊聊天,拉拉加常,顺便看看有没有合作的机会,这里的机会也是互惠互利,占便宜的买卖通常都是持久。

但仅此而已。

其实每个人的能量都与你的实力相差无几。

帮忙引荐一个人,敲个门,带个话,举手之劳尚可,其余不要抱太高期望。

黑帮系列动作片里,结局大高潮,一般是黑老大亲自出马,然后被一锅端,电影结束。之前我有点想不明白,这种级别的大佬还用自己亲自出马?其实还是风险收益的问题,多大的收益,就会带来多大的诱惑,挑战人性的底线,得多有信任的人,才能“替”他做这么重要的事情,冒这么大的风险,基本没有。因此,电影符合人性之逻辑。

发现人品不好的人,远离之,尽量划清界限,勿与之纠缠为宜

解析一下我们支持Backtrader引擎的策略代码:

核心代码继承自bt.Strategy,这是与backtrader内核交互的基础代码。

nofify_order, notify_trade可以打印订单、交易等信息。

在next函数里执algo_list。

我们的框架基本上实现与底层内核解耦,底层换成pybroker或者bt都是比较容易的事情。

图片

下面是backtrader的策略模板,这个模板是可以复用的,网上很多代码把这块贴了一遍又一遍,其实与真正的策略逻辑没多大关系。

我们的系统,没有使用backtrader的指标体系,数据都是使用我们的“因子表达式”来计算的。因此,与引擎的耦合很小。

我们仅使用backtrader的下单函数,比如buy, sell, order_target_percent这样的调仓,交易函数。

另外还会读取backtrader的持仓情况等。

import backtrader as bt
import pandas as pd
from loguru import logger


class StrategyBase(bt.Strategy):
    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        logger.info('%s, %s' % (dt.isoformat(), txt))

    # 取当前的日期
    def get_current_dt(self):
        #print(self.datas[0].datetime)
        dt = self.datas[0].datetime.date(0).strftime('%Y-%m-%d')
        #print(dt)
        return dt

    # 取当前持仓的data列表
    def get_current_holding_datas(self):
        holdings = []
        for data in self.datas:
            if self.getposition(data).size > 0:
                holdings.append(data)
        return holdings

    # 打印订单日志
    def notify_order(self, order):

        order_status = ['Created', 'Submitted', 'Accepted', 'Partial',
                        'Completed', 'Canceled', 'Expired', 'Margin', 'Rejected']
        # 未被处理的订单
        if order.status in [order.Submitted, order.Accepted]:
            return
            self.log('未处理订单:订单号:%.0f, 标的: %s, 状态状态: %s' % (order.ref,
                                                           order.data._name,
                                                           order_status[order.status]))
            return
        # 已经处理的订单
        if order.status in [order.Partial, order.Completed]:

            if order.isbuy():
                self.log(
                    'BUY EXECUTED, 状态: %s, 订单号:%.0f, 标的: %s, 数量: %.2f, 价格: %.2f, 成本: %.2f, 手续费 %.2f' %
                    (order_status[order.status],  # 订单状态
                     order.ref,  # 订单编号
                     order.data._name,  # 股票名称
                     order.executed.size,  # 成交量
                     order.executed.price,  # 成交价
                     order.executed.value,  # 成交额
                     order.executed.comm))  # 佣金
            else:  # Sell
                self.log(
                    'SELL EXECUTED, status: %s, ref:%.0f, name: %s, Size: %.2f, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order_status[order.status],
                     order.ref,
                     order.data._name,
                     order.executed.size,
                     order.executed.price,
                     order.executed.value,
                     order.executed.comm))

        elif order.status in [order.Canceled, order.Margin, order.Rejected, order.Expired]:
            # order.Margin资金不足,订单无法成交
            # 订单未完成
            self.log('未完成订单,订单号:%.0f, 标的 : %s, 订单状态: %s' % (
                order.ref, order.data._name, order_status[order.status]))

        self.order = None

    def notify_trade(self, trade):
        logger.debug('trade......', trade.status)
        # 交易刚打开时
        if trade.justopened:
            self.log('开仓, 标的: %s, 股数: %.2f,价格: %.2f' % (
                trade.getdataname(), trade.size, trade.price))
        # 交易结束
        elif trade.isclosed:
            self.log('平仓, 标的: %s, 股数: %.2f,价格: %.2f, GROSS %.2f, NET %.2f, 手续费 %.2f' % (
                trade.getdataname(), trade.size, trade.price, trade.pnl, trade.pnlcomm, trade.commission))
        # 更新交易状态
        else:
            self.log('交易更新, 标的: %s, 仓位: %.2f,价格: %.2f' % (
                trade.getdataname(), trade.size, trade.price))


class StratgeyAlgo(StrategyBase):
    def __init__(self, algo_list, engine):
        self.algos = algo_list
        self.df_data = engine.df_data
        self.temp = {}
        self.perm = {}
        self.index = -1
        self.dates = list(self.df_data.index.unique())

    def next(self):
        self.index += 1
        self.now = self.dates[self.index]


        self.df_bar = self.df_data.loc[self.now]
        if type(self.df_bar) is pd.Series:
            self.df_bar = self.df_bar.to_frame().T
        self.df_bar.set_index('symbol', inplace=True)

        for algo in self.algos:
            if algo(self) is False:  # 如果algo返回False,直接不运行
                return

吾日三省吾身

“凡事发生必有利于我”。

适当的焦虑与担忧,会激发身体内的斗志,当然不能影响休息,更不能影响身心健康为宜。身边出现了不好的人与事那它一定是来提醒你,最近可能太“岁月静好”了,需要加快速度,加快脚步成长。

寻宝电影里,主人公背后总有一个坏人团队在“协助”推进剧情,制造紧张气氛。那应该怎么办呢?

正确的做法,集中力量,专注自己的成长。

小时候的经历令人印象深刻。农村的邻里关系极期复杂,而且流动性极低,几代人就生活在这方寸之间,看存量,这近乎无解。我的解法就是努力学习,离开小镇,“离开”这些“纯朴”的人们。后来安排父母也远离这些是非。反而,这些远房亲戚反倒由于距离显得亲密与尊重。偶尔回去,听他们聊聊事非,发现尽管物是人非,但是非还在,只是,作为看客。

把因归于内,把行动归于内,这才是我们可以掌控的事情。

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103888
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!

(0)
股市刺客的头像股市刺客
上一篇 2024 年 7 月 29 日
下一篇 2024 年 7 月 29 日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注