动态数字货币交易策略回测平台-python

区块链资讯区块链研究实验室2020-06-30 15:14:12  阅读 -评论 0

下面是一个交易环境,在这个环境中,所有可能的交易策略都可以以一种非常动态的方式进行测试,即使是初学者python程序员也可以创建和回溯测试自己的交易想法,并最终解决他们的疑问。使用环境并实现您自己的想法的唯一先决条件是:对python结构(如for循环和if语句)有基本的了解,对pandas有足够的了解,以便从dataframe的正确列/索引位置获取适当的价格dataframe,可能对面向对象编程有较低层次的理解,这取决于您的策略的复杂性。
收集数据
首先读取数据。在此脚本中,我们使用了binance API,该API允许从交易所中列出的各种加密货币中收集数据。给出的示例是一个单独的脚本,从2019年3月28日到2020年6月1日,读取12种不同加密货币的每种加密货币的价格变化,总共618290个实例的价格,从而产生211 MB的dataframe。在我的机器上,这个从binance API读取的过程大约需要5个小时才能完成,但是通过一个简单的csv写操作,在以后使用脚本时几乎可以立即检索到。
关于数据读取的一些值得注意的事情:
1. 要访问binance API,只需从命令行pip install binance client。其他依赖项安装在其各自的导入行上注释。
2. binance客户端请求API密钥时,这些密钥仅对于将交易订单实时发送到币安交易所是必需的,而对于读取数据则不是必需的。我保留了格式,以防这是任何读者所期望的用例。
3. 在收集了每个代币的数据之后,我们需要让脚本停止运行60秒。这是为了防止binance API因为我们请求太多的数据而把我们踢出去。我目前没有遇到过这种问题,但如果遇到错误,这个时间可能需要增加。
4. 这里包括一个简单的移动平均函数,它展示了如何从价格数据中设计特性并将其添加到dataframe中的示例。这可以是您选择的自定义函数,也可以只是一个在网上找到的通用指示器的函数,如图所示。
5. 卷数据也可用,但在本例中未使用。如果您感兴趣,请将其添加到第32行。
6. csv文件的自定义命名可以在第72行的引号中编辑。
import numpy as np #pip install numpy
from tqdm import tqdm #pip install tqdm
from binance.client import Client #pip install python-binance
import pandas as pd #pip install pandas
from datetime import datetime
import random
SMA_LOW = 40
SMA_HIGH = 150
def compute_sma(data, window):
    sma = data.rolling(window=window).mean()
    return sma
#select cryptocurrencies you'd like to gather and time interval
ratios = ['BTC','ETH','LTC','XLM','XRP','XMR','TRX','LINK','IOTA','EOS','DASH','ZRX']
START_TIME = '28 Mar, 2019'
END_TIME = '1 Jun, 2020'
api_key=''
api_secret=''
client = Client(api_key=api_key,api_secret=api_secret)
merge = False
for ratio in ratios:
    print(f'Gathering {ratio} data...')
    data = client.get_historical_klines(symbol=f'{ratio}USDT',interval=Client.KLINE_INTERVAL_1MINUTE,start_str=START_TIME,end_str=END_TIME)
    cols = ['time','Open','High','Low',f'{ratio}-USD_close',f'{ratio}-USD_volume','CloseTime','QuoteAssetVolume','NumberOfTrades','TBBAV','TBQAV','null']
    temp_df = pd.DataFrame(data,columns=cols)
    temp_df = temp_df[['time',f'{ratio}-USD_close']]
    if merge == False:
        df = temp_df
    else:
        df = pd.merge(df,temp_df,how='inner',on='time')
    merge = True
    print('complete')
    time.sleep(60) #sleep for a bit so the binance api doesn't kick you out for too many data asks
for col in df.columns:
    if col != 'time':
        df[col] = df[col].astype(np.float64)
for ratio in ratios:
    df[f'{ratio}_{SMA_LOW}'] = compute_sma(df[f'{ratio}-USD_close'], SMA_LOW)
    df[f'{ratio}_{SMA_HIGH}'] = compute_sma(df[f'{ratio}-USD_close'], SMA_HIGH)
#clip NaNs
df = df[SMA_HIGH:]
df = df.reset_index(drop=True)
#convert binance timestamp to datetime
for i in tqdm(range(len(df))):
    df['time'][i] = datetime.fromtimestamp(int(df['time'][i]/1000))

df.to_csv('12-coins-Mar18_Jun20')

太好了,现在我们有了一个庞大的加密货币价格数据集。在进入交易环境之前,让我们创建一个简单的memory 类,这样我们可以存储关于每个回测事件的信息。
Memory
class Memory:
    def __init__(self): 
        self.clear()
    def clear(self): 
        self.actions = []
    def add_to_memory(self, new_action): 
        self.actions.append(new_action)
这个类很容易解释;它就是一个简单的Memory对象,它允许我们附加购买/出售操作,还可以在每周期之后清除Memory。
在我们有了数据和Memory对象,让我们开始进入交易环境。
我们的环境采用两个参数:我们刚刚创建的dataframe以及您希望在回溯测试过程中包含的货币比率(例如“BTC”、“LTC”等)。
我们的环境还有另两个方法:reset()和step()。
这是另一个无需过多解释的项目:它只是将交易环境重置为其默认状态。这样做的目的是在运行多个周期的回测时,我们将在每个周期之后调用env.reset()来重置所有局部变量,例如代币余额,周期dataframe的索引位置 跟踪您的特定策略以及可能对日志记录有用的任何其他信息。环境的默认状态是USD余额为1.0,每种加密货币的余额为0.0。有关reset()方法的一些重要注意事项:
请注意,每次重置都会占用主要dataframe的一小部分,并将其称为“ episode_df”,而不是在回测期间遍历整个600,000多个数据实例。这是该策略将针对每个周期进行回测的时间间隔。可以使用常量MINUTES_PER_EPISODE或DAYS_PER_EPISODE来指定此周期dataframe的持续时间。在此示例中,我们使用1天或1440分钟的周期大小。
在启动环境时(在__init__中),将调用reset()方法。这将在第一次调用Env对象时设置所有环境变量。
Env.step()方法
我将这种方法分为两部分:实施交易策略和计算效果指标。
策略
在此示例中,我没有使用更深入的技术分析讨论中可能遇到的更复杂的交易策略,而是要尝试我们在网上看到的一种常见策略的有效性:移动平均线交叉策略。如果你不熟悉,这个想法的要点是,当一个短窗口移动平均线越过一个较长的窗口移动平均线时→买入;当短窗口移动平均线回到较长窗口移动平均线以下时→卖出。
现在,我不确定是否有人相信这个策略真的有效(在某些情况下可能是这样),但是为了演示回溯测试环境(并且因为实现更复杂的策略将从修改您自己的想法中去除一些乐趣),让我们考虑一下。如下面的代码所示,我们有两个关键的if语句,这些语句检查移动平均线变化并决定是否记录买入或卖出(或都不记录)。需要熟悉的几个局部变量:money_in和to_buy。这些是字符串变量,用于跟踪您当前持有的资金以及购买开始时资金的去向。输入买入和卖出if语句后,这些变量将相应更新;因此,余额会根据您当前持有的价格进行更新。请注意,每次买卖都将相应的余额乘以TRADING_FEE_MULTIPLIER,在这种情况下为0.99925。该值基于使用BNB令牌(币安交易所可用的最便宜的选择)支付费用时的0.075%币安交易费用,但可以根据您特定交易所的交易费用进行更改。
性能指标
我们将使用两个指标来评估策略在回测间隔内的结果:回测间隔后的资产净值和回测间隔的平均市场变化。您的余额净值是根据您持有的货币的当前价格和您所持货币的金额将您持有的资产转换为美元来计算的。区间的平均市场变化是通过计算事件开始和结束时所有选定货币的价格平均值,然后将这些值相除得出的。基于这些指标,最终目标是以比拥有平均市场份额时要高的净资产来完成本集(显然要比开始时拥有的净资产高)。
DAYS_PER_EPISODE = 1
MINUTES_PER_EPISODE = 1440*DAYS_PER_EPISODE
NUM_EPISODES = 100
TRADING_FEE_MULTIPLIER = .99925 #this is the trading fee on binance VIP level 0 if using BNB to pay fees
class Env:
    def __init__(self, ratios, df):
        self.ratios = ratios
        self.main_df = df
        self.reset()
    def reset(self):
        self.balances = {'USD':1.0}
        for ratio in self.ratios:
            self.balances[ratio] = 0.0
        self.iloc = random.randint(0,len(self.main_df)-MINUTES_PER_EPISODE-1)
        self.episode_df = self.main_df[self.iloc:self.iloc+MINUTES_PER_EPISODE+2]
        self.money_in = 'USD'
        self.start_time = self.episode_df['time'].iloc[0]
        self.end_time = self.episode_df['time'].iloc[-1]
    def step(self):
        self.iloc+=1
        #-------IMPLEMENT STRATEGY HERE--------
        if self.money_in == 'USD':
            for ratio in self.ratios:
                #if low sma crosses above high sma
                if self.episode_df[f'{ratio}_{SMA_LOW}'][self.iloc] > self.episode_df[f'{ratio}_{SMA_HIGH}'][self.iloc] and self.episode_df[f'{ratio}_{SMA_LOW}'][self.iloc-1] > self.episode_df[f'{ratio}_{SMA_HIGH}'][self.iloc-1]:
                    self.to_buy = ratio
                    #buy that ratio (self.to_buy)
                    self.balances[self.to_buy] = (self.balances['USD']/self.episode_df[f'{self.to_buy}-USD_close'][self.iloc])*TRADING_FEE_MULTIPLIER
                    self.balances['USD'] = 0.0
                    self.buy_price = self.episode_df[f'{self.to_buy}-USD_close'][self.iloc]
                    memory.add_to_memory(f'Buy {self.to_buy}: {self.buy_price}')
                    self.money_in = self.to_buy
                    break
        if self.money_in != 'USD': #can't sell if money_in usd
            if self.episode_df[f'{self.money_in}_{SMA_LOW}'][self.iloc] < self.episode_df[f'{self.money_in}_{SMA_HIGH}'][self.iloc]:
                #if high sma crosses below low sma
                #sell money_in/USD
                self.balances['USD'] = (self.balances[self.money_in]*self.episode_df[f'{self.money_in}-USD_close'][self.iloc])*TRADING_FEE_MULTIPLIER
                self.balances[self.money_in] = 0.0
                self.sell_price = self.episode_df[f'{self.money_in}-USD_close'][self.iloc]
                memory.add_to_memory(f'Sell {self.money_in}: {self.sell_price}')
                self.money_in = 'USD'
        #-------IMPLEMENT STRATEGY HERE--------
        #-------CALCULATE PERFORMANCE METRICS HERE-------
        #Running net worth
        self.net_worth = self.balances['USD']
        for ratio in self.ratios: 
            self.net_worth += self.balances[ratio]*self.episode_df[f'{ratio}-USD_close'][self.iloc]
        #Net_worth had you owned all ratios over episode_df --> 'average_market_change'
        self.average_start_price = 0
        self.average_end_price = 0
        for ratio in self.ratios:
            self.average_start_price += self.episode_df[f'{ratio}-USD_close'].iloc[0]
            self.average_end_price += self.episode_df[f'{ratio}-USD_close'].iloc[-1]
        self.average_start_price /= len(ratios)
        self.average_end_price /= len(ratios)
        self.average_market_change = self.average_start_price / self.average_end_price
        #-------CALCULATE PERFORMANCE METRICS HERE-------
        return self.net_worth, self.average_market_change, self.start_time, self.end_time
执行环境
在这里,我们一次一分钟地遍历环境,按照策略的指示进行买卖,并跟踪性能指标以及将其输出到日志的过程。
df = pd.read_csv('12-coins-Mar18_Jun20')
env = Env(ratios, df)
memory = Memory()
net_worth_collect = []
average_market_change_collect = []
for i_episode in range(NUM_EPISODES):
    for i in range(len(env.episode_df)-1):
        net_worth, average_market_change, start_time, end_time = env.step()
    net_worth_collect.append(net_worth)
    average_market_change_collect.append(average_market_change)
    #log after each episode
    print(f'episode: {i_episode}')
    print(memory.actions)
    print('\n')
    print(f'interval: {start_time} - {end_time}')
    print(f'net worth after {DAYS_PER_EPISODE} day(s): {net_worth}')
    print(f'average market change: {average_market_change}')
    print('\n')
    memory.clear()
    env.reset()
#log overall
print(f'net worth average after {NUM_EPISODES} backtest episodes: {np.mean(net_worth_collect)}')
#Yes, average of the average market changes
print(f'average, average market change over {NUM_EPISODES} episodes: {np.mean(average_market_change_collect)}')
我们做得怎么样?
好吧,正如之前预测的那样,由于策略比较简单,效果不是很好。如图所示,我们预计该策略的实施将导致在平均每天增长0.2%的市场中,平均每天净值下降4%(哎呀)。但是,除此之外日志中还显示,一个快速、动态且易于阅读的策略输出,该策略在2019年3月至2020年6月期间随机选择了100多个1天的时间间隔进行了回溯测试,并提供了每笔交易的买入/卖出信息。现在你的问题有了一些答案!
episode: 96
['Buy BTC: 5255.99', 'Sell BTC: 5227.76', 'Buy ETH: 155.86', 'Sell ETH: 155.41', 'Buy LTC: 67.46', 'Sell LTC: 67.45', 'Buy IOTA: 0.3167', 'Sell IOTA: 0.3176', 'Buy IOTA: 0.3167', 'Sell IOTA: 0.3151', 'Buy LTC: 67.67', 'Sell LTC: 67.42', 'Buy XMR: 61.38', 'Sell XMR: 61.59', 'Buy EOS: 4.5225', 'Sell EOS: 4.5076', 'Buy ZRX: 0.2743', 'Sell ZRX: 0.2723', 'Buy ETH: 155.2', 'Sell ETH: 156.98', 'Buy XLM: 0.09605', 'Sell XLM: 0.09597', 'Buy LINK: 0.439', 'Sell LINK: 0.439', 'Buy LINK: 0.4418', 'Sell LINK: 0.4672', 'Buy BTC: 5308.08', 'Sell BTC: 5304.94', 'Buy XLM: 0.09966', 'Sell XLM: 0.09965', 'Buy XMR: 62.29', 'Sell XMR: 62.22', 'Buy TRX: 0.02312', 'Sell TRX: 0.02307', 'Buy LTC: 72.82']
interval: 2019-04-29 12:25:00 - 2019-04-30 12:26:00
net worth after 1 day(s): 1.0221672847272814
average market change: 0.988959335567251
episode: 99
['Buy XRP: 0.30917', 'Sell XRP: 0.31171', 'Buy BTC: 9641.57', 'Sell BTC: 9635.6', 'Buy TRX: 0.02252', 'Sell TRX: 0.02238', 'Buy XLM: 0.08462', 'Sell XLM: 0.08457', 'Buy LINK: 2.2158', 'Sell LINK: 2.211', 'Buy EOS: 4.2811', 'Sell EOS: 4.2527', 'Buy ETH: 212.07', 'Sell ETH: 211.26', 'Buy IOTA: 0.2835', 'Sell IOTA: 0.2833', 'Buy XLM: 0.08375', 'Sell XLM: 0.08317999999999999', 'Buy LTC: 89.2', 'Sell LTC: 89.34', 'Buy XMR: 79.39', 'Sell XMR: 79.15', 'Buy BTC: 9570.01', 'Sell BTC: 9548.48', 'Buy LINK: 2.1819', 'Sell LINK: 2.1595', 'Buy LTC: 89.33', 'Sell LTC: 89.4', 'Buy EOS: 4.1803', 'Sell EOS: 4.1903', 'Buy BTC: 9540.07', 'Sell BTC: 9559.46', 'Buy ETH: 210.83', 'Sell ETH: 208.78', 'Buy LTC: 90.68', 'Sell LTC: 90.39', 'Buy LTC: 90.76', 'Sell LTC: 90.44', 'Buy XRP: 0.31008', 'Sell XRP: 0.30991', 'Buy BTC: 9504.64', 'Sell BTC: 9490.15', 'Buy ETH: 209.7', 'Sell ETH: 209.77', 'Buy IOTA: 0.2853']
interval: 2019-07-28 16:39:00 - 2019-07-29 16:40:00
net worth after 1 day(s): 0.9218801235080804
average market change: 0.9984598063740531
net worth average after 100 backtest episodes: 0.9656146271760888
average, average market change over 100 episodes: 1.0021440510159623
显示的是100集中仅有两期间的输出。为了简洁起见,我选择了一个有利可图的期间(96个)和一个不赚钱的期间(99个)来显示,而实际输出显示所有100期间的结果。不过我们真正关心的不是单个事件的结果,而是问题:“我的策略平均表现如何?”. 这将显示在最终平均事件日志中。
python日志记录包在这里对于运行许多不同策略并登录到单独文件以比较结果的人可能有用。
最终显示日交易是具有非常大的风险。我希望阅读此文的人会发现此工具有助于探索他们的交易思路,使他们能够在将其策略推向市场之前能自己对决策进行探索。对编程和算法交易知识有限的人来说,似乎缺乏资源来做出明智的交易决策;
其他一些想法
在我看来,使用我们在这个例子中的环境是一个很好的方法,可以将动态算法交易介绍给像我以前一样(也许现在还是我现在的自己)对面向对象编程知识有限的人。就我个人而言,我使用这个工具来回溯测试许多不同的策略,这些策略包含了价格数据的更多特性,还允许一些附加功能;即能够将加密货币交易(例如BTC/LTC对等),而不仅仅是加密货币对美元,反之亦然。

声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们kefu@lianshijie.com

    参与讨论 (0 人参与讨论)

    相关推荐

    中信银行打造“区块链”信用证结算!

    中信银行打造“区块链”信用证结算!

    科技不会改变金融的实质,但却能让金融服务更高效,能让资金供、需方信息不对称的问题更好地解决。近期,中信银行首个区块链项目——基于区块链的国内信用证信息传输系统(简称BCLC)(一期)成功上线,这是国内银行业第一次将区块链技术应用于信用证结算领域。 据中信银行国际业务部总经理助理张栩青介绍,将现在流行的区块链技术应用在国内信用证中,改变了银行传统信用证业务模式,信用证的开立、通知、交单、承兑报文

    中国信息技术部门成立区块链研究实验室

    中国信息技术部门成立区块链研究实验室

    暴走时评:本月初,中国政府对国内的ICO和数字货币交易所的打击在世界范围内引起了强大反响,但政府已经多次声明不会将区块链与数字货币划等号,依然非常重视区块链技术在中国的发展。鉴于中国工业和信息化部成立了一个专门研究区块链的实验室,这一论调也得到了进一步的证实。 虽然中国政府最近在大力打击比特币交易所和ICO,但仍然致力于开发区块链在其他领域的潜力。 据财新网报道,中国工业和信息化部已经成立了一

     分布式账本中的生命科学

    分布式账本中的生命科学

    生物科学是医学领域涉及遗传研究,疾病预防和生活方式治疗(lifestyle treatments)的学科。它已经存在了很长时间,但区块链技术的基础设施应用给该学科提供了重大进步的可能性。 根据Pistoia Alliance进行的2016年6月份高级制药和生命科学领袖调查,83%的受访者表示,他们预计在五年内将全面采用区块链技术。 Pistoia Alliance是一个全球性的非营利组织,致

    区块链vs.核能:日本最大电力公司东京电力(TEPCO)寻求使用区块链减轻对核电的依赖

    区块链vs.核能:日本最大电力公司东京电力(TEPCO)寻求使用区块链减轻对核电的依赖

    东京电力公司 (TEPCO) 对于能源过度中心化的风险可以说绝不陌生。 也许最著名的就是2011年发生的福岛核电站事故,这个日本最大的能源公司如今正在寻求区块链技术来防止这种灾难再次发生。 然而,从使用微型风车的分布式风力发电到用于存储在电力成本低时购买的电力的智能电池,可替代能源项目一直以来都属于个人慈善事业。 然而,TEPCO风险投资部门主管Jeffrey Char认为区块链能够帮助为这

    继证监会发表代币发行声明之后,香港交易所Gatecoin将下线部分ICO币

    继证监会发表代币发行声明之后,香港交易所Gatecoin将下线部分ICO币

    经过一系列监管以及合规审查后,香港交易所Gatecoin将会下线那些被金融监管部门定性为"证券"的代币。 香港加密货币交易所Gatecoin透露,如果在该平台交易的ICO代币在法律上符合"证券"定义,他们就会下线这些代币。据巴比特上月报道,香港主要的金融监管部门证券及期货事务监察委员会(SFC)表达了对ICO这种日渐普及的募资模式的担忧。 尽管ICO中售卖的数字代币通常都被定义为虚拟商品,但

    IBM与超级账本共同加入去中心化身份基金会(DIF),推动创建区块链ID行业标准

    IBM与超级账本共同加入去中心化身份基金会(DIF),推动创建区块链ID行业标准

    IBM与超级账本已经签署协议加入去中心化身份基金会(DIF),这个于今年初成立的联盟旨在帮助推动基于区块链的ID系统的互操作性和标准。 这两个企业区块链大佬加入了这个有各种企业组成的团体,其中包括像微软和埃森哲这样的大企业,还有像Civic和Gem这样的创业公司,以及像uPort和Sovrin这样的开源项目。 DIF执行主管告诉Coindesk说: "这应该是一个信号,表明在这一领域有广泛的

    为打击人口贩卖,牙买加警方盯上了犯罪分子的比特币钱包

    为打击人口贩卖,牙买加警方盯上了犯罪分子的比特币钱包

    作为打击人口贩卖计划的一部分,牙买加警方已经开始行动,锁定了那些试图用比特币和数字支付来掩人耳目的犯罪分子。 越来越多的人口贩卖者都开始转向数字货币来帮助他们进行地下活动并接收非法活动所得,但牙买加警方已经盯上他们了。 牙买加的'大生意' 不幸的是,人口贩卖以及性奴市场规模十分庞大,预计涉资1500亿美元。在牙买加,大约有7000个妇女、儿童以及成年男性被奴役,他们的操控者出售奴役服务的价格

    深圳市将发布《深圳市扶持金融业发展若干措施》,奖励区块链、数字货币等金融创新

    10月9日,深圳市人民政府向各区人民政府,市政府直属各单位印发《深圳市扶持金融业发展若干措施》(以下简称"《若干措施》")。深圳市政府表示,此举是为进一步完善金融支持政策体系,吸引集聚优质金融资源,推动全市金融业可持续均衡发展,加快建设国际化金融创新中心。 《若干措施》共分五大项,33条。内容包括:坚持服务导向,优化金融政策环境;发展金融总部经济,鼓励金融总部企业做大做强;支持金融企业分支机构

    麦妖榜
    更新日期 2019-09-03
    排名用户贡献值
    1牛市来了30910
    2BitettFan24187
    3等待的宿命23810
    4区块大康20369
    5六叶树20310
    6linjm122719429
    7天下无双16192
    8lizhen00215280
    9让时间淡忘14586
    10yelanyi050511349
    返回顶部 ↑