分享

程序化交易初探

 dbn9981 2016-11-13

最近论坛里关于程序化交易很多的帖子很多,看到 @farever0591 的帖子,引起了我的兴趣。
程序化交易最关键的便是获得所用的接口,其余的就是根据自己的系统调用接口实现。
但是国内貌似没有直接提供接口的券商,要么是有接口但是非常昂贵。所以只能从公开的接口想办法,比如web接口以及手机api等等。相对来说从web接口入手比较简单。
下面的相关接口已经整合到一个 Python 类库里了,
easytrader : 目前支持华泰的自动登录和买卖撤单
Github源代码

券商以佣金宝为例,使用IE11浏览器,使用的编程语言是Python,|简明教程1|简明教程2|,想学习的推荐这个 笨办法学Python

登陆

首先我们打开佣金宝的 网上交易登陆 界面,按F12打开控制台:



然后输入我们的账号密码登陆,查看控制台,可以观察到我们与服务器交互的过程:



按照方法排列,找到POST方法,POST发送,GET接收,具体方法解释
可以发现我们登陆的接口是:https://jy./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

查看上面的数据,发现有动态的验证码不能直接简单的登陆。破解验证码就超过了我们这片文章的范畴。所以我们只要保证登陆之后一直不掉线就可以。

那就要先了解平常网站是怎么验证我们是否登陆呢?
一般是利用cookiesession,简单讲cookie是存储的在硬盘的一个字符串,下次打开时还可以生效,session是存储在浏览器中的字符串,在关闭页面后就消失了。你在跟服务器通讯时传递这个字符串,服务器跟自己保存的字符串对比即可认为特定用户已登陆
服务器保存的对应列表
'我是A粉' --> '用户A'
'我是B粉' --> '用户B'

客户端 -----> 服务器
发送:'买入分级A'  携带字符串:'我是A'
服务器执行:A用户 买入分级A
客户端 -----> 服务器
发送:'买入分级B'  携带字符串:'我是B'
服务器执行:B用户 买入分级B
客户端 -----> 服务器
发送:'买入分级C'  携带字符串:'我是韭菜'
服务器返回:查无此用户


通过查看佣金宝的cookie:



我们发现了一个JSEESIONID,这就是我们跟服务器通讯认证的ID了,在跟接口通信时只要携带上这个JSEESIONID的信息即可。

获取交易的相关接口

以获取资金信息为例,先打开查询 --> 资金股份 便可看到上面有资金信息以及持仓信息,同样先清除不必要的信息,然后点击资金信息即可



首先我们查看获取到的api接口,在浏览器上的链接处右键复制url即可https://jy./winner_gj/gjzq/stock/exchange.action? 
CSRF_Token=undefined&timestamp=0.1111111111111111&request_id=mystock_405
https://jy./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./winner_gj/gjzq/stock/exchange.action?CSRF_Token=undefined&timestamp=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./winner_gj/gjzq/stock/exchange.action?CSRF_Token=undefined&timestamp=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./?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAwJCQmaWRlbnRpdHlfdHlwZT0mbW9uZXlfdHlwZT0mcmFtPTAuMTExMTExMTExMTExMTEx
直到我看到一个尾部带=的链接
https://tradegw./?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAkJCZpZGVudGl0eV90eXBlPSZtb25leV90eXBlPSZyYW09MC4xMTExMTExMTExMTExMTE=
才发现并不是加密,只是用了Base64编码而已
在线编解码或者使用Python解码


编码



结尾

买入卖出的接口并没有实测过,有些参数还不清楚用途,因为只有300块钱,交易一次就要五元手续费,伤不起。后续有实际操作: 程序化交易初探续
这次只是一个初期的探索,离真正形成一个交易系统还有很远的距离,希望能给大家带来一点启发。
如果你觉得我的文章不错的话,一元也可,谢谢支持



      本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
      转藏 分享 献花(0

      0条评论

      发表

      请遵守用户 评论公约

      类似文章 更多