Skip to content

Commit a803466

Browse files
author
gaoan
committed
mod: add margin and short fee for contract
1 parent 6e60c07 commit a803466

File tree

7 files changed

+143
-34
lines changed

7 files changed

+143
-34
lines changed

setup.py

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

1111
setup(
1212
name='tigeropen',
13-
version='1.1.6',
13+
version='1.1.7',
1414
description='TigerBrokers Open API',
1515
packages=find_packages(exclude=[]),
1616
author='TigerBrokers',

tigeropen/examples/push_client_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def on_position_changed(account, items):
6161
# time.sleep(t)
6262
# else:
6363
# print('reconnect success')
64-
# break
64+
# return
6565
# print('reconnect failed, please check your network')
6666
#
6767

tigeropen/push/push_client.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,41 @@
2121
}
2222
QUOTE_KEYS_MAPPINGS = {field.value: field.name for field in QuoteChangeKey} # like {'askPrice': 'ask_price'}
2323
QUOTE_KEYS_MAPPINGS.update(HOUR_TRADING_QUOTE_KEYS_MAPPINGS)
24+
PRICE_FIELDS = {'open', 'high', 'low', 'close', 'prev_close', 'ask_price', 'bid_price', 'latest_price'}
2425

2526
ASSET_KEYS_MAPPINGS = {'buyingPower': 'buying_power', 'cashBalance': 'cash',
2627
'grossPositionValue': 'gross_position_value',
2728
'netLiquidation': 'net_liquidation', 'equityWithLoan': 'equity_with_loan',
2829
'initMarginReq': 'initial_margin_requirement',
2930
'maintMarginReq': 'maintenance_margin_requirement',
3031
'availableFunds': 'available_funds', 'excessLiquidity': 'excess_liquidity',
31-
'dayTradesRemaining': 'day_trades_remaining', 'currency': 'currency'}
32+
'dayTradesRemaining': 'day_trades_remaining', 'currency': 'currency', 'segment': 'segment'}
3233

3334
POSITION_KEYS_MAPPINGS = {'averageCost': 'average_cost', 'position': 'quantity', 'latestPrice': 'market_price',
3435
'marketValue': 'market_value', 'orderType': 'order_type', 'realizedPnl': 'realized_pnl',
3536
'unrealizedPnl': 'unrealized_pnl', 'secType': 'sec_type', 'localSymbol': 'local_symbol',
3637
'originSymbol': 'origin_symbol', 'contractId': 'contract_id', 'symbol': 'symbol',
37-
'currency': 'currency', 'strike': 'strike', 'expiry': 'expiry', 'right': 'right'}
38+
'currency': 'currency', 'strike': 'strike', 'expiry': 'expiry', 'right': 'right',
39+
'segment': 'segment'}
3840

3941
ORDER_KEYS_MAPPINGS = {'parentId': 'parent_id', 'orderId': 'order_id', 'orderType': 'order_type',
4042
'limitPrice': 'limit_price', 'auxPrice': 'aux_price', 'avgFillPrice': 'avg_fill_price',
4143
'totalQuantity': 'quantity', 'filledQuantity': 'filled', 'lastFillPrice': 'last_fill_price',
42-
'realizedPnl': 'realized_pnl', 'secType': 'sec_type',
44+
'realizedPnl': 'realized_pnl', 'secType': 'sec_type', 'symbol': 'symbol',
4345
'remark': 'reason', 'localSymbol': 'local_symbol', 'originSymbol': 'origin_symbol',
4446
'outsideRth': 'outside_rth', 'timeInForce': 'time_in_force', 'openTime': 'order_time',
4547
'latestTime': 'trade_time', 'contractId': 'contract_id', 'trailStopPrice': 'trail_stop_price',
4648
'trailingPercent': 'trailing_percent', 'percentOffset': 'percent_offset', 'action': 'action',
47-
'status': 'status', 'currency': 'currency', 'remaining': 'remaining', 'id': 'id'}
49+
'status': 'status', 'currency': 'currency', 'remaining': 'remaining', 'id': 'id',
50+
'segment': 'segment'}
4851

4952
if sys.platform == 'linux' or sys.platform == 'linux2':
5053
KEEPALIVE = True
5154
else:
5255
KEEPALIVE = False
5356

5457

55-
class PushClient(object):
58+
class PushClient(stomp.ConnectionListener):
5659
def __init__(self, host, port, use_ssl=True, connection_timeout=120, auto_reconnect=True,
5760
heartbeats=(30 * 1000, 30 * 1000)):
5861
"""
@@ -155,12 +158,34 @@ def on_message(self, headers, body):
155158
hour_trading = True
156159
if 'symbol' in data:
157160
symbol = data.get('symbol')
161+
offset = data.get('offset', 0)
158162
items = []
159-
for key, value in data.items():
160-
if (key == 'latestTime' or key == 'hourTradingLatestTime') and isinstance(value, six.string_types):
161-
continue
162-
if key in QUOTE_KEYS_MAPPINGS:
163-
items.append((QUOTE_KEYS_MAPPINGS.get(key), value))
163+
# 期货行情推送的价格都乘了 10 的 offset 次方变成了整数, 需要除回去变为正常单位的价格
164+
if offset:
165+
for key, value in data.items():
166+
if (key == 'latestTime' or key == 'hourTradingLatestTime') and \
167+
isinstance(value, six.string_types):
168+
continue
169+
if key in QUOTE_KEYS_MAPPINGS:
170+
key = QUOTE_KEYS_MAPPINGS.get(key)
171+
if key in PRICE_FIELDS:
172+
value /= 10 ** offset
173+
elif key == 'minute':
174+
minute_item = dict()
175+
for m_key, m_value in value.items():
176+
if m_key in {'p', 'h', 'l'}:
177+
m_value /= 10 ** offset
178+
minute_item[m_key] = m_value
179+
value = minute_item
180+
items.append((key, value))
181+
else:
182+
for key, value in data.items():
183+
if (key == 'latestTime' or key == 'hourTradingLatestTime') and \
184+
isinstance(value, six.string_types):
185+
continue
186+
if key in QUOTE_KEYS_MAPPINGS:
187+
key = QUOTE_KEYS_MAPPINGS.get(key)
188+
items.append((key, value))
164189
if items:
165190
self.quote_changed(symbol, items, hour_trading)
166191
elif response_type == str(ResponseType.SUBSCRIBE_ASSET.value):

tigeropen/tiger_open_config.py

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,31 @@
55
@author: gaoan
66
"""
77
from tigeropen.common.consts import Language
8+
from tigeropen.common.util.signature_utils import read_private_key
9+
10+
# 老虎证券开放平台网关地址
11+
SERVER_URL = 'https://openapi.itiger.com/gateway'
12+
# 老虎证券开放平台 socket 连接域名端口
13+
SOCKET_HOST_PORT = ('ssl', 'openapi.itiger.com', 8883)
14+
# 老虎证券开放平台公钥
15+
TIGER_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNF3G8SoEcCZh2rshUbayDgLLrj6rKgzNMxDL2HS' \
16+
'nKcB0+GPOsndqSv+a4IBu9+I3fyBp5hkyMMG2+AXugd9pMpy6VxJxlNjhX1MYbNTZJUT4nudki4uh+LM' \
17+
'OkIBHOceGNXjgB+cXqmlUnjlqha/HgboeHSnSgpM3dKSJQlIOsDwIDAQAB'
18+
# 请求签名类型
19+
SIGN_TYPE = 'RSA'
20+
# 请求字符集
21+
CHARSET = 'UTF-8'
22+
# 语言
23+
LANGUAGE = Language.zh_CN
24+
# 请求超时时间, 单位秒, 默认15s
25+
TIMEOUT = 15
26+
27+
# sandbox 环境配置
28+
SANDBOX_SERVER_URL = 'https://openapi-sandbox.itiger.com/gateway'
29+
SANDBOX_SOCKET_HOST_PORT = ('ssl', 'openapi-sandbox.itiger.com', 8885)
30+
SANDBOX_TIGER_PUBLIC_KEY = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbm21i11hgAENGd3/f280PSe4g9YGkS3TEXBY' \
31+
'MidihTvHHf+tJ0PYD0o3PruI0hl3qhEjHTAxb75T5YD3SGK4IBhHn/Rk6mhqlGgI+bBrBVYaXixm' \
32+
'HfRo75RpUUuWACyeqQkZckgR0McxuW9xRMIa2cXZOoL1E4SL4lXKGhKoWbwIDAQAB'
833

934

1035
class TigerOpenClientConfig(object):
@@ -17,33 +42,29 @@ def __init__(self, sandbox_debug=False):
1742
self._standard_account = ''
1843
# 模拟账户
1944
self._paper_account = ''
20-
# 请求签名类型,推荐RSA2
21-
self._sign_type = 'RSA'
2245
# 开发者应用私钥
2346
self._private_key = ''
24-
47+
# 请求签名类型,推荐RSA2
48+
self._sign_type = SIGN_TYPE
49+
2550
# 老虎证券开放平台网关地址
26-
self._server_url = "https://openapi.itiger.com/gateway"
27-
self._socket_host_port = ('ssl', 'openapi.itiger.com', 8883)
51+
self._server_url = SERVER_URL
52+
self._socket_host_port = SOCKET_HOST_PORT
2853
# 老虎证券开放平台公钥
29-
self._tiger_public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNF3G8SoEcCZh2rshUbayDgLLrj6rKgzNMxDL2HS' \
30-
'nKcB0+GPOsndqSv+a4IBu9+I3fyBp5hkyMMG2+AXugd9pMpy6VxJxlNjhX1MYbNTZJUT4nudki4uh+LM' \
31-
'OkIBHOceGNXjgB+cXqmlUnjlqha/HgboeHSnSgpM3dKSJQlIOsDwIDAQAB'
54+
self._tiger_public_key = TIGER_PUBLIC_KEY
3255

3356
if sandbox_debug:
34-
self._server_url = "https://openapi-sandbox.itiger.com/gateway"
35-
self._socket_host_port = ('ssl', 'openapi-sandbox.itiger.com', 8885)
36-
self._tiger_public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbm21i11hgAENGd3/f280PSe4g9YGkS3TEXBY' \
37-
'MidihTvHHf+tJ0PYD0o3PruI0hl3qhEjHTAxb75T5YD3SGK4IBhHn/Rk6mhqlGgI+bBrBVYaXixm' \
38-
'HfRo75RpUUuWACyeqQkZckgR0McxuW9xRMIa2cXZOoL1E4SL4lXKGhKoWbwIDAQAB'
39-
# 请求字符集,默认utf-8
40-
self._charset = 'UTF-8'
57+
self._server_url = SANDBOX_SERVER_URL
58+
self._socket_host_port = SANDBOX_SOCKET_HOST_PORT
59+
self._tiger_public_key = SANDBOX_TIGER_PUBLIC_KEY
60+
# 请求字符集,默认utf-8
61+
self._charset = CHARSET
4162
# 语言
42-
self._language = Language.zh_CN
63+
self._language = LANGUAGE
4364

44-
## 以下为可选参数
65+
# 以下为可选参数
4566
# 请求读取超时,单位秒,默认15s
46-
self._timeout = 15
67+
self._timeout = TIMEOUT
4768

4869
@property
4970
def tiger_id(self):
@@ -140,3 +161,46 @@ def timeout(self):
140161
@timeout.setter
141162
def timeout(self, value):
142163
self._timeout = value
164+
165+
166+
def get_client_config(private_key_path, tiger_id, account, standard_account=None, paper_account=None,
167+
sandbox_debug=False, sign_type=None, timeout=None, language=None, charset=None,
168+
server_url=None, socket_host_port=None):
169+
"""
170+
生成客户端配置
171+
:param private_key_path: 私钥文件路径, 如 '/Users/tiger/.ssh/rsa_private_key.pem'
172+
:param tiger_id: 开发者应用 id
173+
:param account: 授权账户 (必填. 作为发送请求时的默认账户)
174+
:param standard_account:
175+
:param paper_account:
176+
:param sandbox_debug: 是否请求 sandbox 环境
177+
:param sign_type: 签名类型
178+
:param timeout: 请求超时时间, 单位秒
179+
:param language: 语言, 取值为 tigeropen.common.consts.Language 中的枚举类型
180+
:param charset: 字符集编码
181+
:param server_url: 网关地址
182+
:param socket_host_port: 推送长连接的域名端口, 值为协议, 域名, 端口构成的三元组
183+
:return:
184+
"""
185+
config = TigerOpenClientConfig(sandbox_debug=sandbox_debug)
186+
config.private_key = read_private_key(private_key_path)
187+
config.tiger_id = tiger_id
188+
config.account = account
189+
if standard_account:
190+
config.standard_account = standard_account
191+
if paper_account:
192+
config.paper_account = paper_account
193+
if sign_type:
194+
config.sign_type = sign_type
195+
if timeout:
196+
config.timeout = timeout
197+
if language:
198+
config.language = language
199+
if charset:
200+
config.charset = charset
201+
if server_url:
202+
config.server_url = server_url
203+
if socket_host_port:
204+
config.socket_host_port = socket_host_port
205+
return config
206+

tigeropen/trade/domain/contract.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
class Contract(object):
1010
def __init__(self, symbol, currency, contract_id=None, sec_type=None, exchange=None, origin_symbol=None,
11-
local_symbol=None, expiry=None, strike=None, put_call=None, multiplier=None, name=None):
11+
local_symbol=None, expiry=None, strike=None, put_call=None, multiplier=None, name=None,
12+
short_margin=None, short_fee_rate=None, shortable=None, long_initial_margin=None,
13+
long_maintenance_margin=None):
1214
self.contract_id = contract_id
1315
self.symbol = symbol
1416
self.currency = currency
@@ -21,6 +23,11 @@ def __init__(self, symbol, currency, contract_id=None, sec_type=None, exchange=N
2123
self.put_call = put_call
2224
self.multiplier = multiplier
2325
self.name = name
26+
self.short_margin = short_margin
27+
self.short_fee_rate = short_fee_rate
28+
self.shortable = shortable
29+
self.long_initial_margin = long_initial_margin
30+
self.long_maintenance_margin = long_maintenance_margin
2431

2532
def __repr__(self):
2633
if self.symbol:

tigeropen/trade/response/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
"""
77

88
CONTRACT_FIELDS = set(['symbol', 'market', 'multiplier', 'sec_type', 'currency', 'local_symbol', 'origin_symbol',
9-
'expiry', 'strike', 'right', 'contract_id', 'exchange', 'name'])
9+
'expiry', 'strike', 'right', 'contract_id', 'exchange', 'name', 'short_margin', 'short_fee_rate',
10+
'shortable', 'long_initial_margin', 'long_maintenance_margin'])
1011

tigeropen/trade/response/contracts_response.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
from tigeropen.trade.response import CONTRACT_FIELDS
1313

1414
CONTRACT_FIELD_MAPPINGS = {'secType': 'sec_type', 'localSymbol': 'local_symbol', 'originSymbol': 'origin_symbol',
15-
'conid': 'contract_id', 'contractId': 'contract_id', 'lastTradingDate': 'expiry'}
15+
'conid': 'contract_id', 'contractId': 'contract_id', 'lastTradingDate': 'expiry',
16+
'shortMargin': 'short_margin', 'shortFeeRate': 'short_fee_rate',
17+
'longInitialMargin': 'long_initial_margin',
18+
'longMaintenanceMargin': 'long_maintenance_margin'}
1619

1720

1821
class ContractsResponse(TigerResponse):
@@ -52,7 +55,16 @@ def parse_response_content(self, response_content):
5255
put_call = contract_fields.get('right')
5356
multiplier = contract_fields.get('multiplier')
5457
name = contract_fields.get('name')
58+
short_margin = contract_fields.get('short_margin')
59+
short_fee_rate = contract_fields.get('short_fee_rate')
60+
shortable = contract_fields.get('shortable')
61+
long_initial_margin = contract_fields.get('long_initial_margin')
62+
long_maintenance_margin = contract_fields.get('long_maintenance_margin')
63+
5564
contract = Contract(symbol, currency, contract_id=contract_id, sec_type=sec_type, exchange=exchange,
5665
origin_symbol=origin_symbol, local_symbol=local_symbol, expiry=expiry,
57-
strike=strike, put_call=put_call, multiplier=multiplier, name=name)
66+
strike=strike, put_call=put_call, multiplier=multiplier, name=name,
67+
short_margin=short_margin, short_fee_rate=short_fee_rate, shortable=shortable,
68+
long_initial_margin=long_initial_margin,
69+
long_maintenance_margin=long_maintenance_margin)
5870
self.contracts.append(contract)

0 commit comments

Comments
 (0)