Skip to content

Commit 29aaec0

Browse files
committed
Manage JoinQuant following in scheduler script
1 parent 57dbd2b commit 29aaec0

File tree

8 files changed

+140
-149
lines changed

8 files changed

+140
-149
lines changed

README.rst

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,24 @@ ShiPanE-Python-SDK
88
| 详情见:http://www.iguuu.com/e
99
| 交流QQ群:11527956 |实盘易-股票自动交易|
1010
11-
自动新股申购
12-
------------
11+
功能介绍
12+
--------
1313

14-
一. Windows
15-
~~~~~~~~~~~~
14+
- 简单的实盘易 HTTP API 封装,见 shipane_sdk/client.py
15+
- 多账号自动新股申购(自动打新)
16+
- 聚宽集成
17+
18+
定时任务调度
19+
--------------
20+
21+
- 多账号自动新股申购(自动打新)
22+
- 聚宽跟单(抓取方式)
23+
24+
安装
25+
~~~~
26+
27+
Windows
28+
^^^^^^^
1629

1730
- 安装 Python 3.5(建议安装 Anaconda3)
1831
- cmd 中运行:pip install --no-binary shipane_sdk shipane_sdk
@@ -21,15 +34,25 @@ ShiPanE-Python-SDK
2134
- 找到 python 安装目录,例如:C:\\Program Files\\Anaconda3
2235
- cmd 下执行(具体路径自行修改):python "C:\\Program Files\\Anaconda3\\Scripts\\shipane-scheduler.py"
2336

24-
二. Mac/Linux
25-
~~~~~~~~~~~~~
37+
Mac/Linux
38+
^^^^^^^^^
2639

2740
- 安装 Python 3.5
2841
- terminal 中运行:pip install --no-binary shipane_sdk shipane_sdk
2942
- terminal 中运行:cp -n ~/.shipane_sdk/config/scheduler-example.ini ~/.shipane_sdk/config/scheduler.ini
3043
- 修改 ~/.shipane_sdk/config/scheduler.ini
3144
- terminal 中运行:shipane-scheduler.py
3245

46+
升级
47+
~~~~~
48+
49+
pip install --upgrade --no-deps --no-binary shipane_sdk shipane_sdk
50+
51+
配置
52+
~~~~~
53+
54+
定时任务默认禁用;如需启动,请设置 enabled=true
55+
3356
聚宽集成
3457
--------
3558

@@ -48,11 +71,9 @@ ShiPanE-Python-SDK
4871
步骤
4972
^^^^
5073

51-
- 将 shipane\_sdk/client.py 上传至聚宽“投资研究”根目录,并重命名为
52-
shipane\_sdk.py。
74+
- 将 shipane\_sdk/client.py 上传至聚宽“投资研究”根目录,并重命名为 shipane\_sdk.py。
5375
- 将 shipane\_sdk/joinquant/executor.py 追加到 shpane\_sdk.py 中。
54-
- 用法请参考 examples/joinquant/simple\_strategy.py (注意将其中的
55-
xxx.xxx.xxx.xxx 替换为实际 IP)。
76+
- 用法请参考 examples/joinquant/simple\_strategy.py (注意将其中的 xxx.xxx.xxx.xxx 替换为实际 IP)。
5677

5778
二. 抓取方式
5879
~~~~~~~~~~~~
@@ -68,11 +89,7 @@ ShiPanE-Python-SDK
6889
步骤
6990
^^^^
7091

71-
- git clone 或下载项目到本地。
72-
- 安装必要的依赖 "pip install requests"。
73-
- 参考 examples/joinquant/config/config.ini.template 创建
74-
examples/joinquant/config/config.ini,并完善配置。
75-
- 命令行运行 "python ./examples/joinquant/simple\_runner.py"。
92+
见 `定时任务调度 <#定时任务调度>`__
7693

7794
其他语言 SDK
7895
------------

config/scheduler-example.ini

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
; schedule 参数设置,类似于 cron 表达式
2+
;
3+
; 格式为:[秒(0-59)] [分(0-59)] [时(0-23)] [星期几(0-6 或英文缩写)] [星期(1-53)] [日(1-31)] [月(1-12)] [年(四位数字)]
4+
; (星期几英文缩写:mon,tue,wed,thu,fri,sat,sun)
5+
;
6+
; 字段支持表达式:
7+
; - * 为任意单位时间触发
8+
; - */a 为每 a 个单位时间触发
9+
; - a-b 为 a 到 b 的区间触发
10+
; - a-b/c 为 a 到 b 的区间每 c 个单位时间触发
11+
;
12+
; 详见:https://apscheduler.readthedocs.io/en/v2.1.2/cronschedule.html
13+
;
14+
115
;
216
; 实盘易配置
317
;
@@ -21,23 +35,25 @@ client2=title:guotai
2135
; 是否启用?
2236
enabled=false
2337

24-
; 触发时间设置,类似于 cron 表达式
25-
;
26-
; 格式为:[秒(0-59)] [分(0-59)] [时(0-23)] [星期几(0-6 或英文缩写)] [星期(1-53)] [日(1-31)] [月(1-12)] [年(四位数字)]
27-
; (星期几英文缩写:mon,tue,wed,thu,fri,sat,sun)
28-
;
29-
; 字段支持表达式:
30-
; - * 为任意单位时间触发
31-
; - */a 为每 a 个单位时间触发
32-
; - a-b 为 a 到 b 的区间触发
33-
; - a-b/c 为 a 到 b 的区间每 c 个单位时间触发
34-
;
35-
; 详见:https://apscheduler.readthedocs.io/en/v2.1.2/cronschedule.html
36-
;
3738
; 默认设置为:星期一至星期五中午十二点
38-
;
3939
schedule=0 0 12 mon-fri * * * *
4040

4141
; 需要自动新股申购的交易客户端列表,以,(半角逗号)分割
4242
; clients=client1,client2
4343
clients=client1
44+
45+
[JoinQuant]
46+
username=
47+
password=
48+
49+
; 模拟交易 URL 中 backtestId= 后面的那串字符
50+
; 例如,模拟交易 URL 为:https://www.joinquant.com/algorithm/live/index?backtestId=c215e5e57b30a65df4139bfff8c90e99
51+
; 则此处填写:c215e5e57b30a65df4139bfff8c90e99
52+
backtest_id=
53+
54+
; 是否启用?
55+
enabled=false
56+
57+
;
58+
; 默认设置为:星期一至星期五 9:00 到 15:00 每分钟的第 30 秒
59+
schedule=30 */1 9-15 mon-fri * * * *

examples/joinquant/config/config.ini.template

Lines changed: 0 additions & 11 deletions
This file was deleted.

examples/joinquant/simple_runner.py

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import logging
4+
from datetime import datetime
5+
6+
from shipane_sdk.joinquant.client import JoinQuantClient
7+
from shipane_sdk.joinquant.transaction import JoinQuantTransaction
8+
from shipane_sdk.market_utils import MarketUtils
9+
10+
11+
class JoinQuantFollowingJob(object):
12+
def __init__(self, config, client):
13+
self._log = logging.getLogger()
14+
self._config = config
15+
self._client = client
16+
self._jq_client = JoinQuantClient(username=self._config.get('JoinQuant', 'username'),
17+
password=self._config.get('JoinQuant', 'password'),
18+
backtest_id=self._config.get('JoinQuant', 'backtest_id'))
19+
self._jq_client.login()
20+
self._start_datatime = datetime.now()
21+
self._processed_transactions = []
22+
23+
def __call__(self):
24+
if MarketUtils.is_closed():
25+
self._log.warning("********** 休市期间不跟单 **********")
26+
if self._processed_transactions:
27+
del self._processed_transactions[:]
28+
return
29+
30+
self._log.info("********** 开始跟单 **********")
31+
try:
32+
transaction_detail = self._jq_client.query()
33+
raw_transactions = transaction_detail['data']['transaction']
34+
self._log.info("获取到 {} 条委托".format(len(raw_transactions)))
35+
36+
transactions = []
37+
for raw_transaction in raw_transactions:
38+
transaction = JoinQuantTransaction(raw_transaction).normalize()
39+
if self._is_expired(transaction):
40+
continue
41+
42+
transactions.append(transaction)
43+
self._log.info("获取到 {} 条有效委托".format(len(transactions)))
44+
45+
for tx in transactions:
46+
self._processed_transactions.append(tx)
47+
self._log.info("开始以 {}元 {} {}股 {}".format(tx.price, tx.get_cn_type(), tx.amount, tx.symbol))
48+
response = self._shipane_client.execute(None,
49+
action=tx.type,
50+
symbol=tx.symbol,
51+
type='LIMIT',
52+
price=tx.price,
53+
amount=tx.amount)
54+
if response is not None:
55+
self._log.info(u'实盘易回复:\nstatus_code: %d\ntext: %s', response.status_code, response.text)
56+
else:
57+
self._log.error('实盘易未回复')
58+
except Exception as e:
59+
self._log.exception("跟单异常")
60+
self._log.info("********** 结束跟单 **********\n")
61+
62+
def _is_expired(self, transaction):
63+
if transaction.completed_at < self._start_datatime:
64+
return True
65+
if transaction in self._processed_transactions:
66+
return True
67+
return False

shipane_sdk/joinquant/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def login(self):
3232
'ajax': 1
3333
})
3434
self._session.headers.update({
35-
'cookie': response.headers['set-Cookie']
35+
'cookie': response.headers['Set-Cookie']
3636
})
3737

3838
def query(self):

shipane_sdk/joinquant/runner.py

Lines changed: 0 additions & 71 deletions
This file was deleted.

shipane_sdk/scheduler.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from shipane_sdk import Client
1313
from shipane_sdk.ap import APCronParser
14+
from shipane_sdk.jobs.joinquant_following import JoinQuantFollowingJob
1415
from shipane_sdk.jobs.new_stock_purchase import NewStockPurchaseJob
1516

1617
if six.PY2:
@@ -34,13 +35,22 @@ def __init__(self):
3435
key=self._config.get('ShiPanE', 'key'))
3536

3637
self._new_stock_purchase_job = NewStockPurchaseJob(self._config, self._client)
38+
self._joinquant_following_job = JoinQuantFollowingJob(self._config, self._client)
3739

3840
def start(self):
3941
scheduler = BackgroundScheduler()
4042

4143
if self._config.getboolean('NewStocks', 'enabled'):
4244
scheduler.add_job(self._new_stock_purchase_job,
4345
APCronParser.parse(self._config.get('NewStocks', 'schedule')))
46+
else:
47+
self._log.warning('New stock purchase job is not enabled')
48+
49+
if self._config.getboolean('JoinQuant', 'enabled'):
50+
scheduler.add_job(self._joinquant_following_job,
51+
APCronParser.parse(self._config.get('JoinQuant', 'schedule')))
52+
else:
53+
self._log.warning('JoinQuant following job is not enabled')
4454

4555
scheduler.start()
4656
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))

0 commit comments

Comments
 (0)