CCXT目前是加密货币量化交易者使用的最多的非常好用的库。尽管距离CCXT发布已经过去了好几年,笔者最近才刚开始深入接触CCXT库,该系列将致力于分享笔者在CCXT使用、真实交易中遇到的各类问题及解决方案。
在真实交易前面临的第一个问题就是时间戳,时间戳是一个不可避免的问题。时间戳指的是UNIX时间戳,即从UTC时间1970年1月1日0时0分0秒到现在所过去的时间数。
时间戳无论在交易还是数据研究中都具有重要意义。在实际交易中,当交易信号产生后,应检查本地时间戳与服务器时间戳的差异,若两个时间戳差距过大,应当停止当前交易,等待下一次交易信号产生。在回测数据的研究中,CCXT一般返回的都是13位的UNIX时间戳,因此也需要将时间戳转换成正常日期后,才方便进一步地回测研究。
UNIX时间戳与ISO8601
Unix时间戳根据精度不同,大致有10位(秒级)、13位(毫秒级)、19位(纳秒级)。
大多数交易所,包括CCXT的接口目前提供的是13位的UNIX时间戳,即毫秒级时间戳。本文将针对13位UNIX时间戳与ISO8601时间格式转换进行。
注:Unix毫秒级时间戳 = Unix秒级时间戳 * 1000
注:交易所目前提供的ISO8601格式为 “2021-10-09T10:08:09.999Z”
Python代码实现
CCXT其实内嵌了UNIX时间戳对ISO8601格式时间的转换函数,但为了深入理解概念,笔者分别展示手撸代码部分和内嵌函数调用部分。
手撸timestamp2iso
import datetime
def timestamp2iso(timestamp,format='%Y-%m-%dT%H:%M:%S.%fZ'):
"""
时间戳转换到ISO8601标准时间(支持微秒级输出 YYYY-MM-DD HH:MM:SS.mmmmmm)
:param timestamp:时间戳,支持 秒,毫秒,微秒级别
:param format:输出的时间格式 默认 iso=%Y-%m-%dT%H:%M:%S.%fZ;其中%f表示微秒6位长度
此函数特殊处理,毫秒/微秒部分 让其支持该部分的字符格式输出
:return:
"""
format = format.replace('%f','{-FF-}')#订单处理微秒数据 %f
length = min(16, len(str(timestamp)))#最多去到微秒级
#获取毫秒/微秒 数据
sec = '0'
if length != 10:#非秒级
sec = str(timestamp)[:16][-(length - 10):]#最长截取16位长度 再取最后毫秒/微秒数据
# sec = '{:0<6}'.format(sec)#长度位6,靠左剩下的用0补齐
sec = '{:0<3}'.format(sec) # 长度位3
timestamp = float(str(timestamp)[:10])#转换为秒级时间戳
return datetime.datetime.utcfromtimestamp(timestamp).strftime(format).replace('{-FF-}',sec)
需要注意的是,datetime.datetime.utcfromtimestamp()返回的UTC时间,若需要北京时间,则需要对时间进行转换。
手撸iso2timestamp
import datetime
def iso2timestamp(datestring, format=‘%Y-%m-%dT%H:%M:%S.%fZ’,timespec=‘milliseconds’):
“”"
ISO8601时间转换为时间戳
:param datestring:iso时间字符串 2019-03-25T16:00:00.000Z,2019-03-25T16:00:00.000111Z
:param format:%Y-%m-%dT%H:%M:%S.%fZ;其中%f 表示毫秒或者微秒
:param timespec:返回时间戳最小单位 seconds 秒,milliseconds 毫秒,microseconds 微秒
:return:时间戳 默认单位秒
"""
tz = pytz.timezone('Asia/Shanghai')
utc_time = datetime.datetime.strptime(datestring, format) # 将字符串读取为 时间 class datetime.datetime
time = utc_time.replace(tzinfo=pytz.utc).astimezone(tz)
times = {
'seconds': int(time.timestamp()),
'milliseconds': round(time.timestamp() * 1000),
'microseconds': round(time.timestamp() * 1000 * 1000),
}
return times[timespec]
注意:当调用datetime.timestamp()时返回的时间戳是以你当前电脑设置的时区为基准的时间返回的时间戳。
举例来说,当你电脑/服务器设置的时区为东八区时,你若想得到UTC时间"2021-10-09T00:00:00.000Z"的时间戳,应当输入"2021-10-09T08:00:000Z"作为输入格式,方可得到正确的UTC时间的时间戳。这也是为什么代码中先将时区设置为东八区的原因。
鉴于大多数交易所都为UTC时间,因此在实际交易中,应当将个人电脑/服务器时区调整为UTC时区,以避免不必要的转换麻烦。
ccxt接口实现
由于手撸代码有太多的问题以及麻烦,调用CCXT提供的现有接口是最好的选择。
首先,对交易所完成初始化
import ccxt
okex = ccxt.okex()
获得当前服务器时间戳
unix_tsp = okex.milliseconds()
获取当前时间戳的ISO8601格式
ISO8601 = okex.iso8601(unix_tsp)