【目录】
- 1.1. 安装
- 1.2. 申请权限
- 1.3. 模拟和测试
- 1.4. 运行和维护
- 2.1. 客户端请求
- 2.2. 返回结果
- 2.3. 资产表
- 2.4. 持仓表
- 2.5. 限价买入
- 2.6. 市价买入
- 2.7. 限价卖出
- 2.8. 市价卖出
- 2.9. 取消委托
- 2.10. 查询当日委托
- 撮合配置规则
- 联系方式
-
在windows机器上安装https://emt.eastmoneysec.com/down,下载并安装第二个软件:
-
在同一台机器上安装conda,推荐安装miniconda,并创建虚拟运行环境(python版本3.8):
conda create -n gmclient python=3.8
-
安装gmadaptor:
pip install gmadaptor-1.1.3-py3-none-any.whl
请加入东方财富量化仿真交流群:971584613 ,找管理员申请开通量化实盘权限。请先看群置顶文件。 开通的主要门槛是要求100万初始资金。开通后可以撤资。
在等待实盘权限开通的过程中,可以通过 https://emt.18.cn/apply/test-apply-client 开通模拟账号,先把程序和配置调通。
申请后,记录普通资金账号和密码,如下图:
在登录界面中,选择仿真交易:
登录后,界面显示如下:
以下步骤对实盘和模拟盘均有效。
需要将量化软件中的实盘账号配置到gmadaptor的配置文件中。在用户目录下,创建gmadaptor/config
目录,放置以下文件:
# defaults.yaml
log_level: INFO
server_info:
port: 9000
# client 使用这一token来访问 gmadaptor 提供的服务
access_token : "84ae0899-7a8d-44ff-9983-4fa7cbbc424b"
gm_info:
fake: false
# 文件单输出目录
gm_output: "~/gmadaptor/FileOrders/out"
trade_fees:
commission: 2.5
stamp_duty: 10.0
transfer_fee: 0.1
minimum_cost: 5.0
accounts:
# 账号名
- name: fileorder_s01
acct_id: 1a66e81c-ae5d-11ec-aef5-00163e0a4100
# 文件单输入目录。东财量化终端将从这里读取文件单
acct_input: "~/gmadaptor/FileOrders/inputs/fileorder_s01"
上述配置中,access_token 可任意指定,任何要访问此服务的客户端,必须持有此 token。
gm_output/acct_input 文件设置后,如果未创建,gmadaptor 将在启动时自动创建,请确保 gmadaptor 有权限读写这些文件夹。
accounts > name 中的值来自于在 EMC 终端中,您创建文件单输入时,指定的名称,见下图中的序号2:
accounts > acct_id 来自于下面序号3的位置,点击ID
即可复制:
在 量化 > 文件单 > 文件单输出 中,对下图中的 4,5,6,7 进行配置。其中4选择我们在上面配置文件中gm_output中设置的路径;5选择csv
作为输出格式;6选择自动启动;7将所有项目全选中。
在 量化 > 文件单 > 文件单输入 中,对下图中的 3和4进行配置。其中3选择我们在上面配置文件中设置的 acct_input 路径,4选择自动启动。
在前面生成的gmclient虚拟环境中,执行以下命令,以启动gmadaptor服务器:
python -m gmadaptor.server
如果出现如下界面,表明服务器启动成功:
此时我们另开一个conda
窗口,同样使用gmclient
的虚拟环境,通过以下命令进行测试:
python -m gmtest %account %token %server %port
这里的account即 gmadaptor配置文件中的 gm_info > accounts > account_id, token 即server_info > access_token
这里的 server 即gmadaptor 所在的机器IP, port为端口。如果不提供,默认地,这两项分别为localhost和9000。
如果配置正常,这将打印出初始账号资金,当前持仓,和一笔买、卖的信息。
另外启动一个计划任务,在每天早上8:45左右启动EMC。
使用下面的脚本来启动:
@echo off
call C:\ProgramData\Anaconda3\Scripts\activate.bat C:\ProgramData\anaconda3
call conda activate gmclient
python -m gmadaptor.server
pause
EMC量化终端有时候不稳定。我们可以通过定时重启来提高起稳定性。通过以下代码,在盘后退出EMC:
REM kill process
TASKKILL /F /IM EMCTrade.exe
REM sleep 5 seconds
TIMEOUT /T 5
REM remove all file orders after process killed
DEL /Q C:\zillionare\FileOrders\real_input\*.csv
!!! Warning 如果在输入输出目录中还有未归档的文件,则量化交易将无法自动启动。上述代码中最后一行的作用就是清理未归档文件。 这也要求使用者自行对委托进行核验,确保这些文件可以被自动删除。
客户端通过 http request来请求gmadaptor。以下示例均以同步请求实现,但您也可以根据需要,改为异步请求。服务器对客户端的鉴权是通过headers
来实现的,具体请看示例(任意一示例均可)。客户端向服务器发送数据,都使用的是post方法,gmadaptor所有的方法都只响应post请求。如果请求成功完成,则返回代码是200。
在所有的操作中,股票代码都必须以简码+交易所后缀方式出现,其中上交所为.XSHG,深交所为.XSHE。在仿真测试时,对股票进行操作时,都有特定的响应(比如对某支股票,进行买入时,无论给的参数是多少,返回都会是部分成交;对另一支股票,则永远返回限制买入等等),具体响应文档请在东财量化Q群中,找管理员要文档。
在一些会改变状态的请求中(比如买入操作),往往会需要cid
参数和timeout
参数,其作用是,调用会在指定的timeout期间等待EMC处理请求,并返回结果;但EMC也可能无法在指定的timeout期间返回结果,比如委买单报价过低,一直不能成交,此时将无法产生回报结果。在这种情况下,调用会在timeout之后返回。之后的委买结果查询,就需要依赖cid
参数。注意cid
是必选参数,timeout
是可选参数。
cid
参数(即client entrust id)由客户端自行产生,建议使用以下代码:
import uuid
cid = str(uuid.uuid4())
cid
产生之后,请在客户端保存,直到事务结束,不再需要为止。
为简练起见,以下示例中,可能删除了这些代码:
import httpx
headers = {
"Authorization": "84ae0899-7a8d-44ff-9983-4fa7cbbc424b",
"Account-ID": "780dc4fda3d0af8a2d3ab0279bfa48c9"
}
_url_prefix = "http://192.168.100.100:9000/"
buy_entrust_no = None
sell_entrust_no = None
返回错误可能发生在三个层面。一是http层(包括 bad request 或者 Internal server error); 二是 gmadaptor层,三是 emc可能返回错误。
第一层的错误,我们通过 http status code来检查。比如,如果我们使用的客户端是httpx,则可以检查 response.status_code
是否为200。
gmadaptor始终通过json
来返回响应,响应包括三个字段,即:
status: int,如果为零,则表明在此层没有发生错误,即gmadaptor已经将请求正确上报
msg: str, human readable message
data: dict 如果一切顺利,则返回数据在此项中
第三层的错误由 emc trader给出。即使gmadaptor正确上报的请求,也可能emc trader无法执行,此时它也会通过status
和reason
来给出错误信息。
下面的示例给出了一个response.json()
的输出:
{
"status": 0,
"msg": "OK",
"data": {
"code": "000001.XSHE",
"price": 0.0,
"volume": 100,
"order_side": 1,
"bid_type": 2,
"time": "2023-04-04 15:27:38.921555",
"entrust_no": "0d23bb4e-d81e-4ef2-ab21-c58e0fe6814f",
"status": -1,
"average_price": 0.0,
"filled": 0,
"filled_amount": 0,
"eid": "",
"trade_fees": 0,
"reason": "[Counter] [EMC_PC]不支持该下单类型",
"recv_at": "2023-04-04 15:27:38.924565"
}
}
因此,即使在gmadator层面给出的状态是成功,也并不意味着该笔委托成功。另一个例子是,以过低的价格委买,只要参数合法且被EMC接收,gmadaptor都会返回成功,但该委托是否真正成交,还得通过entrust_no来查询。
# 请求资金信息
import httpx
headers = {
"Authorization": "84ae0899-7a8d-44ff-9983-4fa7cbbc424b",
"Account-ID": "780dc4fda3d0af8a2d3ab0279bfa48c9"
}
_url_prefix = "http://192.168.100.100:9000/"
def get_balance():
r = httpx.post(_url_prefix + "balance", headers=headers)
resp = r.json()
if r.status_code == 200 and resp['status'] == 0:
print("\n------ 账户资金信息 ------")
print(resp["data"])
def get_positions():
r = httpx.post(_url_prefix + "positions", headers=headers)
resp = r.json()
if r.status_code == 200 and resp['status'] == 0:
print("\n----- 持仓信息 ------")
print(resp["data"])
r = httpx.post(_url_prefix + "buy", headers=headers, json={
"security": "000001.XSHE",
"price": 13,
"volume": 100,
"cid": str(uuid.uuid4()),
"timeout": 1
})
print(r.json())
def market_buy():
global buy_entrust_no
r = httpx.post(_url_prefix + "market_buy", headers=headers, json={
"security": "000001.XSHE",
"volume": 100,
"cid": cid,
"timeout": 1
})
resp = r.json()
if r.status_code == 200 and resp["status"] == 0:
print("\n ------ 委买成功 ------")
print(resp["status"], resp["msg"], resp["data"])
buy_entrust_no = resp["data"]["entrust_no"]
else:
print("委买失败:", r.status_code, resp)
def sell():
global sell_entrust_no
r = httpx.post(_url_prefix + "sell", headers=headers, json={
"security": "000001.XSHE",
"price": 10,
"volume": 100,
"cid": cid,
"timeout": 1
})
resp = r.json()
if r.status_code == 200 and resp["status"] == 0:
print("\n ------ 限价委卖成功 ------")
data = resp["data"]
print(data)
sell_entrust_no = data["entrust_no"]
else:
print("卖出失败:", r.status_code, resp)
def market_sell():
r = httpx.post(_url_prefix + "market_sell", headers=headers, json = {
"security": "000001.XSHE",
"volume": 100,
"cid": cid
})
resp = r.json()
if r.status_code == 200 and resp["status"] == 0:
print("\n ------ 市价委卖成功 ------")
print(resp["data"])
else:
print(resp)
def cancel_entrust():
global buy_entrust_no
r = httpx.post(_url_prefix + "cancel_entrust", headers=headers, json = {
"entrust_no": buy_entrust_no,
"timeout": 1
})
resp = r.json()
print(resp["status"], resp["msg"], resp["data"])
def today_entrusts():
r = httpx.post(_url_prefix + "today_entrusts", headers=headers, json = {
# 此处可以传入记录的委托号。传入空数组时,表明取当天所有委托。
"entrust_no": [],
"timeout": 1
})
resp = r.json()
print(resp["status"], resp["msg"], resp["data"])
关于东财文件单,请参考:https://emquant.18.cn/file-help/?doc=file_order 东财量化Q群:971584613
即使实现了EMC的每日自动重启,也有可能偶发连接异常或者其它错误。此时可能需要手动执行:
- 重新连接
- 清除文件单,重新启动
在仿真交易测试中,EMTrader对每个品种,都指定了对应的响应。比如,对000572这个品种,买入一定会全部成交,对000010这个品种,则一定会拒绝。这是为了方便测试的需要。东财提供了名为《撮合配置规则》的文件,该文件可能随时更新,所以,需要在测试前,加他们技术人员QQ领取。
该文件2023年3月份部分内容如下:
[全部成交]
000572 full
000725 full
[分笔成交]
分成两笔:
000002 lot 2
[部分成交] 成交一半
000001 part
000004 part
...
[挂单] 只有响应,没有成交
018014 pending
020417 pending
...
[拒单]
000010 reject
010609 reject
[拒绝撤单] 部分成交,不可撤单
000008 cancel_reject
000151 cancel_reject
如果您在使用本模块中需要帮助,或者需要参加《大富翁量化编程实战课》学习,请添加 宽粉 的微信: