backtrader策略库:10万变成400万的比特币交易策略

完整backtrader技术教程见这里

本文介绍这篇文章 提出的一个比特币交易策略,回测显示能够使10万变成400万!

这个策略依赖的一个重要指标叫库存流量比(Stock-to-Flow,简称stf),这个指标量化了比特币的稀缺性。

stf = Stock/Flow

Stock是指现有的库存和储备,Flow是年产生产量。stf反应了按现有年生产量,需要生产多少年,才能生产出现有库存量。

策略的基本思想是当市场处于跌势(均线下跌)、且价格低估时(价格低于stf),若出现macd金叉,则买入,同时设置一个跟踪停损单保护自己,在出现过大回测时离开市场。

bitcoin.py
# ======================================================================================================================
# 导入必要的库
# ======================================================================================================================

import backtrader as bt
from datetime import datetime
from dateutil.relativedelta import relativedelta
import io
import pandas as pd
import requests

# ======================================================================================================================
# 配置数据
# ======================================================================================================================

# 设置Amberdata的API_KEY,以便从Amberdata下载行情数据
Amberdata_API_KEY = 'YOUR_API_KEY'

# 初始资金
icap = 100000

# 每次交易投入的仓位百分比
PercSize = 100

# 追踪停损百分比
PercTrail = 0.40

# 回测时段
start_date = "2015-01-20"
end_date = "2020-05-09"


# ======================================================================================================================
# 帮助类和函数 - 数据源
# ======================================================================================================================
# 定义一个新的pandas data feed,加入线 stf
class CustomPandas(bt.feeds.PandasData):
    # Add a 'stf' line to the inherited ones from the base class
    lines = ('stf',)
    # sft默认在dataframe的第8列
    params = (('stf', 8),)

# 调用 Amberdata 的 在线API
def amberdata(url, queryString, apiKey):
    try:
        headers = {'x-api-key': apiKey}
        response = requests.request("GET", url, headers=headers, params=queryString)
        return response.text
    except Exception as e:
        raise e

# 从 Amberdata获取日线行情数据
def amberdata_ohlcv(exchange, symbol, startDate, endDate):
    format = "%Y-%m-%dT%H:%M:%S"
    startTimestamp = datetime.strptime(startDate, '%Y-%m-%d')
    endTimestamp = datetime.strptime(endDate, '%Y-%m-%d')

    current = startTimestamp
    next = current
    fields = "timestamp,open,high,low,close,volume"
    payload = fields
    while (current < endTimestamp):
        next += relativedelta(years=1)
        if (next > endTimestamp):
            next = endTimestamp
        print('Retrieving OHLCV between', current, ' and ', next)
        result = amberdata(
            "https://web3api.io/api/v2/market/ohlcv/" + symbol + "/historical",
            {"exchange": exchange, "timeInterval": "days", "timeFormat": "iso", "format": "raw_csv", "fields": fields, "startDate": current.strftime(format), "endDate": next.strftime(format)},
            Amberdata_API_KEY
        )
        payload += "\n" + result
        current = next

    return payload

# 获取stf指标数据
def amberdata_stf(symbol, startDate, endDate):
    print('Retrieving STF between', startDate, ' and ', endDate)
    return amberdata(
        "https://web3api.io/api/v2/market/metrics/" + symbol + "/historical/stock-to-flow",
        {"format": "csv", "timeFrame": "day", "startDate": startDate, "endDate": endDate},
        Amberdata_API_KEY
    )

def to_pandas(csv):
    return pd.read_csv(io.StringIO(csv), index_col='timestamp', parse_dates=True)



# ======================================================================================================================
# 策略
# ======================================================================================================================

class Strategy(bt.Strategy):
    params = (
        ('macd1', 12),
        ('macd2', 26),
        ('macdsig', 9),
        ('trailpercent', PercTrail),
        ('smaperiod', 30),
        ('dirperiod', 10),
    )

    def notify_order(self, order):
        if order.status == order.Completed:
            pass

        if not order.alive():
            self.order = None  # No pending orders

    def __init__(self):
        self.macd = bt.indicators.MACD(self.data,
                                       period_me1=self.p.macd1,
                                       period_me2=self.p.macd2,
                                       period_signal=self.p.macdsig)

        # Cross of macd.macd and macd.signal
        self.mcross = bt.indicators.CrossOver(self.macd.macd, self.macd.signal)

        # 移动均线。
        self.sma = bt.indicators.SMA(self.data, period=self.p.smaperiod)
        # 当日移动均线与dirperiod期前移动均线的差值,若小于0,说明市场处于跌势
        self.smadir = self.sma - self.sma(-self.p.dirperiod)

    def start(self):
        self.order = None  

    def next(self):
        if self.order:
            return  

        if not self.position:  # 无仓位
            # 如果macd金叉,并且当日移动均值比dirperiod前的低,并且收盘价低于stf,则买入
            # 基本思想是当市场处于跌势、且价格低估时,若出现macd金叉,则买入
            if self.mcross[0] > 0.0 and self.smadir < 0.0 and self.data.close < self.data.stf:
                self.order = self.buy()
               
        # 若有仓位
        elif self.order is None: 
            # 发出停损跟踪单,保护自己
            self.order = self.sell(exectype=bt.Order.StopTrail,trailpercent=self.p.trailpercent)
           


# ======================================================================================================================
# 主程序开始
# ======================================================================================================================


cerebro = bt.Cerebro(stdstats=False)
cerebro.broker.setcash(icap)

# addsizer设置下单量管理者
cerebro.addsizer(bt.sizers.PercentSizer, percents=PercSize)

# Add our strategy
cerebro.addstrategy(Strategy)


# 通过amberdata api获取gdax交易所的比特币行情数据,放到dataframe
btc = to_pandas(amberdata_ohlcv("gdax", "btc_usd", start_date, end_date))
# 获取stf指标
btc_stf = to_pandas(amberdata_stf("btc", start_date, end_date))
# 将stf指标合并到行情数据帧
btc['stf'] = btc_stf['price']

# 注入数据
cerebro.adddata(CustomPandas(dataname=btc, openinterest=None, stf='stf'))



# 运行回测
backtest = cerebro.run()


# ======================================================================================================================

猜你喜欢

转载自blog.csdn.net/qtbgo/article/details/111195727