最近论坛里关于程序化交易很多的帖子很多,看到 @farever0591 的帖子,引起了我的兴趣。
程序化交易最关键的便是获得所用的接口,其余的就是根据自己的系统调用接口实现。
但是国内貌似没有直接提供接口的券商,要么是有接口但是非常昂贵。所以只能从公开的接口想办法,比如web接口以及手机api等等。相对来说从web接口入手比较简单。
下面的相关接口已经整合到一个 Python 类库里了,
easytrader : 目前支持华泰的自动登录和买卖撤单
Github源代码
券商以佣金宝为例,使用IE11浏览器,使用的编程语言是Python,|简明教程1|简明教程2|,想学习的推荐这个 笨办法学Python
登陆
首先我们打开佣金宝的 网上交易登陆 界面,按F12打开控制台:

然后输入我们的账号密码登陆,查看控制台,可以观察到我们与服务器交互的过程:
按照方法排列,找到POST方法,POST发送,GET接收,具体方法解释
可以发现我们登陆的接口是:https://jy.yongjinbao.com.cn/winner_gj/gjzq/exchange.action
查看发送的登陆数据account_content: 00000000 #你的账号
content_type: 0
cpuid: -00000-00000000 #CPU的ID
disk_serial_id: #硬盘序列号
function_id: 200 #调用的验证函数
identity_type:
input_content: 1
login_type: stock #登陆类型为股票
loginPasswordType: 000 #登陆的密码类型
mac_addr: 00-00-00-00-00-00 #MAC地址,即你的网卡ID
machinecode: -00000-00000000 #机器码,每台电脑唯一
password: ABCDE…EDCBA #加密的密码字符串
remember_me: #是否记住账号
validateCode: 0000 #验证码
version: 200
查看上面的数据,发现有动态的验证码不能直接简单的登陆。破解验证码就超过了我们这片文章的范畴。所以我们只要保证登陆之后一直不掉线就可以。
那就要先了解平常网站是怎么验证我们是否登陆呢?
一般是利用cookie和session,简单讲cookie是存储的在硬盘的一个字符串,下次打开时还可以生效,session是存储在浏览器中的字符串,在关闭页面后就消失了。你在跟服务器通讯时传递这个字符串,服务器跟自己保存的字符串对比即可认为特定用户已登陆
服务器保存的对应列表
‘我是A粉’ –> ‘用户A’
‘我是B粉’ –> ‘用户B’
客户端 —–> 服务器
发送:’买入分级A’ 携带字符串:’我是A’
服务器执行:A用户 买入分级A
客户端 —–> 服务器
发送:’买入分级B’ 携带字符串:’我是B’
服务器执行:B用户 买入分级B
客户端 —–> 服务器
发送:’买入分级C’ 携带字符串:’我是韭菜’
服务器返回:查无此用户
通过查看佣金宝的cookie:
我们发现了一个JSEESIONID,这就是我们跟服务器通讯认证的ID了,在跟接口通信时只要携带上这个JSEESIONID的信息即可。
获取交易的相关接口
以获取资金信息为例,先打开查询 –> 资金股份 便可看到上面有资金信息以及持仓信息,同样先清除不必要的信息,然后点击资金信息即可
首先我们查看获取到的api接口,在浏览器上的链接处右键复制url即可https://jy.yongjinbao.com.cn/winner_gj/gjzq/stock/exchange.action?
CSRF_Token=undefined×tamp=0.1111111111111111&request_id=mystock_405https://jy.yongjinbao.com.cn/winner_gj/gjzq/stock/exchange.action?
为固定的url前缀,后面传入的是我们的操作传递的参数,以 & 分开:
CSRF_Token=undefined #未知,在后面的接口中也为undefined的固定值
timestamp=0.1111111111111111 #查看js代码发现[‘timestamp=’ + Math.random(1)]为0,1之间的一个随机数,并没有什么意义
request_id=mystock_405 #调用的操作类型,可以理解为进行第405号操作,即返回资金情况
返回的数据,为 JSON 格式,即是以 键:值的方式存储信息
{“login_type”:null,”returnJson”:”{function_id: ‘405’, msg_info: ”, msg_no: ‘0’, error_grids: ”, grid_count: ‘1’, Func405: [{money_type: ‘币种’, current_balance: ‘当前余额’, enable_balance: ‘可用金额’, market_value: ‘证券市值’, asset_balance: ‘资产总值’, pre_interest: ‘预计利息’},{money_type:’人民币’, current_balance:’300.000′, enable_balance:’300.000′, market_value:’0.000′, asset_balance:’300.000′, pre_interest:’0.180′}], end: ‘0’ }”}
格式化一下:
{
“login_type”: null,
“returnJson”:
“{
function_id: ‘405’,
msg_info: ”,
msg_no: ‘0’,
error_grids: ”,
grid_count: ‘1’,
Func405: [
{
money_type: ‘币种’,
current_balance: ‘当前余额’,
enable_balance: ‘可用金额’,
market_value: ‘证券市值’,
asset_balance: ‘资产总值’,
pre_interest: ‘预计利息’
},
{
money_type: ‘人民币’,
current_balance: ‘300.000’,
enable_balance: ‘300.000’,
market_value: ‘0.000’,
asset_balance: ‘300.000’,
pre_interest: ‘0.180’
}
],
end: ‘0’
}”
}
通过观察我们所要的数据就在 Func405 中,佣金宝所有返回的数据都是以类似的格式存储
第一个 { } 中的为中英文对照
第二个 { } 中为我们所请求的数据,若有多个数据,则依次排列
通过程序请求api
准备:
1、安装Python 2.7
2、安装requests
执行:
import requests #使用web接口的类库
import json #解析返回的json格式
import re #格式化不正规的json字符串
#获取资金信息的接口地址
url = ‘https://jy.yongjinbao.com.cn/winner_gj/gjzq/stock/exchange.action?CSRF_Token=undefined×tamp=0.1111111111111111&request_id=mystock_405’
cookie = dict(JSESSIONID=’ABC..CBA’) #填入你自己的JSESSIONID
rep = requests.get(url, cookies=cookie) #使用cookies调用接口获取回应
rep.content即为我们获取的json内容
发现returnJson的数据并不是标准JSON格式,所以写了一个格式化的函数:
格式化之后:
其他接口
接口前缀皆为:https://jy.yongjinbao.com.cn/winner_gj/gjzq/stock/exchange.action?CSRF_Token=undefined×tamp=0.1111111111111111
持仓:
&service_type=stock&request_id=mystock_403&sort_direction=0
{
position_str: ‘定位串’,
stock_code: ‘证券代码’,
stock_name: ‘证券名称’,
current_amount: ‘当前数量’,
enable_amount: ‘可卖数量’,
last_price: ‘最新价’,
cost_price: ‘摊薄成本价’,
keep_cost_price: ‘保本价’,
income_balance: ‘摊薄浮动盈亏’,
market_value: ‘证券市值’
}
股票信息:
&service_type=stock&function_id=Q0002&codeList=股票代码
{
code: ‘代码’,
stockName: ‘名称’,
newPrice: ‘现价’,
zhangdiefu: ‘涨跌幅’,
totalAmount: ‘成交金额’,
maxPrice: ‘最高’,
minPrice: ‘最低’,
preClose: ‘昨收’
},
买入:
&request_id=buystock_302&stock_account=沪深账号&exchange_type=1&entrust_prop=0&entrust_bs=1&stock_code=股票ID&entrust_price=价格&entrust_amount=数量&elig_riskmatch_flag=1
卖出:
&service_type=stock&request_id=sellstock_302&stock_account=沪深账号&exchange_type=1&entrust_prop=0&entrust_bs=2&stock_code=股票代码&entrust_price=价格&entrust_amount=数量
保证不掉线
程序化交易的精髓就是自动运行,所以不能掉线。一般需要重新登陆都是你长时间没操作之后服务器那边你的session就过期了,所以你只需要写个函数隔10秒向服务器请求数据维持登陆状态即可
附录:关于华泰的接口
华泰的接口类似于这种形式,乍看之下加了密
https://tradegw.htsc.com.cn/?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAwJCQmaWRlbnRpdHlfdHlwZT0mbW9uZXlfdHlwZT0mcmFtPTAuMTExMTExMTExMTExMTEx
直到我看到一个尾部带=的链接
https://tradegw.htsc.com.cn/?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAkJCZpZGVudGl0eV90eXBlPSZtb25leV90eXBlPSZyYW09MC4xMTExMTExMTExMTExMTE=
才发现并不是加密,只是用了Base64编码而已
在线编解码或者使用Python解码
编码
结尾
买入卖出的接口并没有实测过,有些参数还不清楚用途,因为只有300块钱,交易一次就要五元手续费,伤不起。后续有实际操作: 程序化交易初探续
这次只是一个初期的探索,离真正形成一个交易系统还有很远的距离