Skip to content

Commit 56e3b9c

Browse files
authored
Merge pull request #44 from tigerfintech/feature_prime_assets
add TradeClient.get_prime_assets api
2 parents 3f81c1a + 906a764 commit 56e3b9c

File tree

8 files changed

+173
-2
lines changed

8 files changed

+173
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.4 (2021-12-08)
2+
### New
3+
- 综合/模拟账户查询资产接口 TradeClient.get_prime_assets
4+
15
## 2.0.3 (2021-12-01)
26
### New
37
- 期权链查询接口支持过滤 QuoteClient.get_option_chain

tigeropen/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
55
@author: gaoan
66
"""
7-
__VERSION__ = '2.0.3'
7+
__VERSION__ = '2.0.4'

tigeropen/common/consts/service_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"""
1717
ACCOUNTS = "accounts"
1818
ASSETS = "assets"
19+
PRIME_ASSETS = "prime_assets"
1920
POSITIONS = "positions"
2021
ORDERS = "orders"
2122
ACTIVE_ORDERS = "active_orders" # 待成交订单

tigeropen/common/util/string_utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,10 @@ def add_start_end(key, start_marker, end_marker):
1919

2020
def camel_to_underline(hunp_str):
2121
return re.sub(CAMEL_PATTERN, r'\1_\2', hunp_str).lower()
22+
23+
24+
def camel_to_underline_obj(d):
25+
if isinstance(d, list):
26+
return [camel_to_underline_obj(i) if isinstance(i, (dict, list)) else i for i in d]
27+
return {camel_to_underline(k): camel_to_underline_obj(v) if isinstance(v, (dict, list)) else v
28+
for k, v in d.items()}

tigeropen/examples/trade_client_demo.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ def get_account_apis():
6464
openapi_client.get_positions()
6565
# 获取资产
6666
openapi_client.get_assets()
67+
# 综合/模拟账户获取资产
68+
openapi_client.get_prime_assets()
6769

6870

6971
def trade_apis():
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# @Date : 2021/12/2
4+
# @Author : sukai
5+
MODEL_REPR = '{}({})'
6+
7+
8+
class PortfolioAccount:
9+
"""
10+
prime/paper account assets
11+
"""
12+
def __init__(self, account, update_timestamp=None):
13+
"""
14+
:param account:
15+
:param update_timestamp: asset update timestamp in milliseconds.
16+
"""
17+
self.account = account
18+
self.update_timestamp = update_timestamp
19+
self._segments = dict()
20+
21+
@property
22+
def segments(self):
23+
"""account information by contract type
24+
:return: dict with two keys, 'S' for stocks, 'C' for commodity futures;
25+
"""
26+
return self._segments
27+
28+
def add_segment(self, segment):
29+
if segment.category not in self._segments:
30+
self._segments[segment.category] = segment
31+
return segment
32+
else:
33+
return self._segments.get(segment.category)
34+
35+
def __repr__(self):
36+
d = {'account': self.account, 'update_timestamp': self.update_timestamp, 'segments': self.segments}
37+
return MODEL_REPR.format(self.__class__.__name__, d)
38+
39+
40+
class Segment:
41+
def __init__(self):
42+
self.currency = None
43+
self.capability = None
44+
self.category = None
45+
self.cash_balance = float('inf')
46+
self.cash_available_for_trade = float('inf')
47+
self.cash_available_for_withdrawal = float('inf')
48+
self.gross_position_value = float('inf')
49+
self.equity_with_loan = float('inf')
50+
self.net_liquidation = float('inf')
51+
self.init_margin = float('inf')
52+
self.maintain_margin = float('inf')
53+
self.overnight_margin = float('inf')
54+
self.unrealized_pl = float('inf')
55+
self.realized_pl = float('inf')
56+
self.excess_liquidation = float('inf')
57+
self.overnight_liquidation = float('inf')
58+
self.buying_power = float('inf')
59+
self.leverage = float('inf')
60+
self._currency_assets = dict()
61+
62+
@property
63+
def currency_assets(self):
64+
return self._currency_assets
65+
66+
def add_currency_asset(self, asset):
67+
if asset.currency not in self._currency_assets:
68+
self._currency_assets[asset.currency] = asset
69+
return asset
70+
else:
71+
return self._currency_assets.get(asset.currency)
72+
73+
def __repr__(self):
74+
d = {k: v for k, v in self.__dict__.items() if not k.startswith('_')}
75+
d['currency_assets'] = self.currency_assets
76+
return MODEL_REPR.format(self.__class__.__name__, d)
77+
78+
79+
class CurrencyAsset:
80+
def __init__(self):
81+
self.currency = None
82+
self.cash_balance = float('inf')
83+
self.cash_available_for_trade = float('inf')
84+
self.gross_position_value = float('inf')
85+
self.stock_market_value = float('inf')
86+
self.futures_market_value = float('inf')
87+
self.option_market_value = float('inf')
88+
self.unrealized_pl = float('inf')
89+
self.realized_pl = float('inf')
90+
91+
@staticmethod
92+
def from_dict(d):
93+
currency_asset = CurrencyAsset()
94+
currency_asset.__dict__.update(d)
95+
return currency_asset
96+
97+
def __repr__(self):
98+
return MODEL_REPR.format(self.__class__.__name__, self.__dict__)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# @Date : 2021/12/2
4+
# @Author : sukai
5+
6+
from tigeropen.common.response import TigerResponse
7+
from tigeropen.trade.domain.prime_account import PortfolioAccount, Segment, CurrencyAsset
8+
from tigeropen.common.util.string_utils import camel_to_underline, camel_to_underline_obj
9+
10+
11+
class PrimeAssetsResponse(TigerResponse):
12+
def __init__(self):
13+
super(PrimeAssetsResponse, self).__init__()
14+
self.assets = None
15+
self._is_success = None
16+
17+
def parse_response_content(self, response_content):
18+
response = super(PrimeAssetsResponse, self).parse_response_content(response_content)
19+
if 'is_success' in response:
20+
self._is_success = response['is_success']
21+
22+
if self.data:
23+
assets = PortfolioAccount(self.data.get('accountId'), self.data.get('updateTimestamp'))
24+
25+
for segment_data in self.data.get('segments', list()):
26+
segment = Segment()
27+
for key, value in segment_data.items():
28+
if key == 'currencyAssets':
29+
currency_assets = camel_to_underline_obj(value)
30+
[segment.add_currency_asset(CurrencyAsset.from_dict(i)) for i in currency_assets]
31+
else:
32+
setattr(segment, camel_to_underline(key), value)
33+
assets.add_segment(segment)
34+
self.assets = assets
35+
36+

tigeropen/trade/trade_client.py

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

99
from tigeropen.common.consts import THREAD_LOCAL, SecurityType, Market, Currency
1010
from tigeropen.common.consts.service_types import CONTRACTS, ACCOUNTS, POSITIONS, ASSETS, ORDERS, ORDER_NO, \
11-
CANCEL_ORDER, MODIFY_ORDER, PLACE_ORDER, ACTIVE_ORDERS, INACTIVE_ORDERS, FILLED_ORDERS, CONTRACT, PREVIEW_ORDER
11+
CANCEL_ORDER, MODIFY_ORDER, PLACE_ORDER, ACTIVE_ORDERS, INACTIVE_ORDERS, FILLED_ORDERS, CONTRACT, PREVIEW_ORDER, \
12+
PRIME_ASSETS
1213
from tigeropen.common.exceptions import ApiException
1314
from tigeropen.quote.request import OpenApiRequest
1415
from tigeropen.tiger_open_client import TigerOpenClient
@@ -22,6 +23,7 @@
2223
from tigeropen.trade.response.order_preview_response import PreviewOrderResponse
2324
from tigeropen.trade.response.orders_response import OrdersResponse
2425
from tigeropen.trade.response.positions_response import PositionsResponse
26+
from tigeropen.trade.response.prime_assets_response import PrimeAssetsResponse
2527

2628

2729
class TradeClient(TigerOpenClient):
@@ -241,6 +243,27 @@ def get_assets(self, account=None, sub_accounts=None, segment=False, market_valu
241243

242244
return None
243245

246+
def get_prime_assets(self, account=None):
247+
"""
248+
get prime account assets
249+
:param account:
250+
:return: tigeropen.trade.domain.prime_account.PortfolioAccount
251+
"""
252+
params = AssetParams()
253+
params.account = account if account else self._account
254+
params.secret_key = self._secret_key
255+
256+
request = OpenApiRequest(PRIME_ASSETS, biz_model=params)
257+
response_content = self.__fetch_data(request)
258+
if response_content:
259+
response = PrimeAssetsResponse()
260+
response.parse_response_content(response_content)
261+
if response.is_success():
262+
return response.assets
263+
else:
264+
raise ApiException(response.code, response.message)
265+
return None
266+
244267
def get_orders(self, account=None, sec_type=None, market=Market.ALL, symbol=None, start_time=None, end_time=None,
245268
limit=100, is_brief=False, states=None):
246269
"""

0 commit comments

Comments
 (0)