之前发过一篇文章,原理是通过手机端来实现实盘操作,如下:
https://www.joinquant.com/view/community/detail/8a27eb5e5aa2e26842810f4ce8578a1e
好处是任何时候都是可用的,不足是稳定性和响应速度不够快,受https://www.joinquant.com/view/community/detail/98b2880afbd8655f927406d656fdf80b#317833
启发,有望实现毫秒级稳定实盘,现已初步实现仓位查询,后续打算实现委托单,交易查询以及买卖功能,让我们一起期待,上图:

**仅支持华宝**
2023-12-02 更新
实现帐户信息查询,如下

实现历史成交单查询

2023-12-04 更新
今天试了下下单功能,已经通了,先把实验板放上来大家试用下吧!有问题多多反馈
1. 安装依赖
```
pip install requests lxml
```
2. 当前目录下新建配置文件,名为config.ini,内容如下
```
[hb]
cookie = xxx
```
xxx为web端登入后的cookie 经过base64编码
3. cookie的获取
浏览器打开https://m.touker.com/trading/trade/trading-sub/position,手机登录,打开开发者选项,找到position中header的cookie即可
4. 下载附件的源码,和config在同一目录即可,然后运行先体验下
2023-12-17更新
将所有功能函数化,至此,这个已经是一个完整的集查询持仓,账户,查询委托和成交及下单一体化的程序了,可单独使用,也可集成在你自己的代码中(需要一定的编程基础),下面简单介绍下使用方法。
**1. 单独使用**
1.1 导入模块
```
from hb_web import *
```
1.2 查询持仓
```
get_position()
```
1.3 查询账户信息
```
get_account()
```
1.4 查询历史成交
```
consult('lscj')
```
1.5 查询今日成交
```
consult('jrcj')
```
1.6 查询今日委托
```
consult('jrwt')
```
1.7 最重要的,买卖功能
```
order(act,stock_name,stock_code,price,amount)
```
各参数解释如下:
act为买卖动作,具体为BUY/SELL
stock_name股票名称,可以为空
stock_code聚宽的股票代码,如000592.XSHE等
price价格
amount 股票数量
实例:
order('BUY','','000592.XSHE','2.5',100)
此处,股票名称为空,建议如此,股票代码是唯一的
**2 . 结合蒋老师的redis来使用,实现自动实盘**
2.1 下面的文章已经讲的很清楚了,只要改动下对应的order_handle函数即可,换成自己的下单程序即可
https://www.joinquant.com/view/community/detail/62538f9415d228ab72ed8f20d48bb533
2.2 好人做到底,就分享一下如何写吧,其实很简单,就几行代码搞定
```
def order_hb(msg):
# 请在此处自己coding, 根据msg给交易端下单
print(f'正在处理{msg}')
act=msg['action']
code=msg['code']
pct=msg['pct']
amt=msg['amount']
if act=='BUY':
order(act,'',code,'',amt)
elif act=='SELL':
order(act,'',code,'',amt)
```
2023-12-20 更新
增加jq版本,复制内容至研究根目录下即可,替换对应的cookie,可以在jq中运行,只能传一个附件,这个就直接贴了
```
#!/bin/python
#coding=utf8
'''
Author: Michael Jin
Date: 2023-12-19
'''
import urllib
import requests
import os,re,time
import base64,json
from lxml import etree
from kuanke.user_space_api import *
###模拟get,post请求
def general(method,url,data=''):
'''
功能:推送消息
title:消息的标题
content:消息的内容
'''
s=requests.Session()
hb_cookie=r'' #填入你自己的cookie,以_b_开头
if method=='get':
myheader={
'Accept':'text/html, */*; q=0.01',
'Accept-Encoding':'gzip, deflate, br',
'Accept-Language':'zh-CN,zh;q=0.9',
'cookie':hb_cookie,
'Refer':'https://m.touker.com/trading/trade/position',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
'X-Requested-Width':'XMLHttpRequest',
'Sec-Ch-Ua':'"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
'Sec-Ch-Ua-Platform':'Windows',
'Sec-Fetch-Dest':'document',
'Sec-Fetch-Mode':'navigate',
'Sec-Fetch-Site':'same-origin',
}
# res=requests.get(url,headers=myheader,allow_redirects=False)#发送get请求
res=s.get(url,headers=myheader,allow_redirects=False)#发送get请求
# print(res.status_code)
# print(res.url)
elif method=='post':
myheader={
'cookie':hb_cookie,
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'origin': 'https://m.touker.com',
'referer': 'https://m.touker.com/trading/trade/buy',
'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': "Windows",
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
'x-requested-with': 'XMLHttpRequest',
'Host': 'm.touker.com'
}
buy_url='https://m.touker.com/trading/securitiesEntrust.json'
#下面两条为抓取的实际示例
# data_buy = "stockName=&stockCode=159601&exchange=SZ&securityType=3&price=0.686&num=4600&entrustType=1&channel=&deviceInfo="
# data_sell="stockName=恒生互联网ETF&stockCode=513330&exchange=SH&securityType=3&price=0.370&num=100&entrustType=2&channel=&deviceInfo="
# res=requests.post(buy_url,headers=myheader,data=data1)
res=s.post(buy_url,headers=myheader,data=data)
# print(res.status_code)
# print(res.text)
return res
###查询持仓
def get_position():
position_url='https://m.touker.com/trading/queryHoldPosition.json?positionType=total&_=1701322363576'#持仓明细
res=general('get',position_url)
selector=etree.HTML(res.text)
items=selector.xpath('//div[@class="position-item"]')
positions=[]
for item in items:
total_info=[]
# print(etree.tostring(item))
part1=item.xpath('./div/div/div/text()')
part2=item.xpath('./div/div/div/div/text()')
total_info=part1[0:7]+part2
# print(part1[0:7]+part2)
# print('='*50)
positions.append(total_info)
return positions
###获取账户信息
def get_account():
url='https://m.touker.com/trading/baseInfo.json?_=1701498696248'
res=general('get',url)
base_info=json.loads(res.text)
return base_info
###查询委托成交
def consult(act):
'''
act(str):查询的动作,即历史委托(lswt),今日委托(jswt),历史成交(lscj),今日成交(jrcj)等
'''
consult_url=f'https://m.touker.com/trading/trade/entrustList?orderType={act}'
res=general('get',consult_url)
selector=etree.HTML(res.text)
items=selector.xpath('//div[@class="revoke-area"]/a')
deals=[]
for item in items:
code=item.xpath('./div/p/text()')
act=item.xpath('./div[2]/button/text()')
details=item.xpath('./div[2]/div/div/p/span/text()')
print(code,act,details)
###下单
def myorder(act,data):
if act=='buy':
buy_url='https://m.touker.com/trading/securitiesEntrust.json'
elif act=='sell':
sel_url=''
general('post',data)
pass
###菜单
def Menu():
choice=input('1.position\n2.历史成交\n3.今日成交\n4.帐户信息\n5.今日委托')
if choice=='1':
# position_url=f'https://m.touker.com/trading/trade/trading-sub/position?_=1701162501444'#构建get请求的地址
positions=get_position()
for i,stock in enumerate(positions):
print(f'{i+1}-->{stock}')
elif choice=='2':
consult('lscj')
elif choice=='3':
consult('jrcj')
elif choice=='4':
base_info=get_account()
print(base_info)
assets=base_info['totalAssets']
market_values=base_info['totalMarketValue']
available=base_info['useAvailable']
profits=base_info['totalHoldingProfit']
today_profit=base_info['todayProfit']
# print(assets,market_values,available,profits,today_profit)
elif choice=='buy':
code=input('请输入股票代码')
price=input('请输入价格')
amount=input('请输入数量')
order('BUY','',code,price,amount)
elif choice=='sell':
code=input('请输入股票代码')
price=input('请输入价格')
amount=input('请输入数量')
order('SELL','',code,price,amount)
elif choice=='5':
consult('jrwt')
###构建买卖的股票基本信息并下单
def order(act,stock_name,code,price,amount):
'''
act(str):买卖
stock_name(str):股票名称
code(str):代码
price(float):价格
amount(int):数量
'''
#基于股票代码,判断市场类型
# if 'sh' or 'SH' or 'XSHG' in stock_name:
if 'XSHG' in code:
market='SH'
elif 'XSHE' in code:
market='SZ'
#提取code中的数字部分
code=re.search('\d+',code).group()
#这个信息中包含了buy/sell的动作,1:buy,2:sell
if act=='BUY':
data = f"stockName={stock_name}&stockCode={code}&exchange={market}&securityType=3&price={price}&num={amount}&entrustType=1&channel=&deviceInfo="
elif act=='SELL':
data = f"stockName={stock_name}&stockCode={code}&exchange={market}&securityType=3&price={price}&num={amount}&entrustType=2&channel=&deviceInfo="
print(data)
url='https://m.touker.com/trading/securitiesEntrust.json'
general('post',url,data)
```
哈哈,加油,继续。这个确实是目前最简洁的方案。另外,不用太过于纠结下单的速度,除了tick级别的策略,大盘股或者小市值策略对交易的速度其实要求不高,毕竟撮合制下用涨跌停价格下单基本秒成交,但如果换成2%笼子价格下单,成交时间可能会延迟至6-10秒了
2023-12-03
大家喜欢的话多多点赞,有什么问题也可以在这里留言,cookie的获取不清楚的话可以百度一下,不复杂
2023-12-04