前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 实战之量化交易

Python 实战之量化交易

作者头像
somenzz
发布2020-11-25 10:18:00
4.3K0
发布2020-11-25 10:18:00
举报
文章被收录于专栏:Python七号Python七号

阅读本文大概需要 6 分钟。

什么是量化交易?

百科上是这样介绍的

量化交易是指以先进的数学模型替代人为的主观判断,利用计算机技术从庞大的历史数据中海选能带来超额收益的多种“大概率”事件以制定策略,极大地减少了投资者情绪波动的影响,避免在市场极度狂热或悲观的情况下作出非理性的投资决策。

量化交易的涵盖范围很大,程序化交易,算法交易,高频交易,自动化交易平台等等都可以算作量化交易。

它最大的优点可以规避心理素质原因带来的交易风险,另外,计算机不睡觉,不需要人工实时操盘,满足人们躺着赚钱的愿景。当然实际情况下还是需要人适时干预,防止算法突然失效造成巨额交易亏损。

使用程序来做量化交易,底层就是将买卖请求发送至交易所实现交易,券商或者交易所,通常也会提供 API 接口给投资者。举个例子,Gemini 交易所的公开行情 API 就可以通过下面这种简单的 HTTP GET 请求,来获取最近的比特币对美元的价格和最近的成交量。

代码语言:javascript
复制
########## GEMINI 行情接口 ##########
## https://api.gemini.com/v1/pubticker/:symbol

import json
import requests

gemini_ticker = 'https://api.gemini.com/v1/pubticker/{}'
symbol = 'btcusd'
btc_data = requests.get(gemini_ticker.format(symbol)).json()
print(json.dumps(btc_data, indent=4))

########## 输出 ##########

{
   "bid": "8825.88",
   "ask": "8827.52",
   "volume": {
       "BTC": "910.0838782726",
       "USD": "7972904.560901317851",
       "timestamp": 1560643800000
   },
   "last": "8838.45"
}

对算法交易系统来说,API 只是最下层的结构,通常而言,一个基本的交易系统应该包括:行情模块、策略模块、执行模块,为了辅助策略的开发,通常还有回测系统辅助,它们的分工示意图如下:

交易系统各模块分工

  • 行情模块主要获取市场行情数据,通常也负责获取交易账户的状态。
  • 策略模块主要订阅市场数据,根据设定的算法发出买、卖指令给执行模块。
  • 执行模块的主要功能是接受并把策略模块发过来的买、卖指令封闭并转发到交易所,并监督策略买卖的完整执行。

Python 量化交易

算法交易一个基本需求,就是高效处理数据,数据处理是 Python 的强项,特别是 Numpy+Pandas 的组合,让算法交易开发者的效率直线上升。

这里提供一个爬取、格式化、绘制比特币在过去一个小时的价格曲线的 Python 代码。

代码语言:javascript
复制
import matplotlib.pyplot as plt
import pandas as pd
import requests

# 选择要获取的数据时间段
periods = '3600'

# 通过 Http 抓取 btc 历史价格数据
resp = requests.get('https://api.cryptowat.ch/markets/gemini/btcusd/ohlc', 
  params={
    'periods': periods
  })
data = resp.json()

# 转换成 pandas data frame
df = pd.DataFrame(
  data['result'][periods], 
  columns=[
    'CloseTime',
    'OpenPrice',
    'HighPrice',
    'LowPrice',
    'ClosePrice',
    'Volume',
    'NA'])

# 输出 DataFrame 的头部几行
print(df.head())

# 绘制 btc 价格曲线
df['ClosePrice'].plot(figsize=(14, 7))


########### 输出 ###############
CloseTime  OpenPrice  HighPrice  ...  ClosePrice     Volume             NA
0  1558843200    8030.55    8046.30  ...     8011.20  11.642968   93432.459964
1  1558846800    8002.76    8050.33  ...     8034.48   8.575682   68870.145895
2  1558850400    8031.61    8036.14  ...     8000.00  15.659680  125384.519063
3  1558854000    8000.00    8016.29  ...     8001.46  38.171420  304342.048892
4  1558857600    8002.69    8023.11  ...     8009.24   3.582830   28716.385009

通过执行代码,我们便可能得到下图所示的曲线:

可以借助一些专有的库:

  • Zipline 策略回测
  • Pyfolio 投资组合分析

另外,有一些现有的便利交易平台可以执行自定义的 Python 策略,无需搭建量化交易框架。比如,Quantopian,就提供了基于 Zipline 的标准回测环境,国内也有诸如 BigQuant,果仁网等类似平台。

此外, Python 是各行各业广泛使用的编程语言,越来越多投资机构的交易部门,都开始使用 Python,因此对优秀的 Python 开发者产生了更多的需求,自然也让学习 Python 成了更有意义的投资。

量化交易必须了解什么是 REST

什么是 REST API,要理解 RESTful 架构,最好的方法就是去理解Representational State Transfer 这个词组到底是什么意思,它的每一个词代表了什么涵义。从其英文全称来看是表征状态转移,通过 url 定位资源,用 GET,POST,PUT,DELETE 等动词来描述操作。满足这种要求的 API ,就叫 REST API。

举几个例子吧: 1、Gemini 交易所 BTC 对 USD 的 ticker 接口:

代码语言:javascript
复制
GET https://api.gemini.com/v1/pubticker/btcusd

这里的 GET 是动词,后边的 url 是 ticker 这个资源的地址,所以这是一个 REST API 接口。

2、下面这样的,就不是严格的 REST API 接口。

代码语言:javascript
复制
POST https://api.restful.cn/accounts/delete/:username

因为 URI 中包含动词“delete”(删除),所以这个 URI 并不是指向一个资源。如果要修改成严格的 RESTful 接口,我们可以把它改成下面这样:

代码语言:javascript
复制
DELETE https://api.rest.cn/accounts/:username

手把手教你使用 API 下单

手动挂单显然太慢,也不符合量化交易的初衷。我们就来看看如何用代码实现自动化下单吧。

第一步,你需要做的是,注册一个 Gemini Sandbox 账号。请放心,这个测试账号不需要你充值任何金额,注册后即送大量虚拟现金。这口吻是不是听着特像网游宣传语,接下来就是“快来贪玩蓝月里找我吧”?哈哈,不过这个设定确实如此,所以赶紧来注册一个吧。

注册后,为了满足好奇,你可以先尝试着使用 web 界面自行下单。不过,事实上,未解锁的情况下是无法正常下单的,因此这样尝试并没啥太大意义。

所以第二步,我们需要来配置 API Key。User Settings,API Settings,然后点 GENERATE A NEW ACCOUNT API KEY.,记下 Key 和 Secret 这两串字符。因为窗口一旦消失,这两个信息就再也找不到了,需要你重新生成。配置到此结束。接下来,我们来看具体实现。

先强调一点,在量化系统开发的时候,你的心中一定要有清晰的数据流图。下单逻辑是一个很简单的 RESTful 的过程,和你在网页操作的一样,构造你的请求订单、加密请求,然后 post 给 gemini 交易所即可。

不过,因为涉及到的知识点较多,带你一步一步从零来写代码显然不太现实。所以,我们采用“先读懂后记忆并使用”的方法来学,下面即为这段代码:

代码语言:javascript
复制
import requests
import json
import base64
import hmac
import hashlib
import datetime
import time

base_url = "https://api.sandbox.gemini.com"
endpoint = "/v1/order/new"
url = base_url + endpoint

gemini_api_key = "account-zmidXEwP72yLSSybXVvn"
gemini_api_secret = "375b97HfE7E4tL8YaP3SJ239Pky9".encode()

t = datetime.datetime.now()
payload_nonce = str(int(time.mktime(t.timetuple())*1000))

payload = {
   "request": "/v1/order/new",
   "nonce": payload_nonce,
   "symbol": "btcusd",
   "amount": "5",
   "price": "3633.00",
   "side": "buy",
   "type": "exchange limit",
   "options": ["maker-or-cancel"]
}

encoded_payload = json.dumps(payload).encode()
b64 = base64.b64encode(encoded_payload)
signature = hmac.new(gemini_api_secret, b64, hashlib.sha384).hexdigest()

request_headers = {
    'Content-Type': "text/plain",
    'Content-Length': "0",
    'X-GEMINI-APIKEY': gemini_api_key,
    'X-GEMINI-PAYLOAD': b64,
    'X-GEMINI-SIGNATURE': signature,
    'Cache-Control': "no-cache"
}

response = requests.post(url,
                         data=None,
                         headers=request_headers)

new_order = response.json()
print(new_order)


########## 输出 ##########

{'order_id': '239088767', 'id': '239088767', 'symbol': 'btcusd', 'exchange': 'gemini', 'avg_execution_price': '0.00', 'side': 'buy', 'type': 'exchange limit', 'timestamp': '1561956976', 'timestampms': 1561956976535, 'is_live': True, 'is_cancelled': False, 'is_hidden': False, 'was_forced': False, 'executed_amount': '0', 'remaining_amount': '5', 'options': ['maker-or-cancel'], 'price': '3633.00', 'original_amount': '5'}

RESTful 的 POST 请求,通过 requests.post 来实现。post 接受三个参数,url、data 和 headers。这里的 url 等价于 https://api.sandbox.gemini.com/v1/order/new . ,但是在代码中分两部分写。第一部分是交易所 API 地址;第二部分,以斜杠开头,用来表示统一的 API endpoint。我们也可以在其他交易所的 API 中看到类似的写法,两者连接在一起,就构成了最终的 url。

而接下来大段命令的目的,是为了构造 request_headers。

另外,请注意 nonce,这是个很关键并且在网络通信中很常见的字段。因为网络通信是不可靠的,一个信息包有可能会丢失,也有可能重复发送,在金融操作中,这两者都会造成很严重的后果。丢包的话,我们重新发送就行了;但是重复的包,我们需要去重。虽然 TCP 在某种程度上可以保证,但为了在应用层面进一步减少错误发生的机会,Gemini 交易所要求所有的通信 payload 必须带有 nonce。

nonce 是个单调递增的整数。当某个后来的请求的 nonce,比上一个成功收到的请求的 nouce 小或者相等的时候,Gemini 便会拒绝这次请求。这样一来,重复的包就不会被执行两次了。另一方面,这样也可以在一定程度上防止中间人攻击:

  • 一则是因为 nonce 的加入,使得加密后的同样订单的加密文本完全混乱;
  • 二则是因为,这会使得中间人无法通过“发送同样的包来构造重复订单“进行攻击。

接下来的代码就很清晰了。我们要对 payload 进行 base64 和 sha384 算法非对称加密,其中 gemini_api_secret 为私钥;而交易所存储着公钥,可以对你发送的请求进行解密。最后,代码再将加密后的请求封装到 request_headers 中,发送给交易所,并收到 response,这个订单就完成了。

参考文章:

Python 核心技术与实战:量化交易实战篇。 这是我学习 Python 最受益匪浅的地方,推荐给你。购买请扫下方二维码:

(完)

专注于Python技术分享

欢迎订阅、在看、转发

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python七号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是量化交易?
  • Python 量化交易
  • 量化交易必须了解什么是 REST
  • 手把手教你使用 API 下单
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档