Skip to content

Commit 69853ba

Browse files
committed
Support RiceQuant following
1 parent f05c5c2 commit 69853ba

File tree

12 files changed

+215
-5
lines changed

12 files changed

+215
-5
lines changed

README.rst

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ ShiPanE-Python-SDK
1313

1414
- 简单的实盘易 HTTP API 封装,见 shipane_sdk/client.py
1515
- 多账号自动新股申购(自动打新)
16-
- 聚宽集成
16+
- 聚宽(JoinQuant)集成
17+
- 米筐(RiceQuant)集成
1718

1819
定时任务调度
1920
--------------
2021

2122
- 多账号自动新股申购(自动打新)
22-
- 聚宽跟单(抓取方式)
23+
- 聚宽(JoinQuant)自动跟单(抓取方式)
24+
- 米筐(RiceQuant)自动跟单(抓取方式)
2325

2426
安装
2527
~~~~
@@ -53,8 +55,8 @@ pip install --upgrade --no-deps --no-binary shipane_sdk shipane_sdk
5355

5456
定时任务默认禁用;如需启动,请设置 enabled=true
5557

56-
聚宽集成
57-
--------
58+
聚宽(JoinQuant)集成
59+
---------------------
5860

5961
一. 推送方式
6062
~~~~~~~~~~~~
@@ -91,6 +93,30 @@ pip install --upgrade --no-deps --no-binary shipane_sdk shipane_sdk
9193

9294
见 `定时任务调度 <#定时任务调度>`__
9395

96+
米筐(RiceQuant)集成
97+
---------------------
98+
99+
一. 推送方式
100+
~~~~~~~~~~~~
101+
102+
不支持。
103+
104+
二. 抓取方式
105+
~~~~~~~~~~~~
106+
107+
采用定时轮询的方式。
108+
109+
先决条件
110+
^^^^^^^^
111+
112+
- 部署实盘易成功。
113+
- 手动测试通过。
114+
115+
步骤
116+
^^^^
117+
118+
见 `定时任务调度 <#定时任务调度>`__
119+
94120
其他语言 SDK
95121
------------
96122

config/scheduler-example.ini

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,19 @@ enabled=false
5757
;
5858
; 默认设置为:星期一至星期五 9:00 到 15:00 每分钟的第 30 秒
5959
schedule=30 */1 9-15 mon-fri * * * *
60+
61+
[RiceQuant]
62+
username=
63+
password=
64+
65+
; 模拟交易 URL 中 最后一个 / 后面的那串字符
66+
; 例如,模拟交易 URL 为:https://www.ricequant.com/pt/454879/1226010
67+
; 则此处填写:1226010
68+
run_id=
69+
70+
; 是否启用?
71+
enabled=false
72+
73+
;
74+
; 默认设置为:星期一至星期五 9:00 到 15:00 每分钟的第 30 秒
75+
schedule=30 */1 9-15 mon-fri * * * *

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
4747

48-
install_requires=['requests', 'six', 'apscheduler', 'lxml', 'cssselect', 'bs4', 'html5lib', 'pandas'],
48+
install_requires=['requests', 'six', 'apscheduler', 'lxml', 'cssselect', 'bs4', 'html5lib', 'pandas', 'rqopen-client'],
4949

5050
extras_require={
5151
'dev': [],
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.market_utils import MarketUtils
7+
from shipane_sdk.ricequant.client import RiceQuantClient
8+
from shipane_sdk.ricequant.transaction import RiceQuantTransaction
9+
10+
11+
class RiceQuantFollowingJob(object):
12+
def __init__(self, config, client):
13+
self._log = logging.getLogger()
14+
self._config = config
15+
self._client = client
16+
self._rq_client = RiceQuantClient(username=self._config.get('RiceQuant', 'username'),
17+
password=self._config.get('RiceQuant', 'password'),
18+
run_id=self._config.get('RiceQuant', 'run_id'))
19+
self._rq_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._rq_client.query()
33+
raw_transactions = transaction_detail['resp']['trades']
34+
self._log.info("获取到 {} 条委托".format(len(raw_transactions)))
35+
36+
transactions = []
37+
for raw_transaction in raw_transactions:
38+
transaction = RiceQuantTransaction(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/ricequant/__init__.py

Whitespace-only changes.

shipane_sdk/ricequant/client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from rqopen_client import RQOpenClient
4+
5+
6+
class RiceQuantClient(object):
7+
def __init__(self, **kwargs):
8+
self._run_id = kwargs.pop('run_id')
9+
self._rq_client = RQOpenClient(kwargs.pop('username'), kwargs.pop('password'))
10+
11+
def login(self):
12+
self._rq_client.login()
13+
14+
def query(self):
15+
return self._rq_client.get_day_trades(self._run_id)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from datetime import datetime
4+
5+
from shipane_sdk.transaction import Transaction
6+
7+
8+
class RiceQuantTransaction(object):
9+
def __init__(self, json):
10+
self.__dict__.update(json)
11+
12+
def normalize(self):
13+
transaction = Transaction()
14+
transaction.completed_at = datetime.strptime(self.time, '%Y-%m-%d %H:%M:%S')
15+
transaction.action = 'BUY' if self.quantity > 0 else 'SELL'
16+
transaction.symbol = self.order_book_id
17+
transaction.price = self.price
18+
transaction.amount = abs(self.quantity)
19+
return transaction

shipane_sdk/scheduler.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from shipane_sdk.ap import APCronParser
1414
from shipane_sdk.jobs.joinquant_following import JoinQuantFollowingJob
1515
from shipane_sdk.jobs.new_stock_purchase import NewStockPurchaseJob
16+
from shipane_sdk.jobs.ricequant_following import RiceQuantFollowingJob
1617

1718
if six.PY2:
1819
ConfigParser = configparser.RawConfigParser
@@ -36,6 +37,7 @@ def __init__(self):
3637

3738
self._new_stock_purchase_job = NewStockPurchaseJob(self._config, self._client)
3839
self._joinquant_following_job = JoinQuantFollowingJob(self._config, self._client)
40+
self._ricequant_following_job = RiceQuantFollowingJob(self._config, self._client)
3941

4042
def start(self):
4143
scheduler = BackgroundScheduler()
@@ -52,6 +54,12 @@ def start(self):
5254
else:
5355
self._log.warning('JoinQuant following job is not enabled')
5456

57+
if self._config.getboolean('RiceQuant', 'enabled'):
58+
scheduler.add_job(self._ricequant_following_job,
59+
APCronParser.parse(self._config.get('RiceQuant', 'schedule')))
60+
else:
61+
self._log.warning('RiceQuant following job is not enabled')
62+
5563
scheduler.start()
5664
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
5765

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{"code": 200, "resp": {"name": "SVM大法好",
2+
"trades": [{"order_book_id": "600216.XSHG",
3+
"price": 12.77,
4+
"quantity": -100.0,
5+
"time": "2016-12-23 09:32:00",
6+
"trade_id": "2",
7+
"transaction_cost": 6.28}]}}

tests/shipane_sdk/ricequant/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)