工欲利其事,必先利其器。在量化交易中,数据质量的高低直接决定了策略可不可靠。本章主要是为后续开发量化策略打下基础,并且给出两个策略代码,一个代码可以获取比特币3年内行情数据,一个可以获取10年以上的数据。
CCXT 库可用于世界各地的加密货币/山寨币交易所的连接和交易,以及转账支付处理服务。它提供了快速访问市场数据的途径,可用于存储数据,分析,可视化,指标开发,算法交易,策略回测,机器人程序,网上商店集成及其它相关的软件工程。
这个章节我们主要利用了ccxt中集成好的框架获取各个交易所的币种行情数据,保存到本地文件。
pip install ccxt
这块会有个bug,由于数字货币交易所都在国外,访问外网需要有一定条件(懂的都懂),需要在本地项目中设置代理。
# -*- coding: utf-8 -*-
# __file__name:binance-fetch-ohlcv-to-csv.py
import os
import time
import pandas as pd
os.environ["http_proxy"] = "http://127.0.0.1:1001"
os.environ["https_proxy"] = "http://127.0.0.1:1001"
# -----------------------------------------------------------------------------
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import ccxt # noqa: E402
# -----------------------------------------------------------------------------
def retry_fetch_ohlcv(exchange, max_retries, symbol, timeframe, since, limit):
num_retries = 0
try:
num_retries += 1
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, since, limit)
# print('Fetched', len(ohlcv), symbol, 'candles from', exchange.iso8601 (ohlcv[0][0]), 'to', exchange.iso8601 (ohlcv[-1][0]))
time.sleep(0.05)
return ohlcv
except Exception:
if num_retries > max_retries:
raise # Exception('Failed to fetch', timeframe, symbol, 'OHLCV in', max_retries, 'attempts')
def scrape_ohlcv(exchange, max_retries, symbol, timeframe, since, limit):
timeframe_duration_in_seconds = exchange.parse_timeframe(timeframe)
timeframe_duration_in_ms = timeframe_duration_in_seconds * 1000
timedelta = limit * timeframe_duration_in_ms
now = exchange.milliseconds()
all_ohlcv = []
fetch_since = since
while fetch_since < now:
try:
ohlcv = retry_fetch_ohlcv(exchange, max_retries, symbol, timeframe, fetch_since, limit)
fetch_since = (ohlcv[-1][0] + 1) if len(ohlcv) else (fetch_since + timedelta)
all_ohlcv = all_ohlcv + ohlcv
if len(all_ohlcv):
print(len(all_ohlcv), 'candles in total from', exchange.iso8601(all_ohlcv[0][0]), 'to',
exchange.iso8601(all_ohlcv[-1][0]))
else:
print(len(all_ohlcv), 'candles in total from', exchange.iso8601(fetch_since))
except Exception as e:
print(e)
return exchange.filter_by_since_limit(all_ohlcv, since, None, key=0)
def write_to_csv(filename, data):
df = pd.DataFrame(data, columns=["时间戳", "开盘价", "最高价", "最低价", "收盘价", "成交量"])
df.to_csv(filename, index=False)
def scrape_candles_to_csv(filename, exchange_id, max_retries, symbol, timeframe, since, limit):
# instantiate the exchange by id
exchange = getattr(ccxt, exchange_id)()
# convert since from string to milliseconds integer if needed
if isinstance(since, str):
since = exchange.parse8601(since)
# preload all markets from the exchange
exchange.load_markets()
# fetch all candles
ohlcv = scrape_ohlcv(exchange, max_retries, symbol, timeframe, since, limit)
# save them to csv file
write_to_csv(filename, ohlcv)
print('Saved', len(ohlcv), 'candles from', exchange.iso8601(ohlcv[0][0]), 'to', exchange.iso8601(ohlcv[-1][0]),
'to', filename)
# -----------------------------------------------------------------------------
if __name__ == '__main__':
# Binance's BTC/USDT candles start on 2017-08-17
path = r'datas\binance.csv'
scrape_candles_to_csv(os.path.join(root, path), 'binance', 3, 'BTC/USDT', '1d', '2017-08-17T00:00:00Z', 1)
代码中需要强调几个地方:
函数scrape_candles_to_csv()中
由于币安交易所限制,最多只能获取近5年的数据,而且每分钟最多请求1200个数据,平均1秒20个数据
在真实交易前面临的第一个问题就是时间戳,时间戳是一个不可避免的问题。时间戳指的是UNIX时间戳,即从UTC时间1970年1月1日0时0分0秒到现在所过去的时间数。
时间戳无论在交易还是数据研究中都具有重要意义。在实际交易中,当交易信号产生后,应检查本地时间戳与服务器时间戳的差异,若两个时间戳差距过大,应当停止当前交易,等待下一次交易信号产生。在回测数据的研究中,CCXT一般返回的都是13位的UNIX时间戳,因此也需要将时间戳转换成正常日期后,才方便进一步地回测研究。
引用:https://blog.csdn.net/c_morning/article/details/120679567
Unix时间戳根据精度不同,大致有10位(秒级)、13位(毫秒级)、19位(纳秒级)。
大多数交易所,包括CCXT的接口目前提供的是13位的UNIX时间戳,即毫秒级时间戳。本文将针对13位UNIX时间戳与ISO8601时间格式转换进行。
Unix毫秒级时间戳 = Unix秒级时间戳 * 1000
交易所目前提供的ISO8601格式为 “2021-10-09T10:08:09.999Z”
可以根据api文档进行开发https://min-api.cryptocompare.com/documentation
获取其他级别周期的数据可以参考文档开发
import os
import json
import requests
import pandas as pd
# 设置你的代理
os.environ["http_proxy"] = "http://127.0.0.1:1001"
os.environ["https_proxy"] = "http://127.0.0.1:1001"
def fetch_ohlcv(fsym,tsym,limit,toTs,api_key=None):
url = f"https://min-api.cryptocompare.com/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&toTs={toTs}&api_key={api_key}"
response = requests.get(url)
json_content = json.loads(response.content)
data = json_content["Data"]["Data"] # 转化为json格式
df = pd.DataFrame(data,columns=["time","high","low","open","close","volumefrom"])
return df
start_time = 1356998400 # 获取行情的起始时间
end_time = 1652918400 # 获取行情的终止时间
frames = []
while start_time<end_time:
df = fetch_ohlcv("BTC","USD","1000",end_time,"your_api_key")
end_time = df['time'].iloc[0]
frames.append(df)
df = pd.concat(frames)
df = df.sort_values(by=["time"])
df = df.sort_values(by=["time"])
df.set_index("time",inplace=True)
df[df.index>=start_time]
df.to_csv("btc.csv") # 保存文件
在2.1给出的代码中含有部分对pandas的操作,对pandas不熟悉的朋友可以参考官方文档进行学习,在这里留一个小坑,后续我会出个系列教程,教大家如何入门pandas。