forked from hhuhhu/trade
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi_future.py
More file actions
295 lines (237 loc) · 9.58 KB
/
api_future.py
File metadata and controls
295 lines (237 loc) · 9.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# -*- coding: utf-8 -*-
#
# Copyright 2017 Ricequant, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
'''
更多描述请见
https://www.ricequant.com/api/python/chn
'''
from __future__ import division
import six
import numpy as np
from api.api_base import decorate_api_exc, instruments
from execution_context import ExecutionContext
from environment import Environment
from model.order import Order, MarketOrder, LimitOrder, OrderStyle
from const import EXECUTION_PHASE, SIDE, POSITION_EFFECT, ORDER_TYPE
from model.instrument import Instrument
from utils.exception import RQInvalidArgument
from utils.logger import user_system_log
from utils.i18n import gettext as _
from utils.arg_checker import apply_rules, verify_that
__all__ = [
]
def export_as_api(func):
__all__.append(func.__name__)
func = decorate_api_exc(func)
return func
def smart_order(order_book_id, quantity, style):
position = Environment.get_instance().portfolio.positions[order_book_id]
orders = []
if quantity > 0:
# 平昨仓
if position.sell_old_quantity > 0:
orders.append(order(
order_book_id,
min(quantity, position.sell_old_quantity),
SIDE.BUY,
POSITION_EFFECT.CLOSE,
style
))
quantity -= position.sell_old_quantity
if quantity <= 0:
return orders
# 平今仓
if position.sell_today_quantity > 0:
orders.append(order(
order_book_id,
min(quantity, position.sell_today_quantity),
SIDE.BUY,
POSITION_EFFECT.CLOSE_TODAY,
style
))
quantity -= position.sell_today_quantity
if quantity <= 0:
return orders
# 开多仓
orders.append(order(
order_book_id,
quantity,
SIDE.BUY,
POSITION_EFFECT.OPEN,
style
))
return orders
else:
# 平昨仓
quantity *= -1
if position.buy_old_quantity > 0:
order.append(order(
order_book_id,
min(quantity, position.buy_old_quantity),
SIDE.SELL,
POSITION_EFFECT.CLOSE,
style
))
quantity -= position.buy_old_quantity
if quantity <= 0:
return orders
# 平今仓
if position.buy_today_quantity > 0:
orders.append(order(
order_book_id,
min(quantity, position.buy_today_quantity),
SIDE.SELL,
POSITION_EFFECT.CLOSE_TODAY,
style
))
quantity -= position.buy_today_quantity
if quantity <= 0:
return orders
# 开空仓
orders.append(order(
order_book_id,
quantity,
SIDE.SELL,
POSITION_EFFECT.OPEN,
style
))
return orders
@ExecutionContext.enforce_phase(EXECUTION_PHASE.ON_BAR,
EXECUTION_PHASE.ON_TICK,
EXECUTION_PHASE.SCHEDULED)
@apply_rules(verify_that('id_or_ins').is_valid_future(),
verify_that('amount').is_greater_than(0),
verify_that('side').is_in([SIDE.BUY, SIDE.SELL]),
verify_that('position_effect').is_in([POSITION_EFFECT.OPEN, POSITION_EFFECT.CLOSE]),
verify_that('style').is_instance_of((LimitOrder, MarketOrder)))
def order(id_or_ins, amount, side, position_effect, style):
if not isinstance(style, OrderStyle):
raise RuntimeError
if amount <= 0:
raise RuntimeError
if isinstance(style, LimitOrder) and style.get_limit_price() <= 0:
raise RQInvalidArgument(_(u"Limit order price should be positive"))
order_book_id = assure_future_order_book_id(id_or_ins)
env = Environment.get_instance()
price = env.get_last_price(order_book_id)
if np.isnan(price):
user_system_log.warn(
_(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id))
return
amount = int(amount)
r_order = Order.__from_create__(env.calendar_dt, env.trading_dt, order_book_id, amount, side, style,
position_effect)
if np.isnan(price) or price == 0:
user_system_log.warn(
_(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id))
r_order.mark_rejected(
_(u"Order Creation Failed: [{order_book_id}] No market data").format(order_book_id=order_book_id))
return r_order
if r_order.type == ORDER_TYPE.MARKET:
r_order.set_frozen_price(price)
if env.can_submit_order(r_order):
env.broker.submit_order(r_order)
return r_order
@export_as_api
def buy_open(id_or_ins, amount, style=MarketOrder()):
"""
买入开仓。
:param id_or_ins: 下单标的物
:type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]
:param int amount: 下单手数
:param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
:type style: `OrderStyle` object
:return: :class:`~Order` object
:example:
.. code-block:: python
#以价格为3500的限价单开仓买入2张上期所AG1607合约:
buy_open('AG1607', amount=2, style=LimitOrder(3500))
"""
return order(id_or_ins, amount, SIDE.BUY, POSITION_EFFECT.OPEN, style)
@export_as_api
def buy_close(id_or_ins, amount, style=MarketOrder()):
"""
平卖仓
:param id_or_ins: 下单标的物
:type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]
:param int amount: 下单手数
:param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
:type style: `OrderStyle` object
:return: :class:`~Order` object
:example:
.. code-block:: python
#市价单将现有IF1603空仓买入平仓2张:
buy_close('IF1603', 2)
"""
return order(id_or_ins, amount, SIDE.BUY, POSITION_EFFECT.CLOSE, style)
@export_as_api
def sell_open(id_or_ins, amount, style=MarketOrder()):
"""
卖出开仓
:param id_or_ins: 下单标的物
:type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]
:param int amount: 下单手数
:param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
:type style: `OrderStyle` object
:return: :class:`~Order` object
"""
return order(id_or_ins, amount, SIDE.SELL, POSITION_EFFECT.OPEN, style)
@export_as_api
def sell_close(id_or_ins, amount, style=MarketOrder()):
"""
平买仓
:param id_or_ins: 下单标的物
:type id_or_ins: :class:`~Instrument` object | `str` | List[:class:`~Instrument`] | List[`str`]
:param int amount: 下单手数
:param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`
:type style: `OrderStyle` object
:return: :class:`~Order` object
"""
return order(id_or_ins, amount, SIDE.SELL, POSITION_EFFECT.CLOSE, style)
def assure_future_order_book_id(id_or_symbols):
if isinstance(id_or_symbols, Instrument):
if id_or_symbols.type != "Future":
raise RQInvalidArgument(
_(u"{order_book_id} is not supported in current strategy type").format(
order_book_id=id_or_symbols.order_book_id))
else:
return id_or_symbols.order_book_id
elif isinstance(id_or_symbols, six.string_types):
return assure_future_order_book_id(instruments(id_or_symbols))
else:
raise RQInvalidArgument(_(u"unsupported order_book_id type"))
@export_as_api
@ExecutionContext.enforce_phase(EXECUTION_PHASE.ON_INIT,
EXECUTION_PHASE.BEFORE_TRADING,
EXECUTION_PHASE.ON_BAR,
EXECUTION_PHASE.ON_TICK,
EXECUTION_PHASE.AFTER_TRADING,
EXECUTION_PHASE.SCHEDULED)
@apply_rules(verify_that('underlying_symbol').is_instance_of(str))
def get_future_contracts(underlying_symbol):
"""
获取某一期货品种在策略当前日期的可交易合约order_book_id列表。按照到期月份,下标从小到大排列,返回列表中第一个合约对应的就是该品种的近月合约。
:param str underlying_symbol: 期货合约品种,例如沪深300股指期货为'IF'
:return: list[`str`]
:example:
获取某一天的主力合约代码(策略当前日期是20161201):
.. code-block:: python
[In]
logger.info(get_future_contracts('IF'))
[Out]
['IF1612', 'IF1701', 'IF1703', 'IF1706']
"""
env = Environment.get_instance()
return env.data_proxy.get_future_contracts(underlying_symbol, env.trading_dt)