最近论坛里关于程序化交易很多的帖子很多,看到 @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 查看上面的数据,发现有动态的验证码不能直接简单的登陆。破解验证码就超过了我们这片文章的范畴。所以我们只要保证登陆之后一直不掉线就可以。 那就要先了解平常网站是怎么验证我们是否登陆呢?一般是利用 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./winner_gj/gjzq/stock/exchange.action? CSRF_Token=undefined×tamp=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.72、 安装requests执行: import requests #使用web接口的类库 import json #解析返回的json格式 import re #格式化不正规的json字符串 #获取资金信息的接口地址 url = 'https://jy./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./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./?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAwJCQmaWRlbnRpdHlfdHlwZT0mbW9uZXlfdHlwZT0mcmFtPTAuMTExMTExMTExMTExMTEx 直到我看到一个尾部带=的链接 https://tradegw./?MTExMTExMSZjc3N3ZWJfdHlwZT1HRVRfRlVORFMmdmVyc2lvbj0xJmN1c3RpZD0xMTExMTExMTExMTEmb3BfYnJhbmNoX25vPTAwJmJyYW5jaF9ubz0wMCZvcF9lbnRydXN0X3dheT0wJm9wX3N0YXRpb249SVAkMjU1LjI1NS4yNTUuMjU1O01BQyRGRi1GRi1GRi1GRi1GRi1GRjtIREQkMDAwMDAwMDAxMTExMTExMTExMSZmdW5jdGlvbl9pZD00MDUmZnVuZF9hY2NvdW50PTExMTExMTExMTExMSZwYXNzd29yZD0wMDAwMDAwMDAkJCZpZGVudGl0eV90eXBlPSZtb25leV90eXBlPSZyYW09MC4xMTExMTExMTExMTExMTE= 才发现并不是加密,只是用了 Base64编码而已 在线编解码或者使用Python 解码编码结尾买入卖出的接口并没有实测过,有些参数还不清楚用途,因为只有300块钱,交易一次就要五元手续费,伤不起。后续有实际操作: 程序化交易初探续这次只是一个初期的探索,离真正形成一个交易系统还有很远的距离,希望能给大家带来一点启发。 如果你觉得我的文章不错的话,一元也可,谢谢支持
|