siglab-py 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of siglab-py might be problematic. Click here for more details.
- siglab_py/exchanges/any_exchange.py +1 -0
- siglab_py/ordergateway/client.py +6 -6
- siglab_py/ordergateway/gateway.py +13 -1
- siglab_py/tests/integration/market_data_util_tests.py +3 -8
- siglab_py/tests/unit/analytic_util_tests.py +45 -0
- siglab_py/util/aws_util.py +5 -0
- {siglab_py-0.1.6.dist-info → siglab_py-0.1.8.dist-info}/METADATA +1 -1
- {siglab_py-0.1.6.dist-info → siglab_py-0.1.8.dist-info}/RECORD +10 -9
- {siglab_py-0.1.6.dist-info → siglab_py-0.1.8.dist-info}/WHEEL +0 -0
- {siglab_py-0.1.6.dist-info → siglab_py-0.1.8.dist-info}/top_level.txt +0 -0
siglab_py/ordergateway/client.py
CHANGED
|
@@ -67,8 +67,9 @@ class DivisiblePosition(Order):
|
|
|
67
67
|
self.slices = slices
|
|
68
68
|
self.wait_fill_threshold_ms = wait_fill_threshold_ms
|
|
69
69
|
self.multiplier = 1
|
|
70
|
-
self.filled_amount =
|
|
71
|
-
self.average_cost =
|
|
70
|
+
self.filled_amount : Union[float, None] = None
|
|
71
|
+
self.average_cost : Union[float, None] = None
|
|
72
|
+
self.pos : Union[float, None] = None # in base ccy, after execution. (Not in USDT or quote ccy, Not in # contracts)
|
|
72
73
|
|
|
73
74
|
self.executions : Dict[str, Dict[str, Any]] = {}
|
|
74
75
|
|
|
@@ -119,13 +120,11 @@ class DivisiblePosition(Order):
|
|
|
119
120
|
def get_filled_amount(self) -> float:
|
|
120
121
|
# filled_amount is in base ccy
|
|
121
122
|
filled_amount = sum([ self.executions[order_id]['filled'] * self.multiplier for order_id in self.executions ])
|
|
122
|
-
self.filled_amount = filled_amount
|
|
123
123
|
return filled_amount
|
|
124
124
|
|
|
125
125
|
def get_average_cost(self) -> float:
|
|
126
126
|
average_cost = sum([ self.executions[order_id]['average'] * self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
127
127
|
average_cost = average_cost / sum([ self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
128
|
-
self.average_cost = average_cost
|
|
129
128
|
return average_cost
|
|
130
129
|
|
|
131
130
|
def to_dict(self) -> Dict[JSON_SERIALIZABLE_TYPES, JSON_SERIALIZABLE_TYPES]:
|
|
@@ -135,6 +134,7 @@ class DivisiblePosition(Order):
|
|
|
135
134
|
rv['executions'] = self.executions
|
|
136
135
|
rv['filled_amount'] = self.filled_amount
|
|
137
136
|
rv['average_cost'] = self.average_cost
|
|
137
|
+
rv['pos'] = self.pos
|
|
138
138
|
return rv
|
|
139
139
|
|
|
140
140
|
def execute_positions(
|
|
@@ -150,8 +150,6 @@ def execute_positions(
|
|
|
150
150
|
_positions = [ position.to_dict() for position in positions ]
|
|
151
151
|
redis_client.set(name=ordergateway_pending_orders_topic, value=json.dumps(_positions).encode('utf-8'), ex=60*15)
|
|
152
152
|
|
|
153
|
-
print(f"{ordergateway_pending_orders_topic}: Orders sent {_positions}.")
|
|
154
|
-
|
|
155
153
|
# Wait for fills
|
|
156
154
|
fills_received : bool = False
|
|
157
155
|
while not fills_received:
|
|
@@ -165,6 +163,8 @@ def execute_positions(
|
|
|
165
163
|
message = message.decode('utf-8')
|
|
166
164
|
executed_positions = json.loads(message)
|
|
167
165
|
fills_received = True
|
|
166
|
+
|
|
167
|
+
redis_client.delete(key)
|
|
168
168
|
break
|
|
169
169
|
|
|
170
170
|
except Exception as loop_err:
|
|
@@ -528,6 +528,18 @@ async def execute_one_position(
|
|
|
528
528
|
finally:
|
|
529
529
|
i += 1
|
|
530
530
|
|
|
531
|
+
position.filled_amount = position.get_filled_amount()
|
|
532
|
+
position.average_cost = position.get_average_cost()
|
|
533
|
+
|
|
534
|
+
balances = await exchange.fetch_balance() # type: ignore
|
|
535
|
+
if param['default_type']!='spot':
|
|
536
|
+
updated_position = await exchange.fetch_position(symbol=position.ticker) # type: ignore
|
|
537
|
+
amount = updated_position['contracts'] * position.multiplier # in base ccy
|
|
538
|
+
else:
|
|
539
|
+
base_ccy : str = position.ticker.split("/")[0]
|
|
540
|
+
amount = balances[base_ccy]['total']
|
|
541
|
+
position.pos = amount
|
|
542
|
+
|
|
531
543
|
async def work(
|
|
532
544
|
param : Dict,
|
|
533
545
|
exchange : AnyExchange,
|
|
@@ -581,7 +593,7 @@ async def work(
|
|
|
581
593
|
|
|
582
594
|
i = 0
|
|
583
595
|
for position in positions:
|
|
584
|
-
log(f"{i} {position.ticker}, {position.side} # executions: {len(position.get_executions())}, filled_amount: {position.
|
|
596
|
+
log(f"{i} {position.ticker}, {position.side} # executions: {len(position.get_executions())}, filled_amount: {position.filled_amount}, average_cost: {position.average_cost}, pos: {position.pos}, order_dispatch_elapsed_ms: {order_dispatch_elapsed_ms}")
|
|
585
597
|
i += 1
|
|
586
598
|
|
|
587
599
|
start = time.time()
|
|
@@ -12,7 +12,7 @@ from ccxt.deribit import deribit
|
|
|
12
12
|
from ccxt.base.exchange import Exchange
|
|
13
13
|
|
|
14
14
|
# @unittest.skip("Skip all integration tests.")
|
|
15
|
-
class
|
|
15
|
+
class MarketDataUtilTests(unittest.TestCase):
|
|
16
16
|
|
|
17
17
|
def test_fetch_candles_yahoo(self):
|
|
18
18
|
start_date : datetime = datetime(2024, 1,1)
|
|
@@ -89,16 +89,11 @@ class MarketDataGizmoTests(unittest.TestCase):
|
|
|
89
89
|
param = {
|
|
90
90
|
'apiKey' : None,
|
|
91
91
|
'secret' : None,
|
|
92
|
-
'password' : None,
|
|
92
|
+
'password' : None,
|
|
93
93
|
'subaccount' : None,
|
|
94
94
|
'rateLimit' : 100, # In ms
|
|
95
95
|
'options' : {
|
|
96
|
-
'defaultType': 'swap'
|
|
97
|
-
'leg_room_bps' : 5,
|
|
98
|
-
'trade_fee_bps' : 3,
|
|
99
|
-
|
|
100
|
-
'list_ts_field' : 'listTime' # list_ts_field: Response field in exchange.markets[symbol] to indiate timestamp of symbol's listing date in ms. For bybit, markets['launchTime'] is list date. For okx, it's markets['listTime'].
|
|
101
|
-
}
|
|
96
|
+
'defaultType': 'swap' }
|
|
102
97
|
}
|
|
103
98
|
|
|
104
99
|
exchange : Exchange = okx(param)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from typing import List
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from util.analytic_util import compute_candles_stats
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
'''
|
|
10
|
+
Manual checks against for example Tradingview here: \siglab\siglab_py\tests\manual
|
|
11
|
+
'''
|
|
12
|
+
|
|
13
|
+
# @unittest.skip("Skip all integration tests.")
|
|
14
|
+
class AnalyticUtilTests(unittest.TestCase):
|
|
15
|
+
|
|
16
|
+
def test_compute_candle_stats(self):
|
|
17
|
+
'''
|
|
18
|
+
Folder structure:
|
|
19
|
+
\ siglab
|
|
20
|
+
\ siglab_py <-- python project root
|
|
21
|
+
\ sigab_py
|
|
22
|
+
__init__.py
|
|
23
|
+
\ util
|
|
24
|
+
__init__.py
|
|
25
|
+
market_data_util.py
|
|
26
|
+
\ tests
|
|
27
|
+
\ unit
|
|
28
|
+
__init__.py
|
|
29
|
+
analytic_util_tests.py <-- Tests here
|
|
30
|
+
|
|
31
|
+
\ siglab_rs <-- Rust project root
|
|
32
|
+
\ data <-- Data files here!
|
|
33
|
+
'''
|
|
34
|
+
data_dir = Path(__file__).parent.parent.parent.parent / "data"
|
|
35
|
+
csv_path = data_dir / "sample_btc_candles.csv"
|
|
36
|
+
pd_candles : pd.DataFrame = pd.read_csv(csv_path)
|
|
37
|
+
compute_candles_stats(
|
|
38
|
+
pd_candles=pd_candles,
|
|
39
|
+
boillenger_std_multiples=2,
|
|
40
|
+
sliding_window_how_many_candles=20,
|
|
41
|
+
pypy_compat=True
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
expected_columns : List[str] = ['exchange', 'symbol', 'timestamp_ms', 'open', 'high', 'low', 'close', 'volume', 'datetime', 'datetime_utc', 'year', 'month', 'day', 'hour', 'minute', 'dayofweek', 'pct_chg_on_close', 'candle_height', 'is_green', 'pct_change_close', 'sma_short_periods', 'sma_long_periods', 'ema_short_periods', 'ema_long_periods', 'ema_close', 'std', 'ema_volume_short_periods', 'ema_volume_long_periods', 'max_short_periods', 'max_long_periods', 'idmax_short_periods', 'idmax_long_periods', 'min_short_periods', 'min_long_periods', 'idmin_short_periods', 'idmin_long_periods', 'h_l', 'h_pc', 'l_pc', 'tr', 'atr', 'hurst_exp', 'boillenger_upper', 'boillenger_lower', 'boillenger_channel_height', 'boillenger_upper_agg', 'boillenger_lower_agg', 'boillenger_channel_height_agg', 'aggressive_up', 'aggressive_up_index', 'aggressive_up_candle_height', 'aggressive_up_candle_high', 'aggressive_up_candle_low', 'aggressive_down', 'aggressive_down_index', 'aggressive_down_candle_height', 'aggressive_down_candle_high', 'aggressive_down_candle_low', 'fvg_low', 'fvg_high', 'fvg_gap', 'fvg_mitigated', 'close_delta', 'close_delta_percent', 'up', 'down', 'rsi', 'ema_rsi', 'typical_price', 'money_flow', 'money_flow_positive', 'money_flow_negative', 'positive_flow_sum', 'negative_flow_sum', 'money_flow_ratio', 'mfi', 'macd', 'signal', 'macd_minus_signal', 'fib_618_short_periods', 'fib_618_long_periods', 'gap_close_vs_ema', 'close_above_or_below_ema', 'close_vs_ema_inflection']
|
|
45
|
+
assert(pd_candles.columns.to_list()==expected_columns)
|
siglab_py/util/aws_util.py
CHANGED
|
@@ -3,6 +3,11 @@ from typing import Union, Dict
|
|
|
3
3
|
'''
|
|
4
4
|
https://gist.github.com/raphaelgabbarelli/bc5a41d93789046f9c71e4685f1463e7
|
|
5
5
|
https://www.youtube.com/watch?v=CFEYKrP0vxs
|
|
6
|
+
|
|
7
|
+
If boto3 import complains: AttributeError: module 'lib' has no attribute 'X509_V_FLAG_CB_ISSUER_CHECK'
|
|
8
|
+
python3 -m pip install pip --upgrade
|
|
9
|
+
pip install pyopenssl --upgrade
|
|
10
|
+
https://stackoverflow.com/questions/73830524/attributeerror-module-lib-has-no-attribute-x509-v-flag-cb-issuer-check
|
|
6
11
|
'''
|
|
7
12
|
import boto3
|
|
8
13
|
import base64
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
siglab_py/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
siglab_py/constants.py,sha256=YGNdEsWtQ99V2oltaynZTjM8VIboSfyIjDXJKSlhv4U,132
|
|
3
3
|
siglab_py/exchanges/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
siglab_py/exchanges/any_exchange.py,sha256=
|
|
4
|
+
siglab_py/exchanges/any_exchange.py,sha256=pnSAatOzUIgwY9iPa5XR5xF_C5VIXAWi_uAhjvBP8bQ,749
|
|
5
5
|
siglab_py/market_data_providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
siglab_py/market_data_providers/aggregated_orderbook_provider.py,sha256=uN6oD6PqbfnkPKVzKF_GfSEuXdtmv0lFTB-yg9gRYcI,23234
|
|
7
7
|
siglab_py/market_data_providers/candles_provider.py,sha256=fqHJjlECsBiBlpgyywrc4gTgxiROPNzZM8KxQBB5cOg,14139
|
|
@@ -10,20 +10,21 @@ siglab_py/market_data_providers/deribit_options_expiry_provider.py,sha256=mP-508
|
|
|
10
10
|
siglab_py/market_data_providers/orderbooks_provider.py,sha256=cBp-HYCups2Uiwzw0SaUwxrg4unJvnm2TDqIK8f4hUg,15674
|
|
11
11
|
siglab_py/market_data_providers/test_provider.py,sha256=wBLCgcWjs7FGZJXWsNyn30lkOLa_cgpuvqRakMC0wbA,2221
|
|
12
12
|
siglab_py/ordergateway/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
siglab_py/ordergateway/client.py,sha256=
|
|
13
|
+
siglab_py/ordergateway/client.py,sha256=BndmyQkAtPSEXQP9vR8ySiPIkODjuf0-LOwnsFFPPhg,6508
|
|
14
14
|
siglab_py/ordergateway/encrypt_keys_util.py,sha256=-qi87db8To8Yf1WS1Q_Cp2Ya7ZqgWlRqSHfNXCM7wE4,1339
|
|
15
|
-
siglab_py/ordergateway/gateway.py,sha256=
|
|
15
|
+
siglab_py/ordergateway/gateway.py,sha256=n1tfKsSujdyygyV3fYGy56CGXMT1Y_6BFuOsXesG3bU,30589
|
|
16
16
|
siglab_py/ordergateway/test_ordergateway.py,sha256=DH4djEZeWZr69lTx_xG9_N8S_E2wAG4S3430VisU5w4,3805
|
|
17
17
|
siglab_py/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
18
|
siglab_py/tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
siglab_py/tests/integration/market_data_util_tests.py,sha256=
|
|
19
|
+
siglab_py/tests/integration/market_data_util_tests.py,sha256=HFESIXEdQmrbDV3DvLiDLq0iE-4itysxSFur_Th4jjE,5207
|
|
20
20
|
siglab_py/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
siglab_py/tests/unit/analytic_util_tests.py,sha256=-FGj-cWdIZ_WZQqQCIpDLRSv5TlJIG81fHyBlWuAm1U,2961
|
|
21
22
|
siglab_py/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
23
|
siglab_py/util/analytic_util.py,sha256=QLabbEMqM4rKKH2PE_LqxIyo-BUdCRhkLybLATBImcc,43438
|
|
23
|
-
siglab_py/util/aws_util.py,sha256=
|
|
24
|
+
siglab_py/util/aws_util.py,sha256=KGmjHrr1rpnnxr33nXHNzTul4tvyyxl9p6gpwNv0Ygc,2557
|
|
24
25
|
siglab_py/util/market_data_util.py,sha256=3qTq71xGvQXj0ORKJV50IN5FP_mCBF_gvdmlPyhdyco,16439
|
|
25
26
|
siglab_py/util/retry_util.py,sha256=mxYuRFZRZoaQQjENcwPmxhxixtd1TFvbxIdPx4RwfRc,743
|
|
26
|
-
siglab_py-0.1.
|
|
27
|
-
siglab_py-0.1.
|
|
28
|
-
siglab_py-0.1.
|
|
29
|
-
siglab_py-0.1.
|
|
27
|
+
siglab_py-0.1.8.dist-info/METADATA,sha256=QqYYIHR02shHkYxd9X4vBgxwhhp_6eoYEctTN-rUgpk,1096
|
|
28
|
+
siglab_py-0.1.8.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
29
|
+
siglab_py-0.1.8.dist-info/top_level.txt,sha256=AbD4VR9OqmMOGlMJLkAVPGQMtUPIQv0t1BF5xmcLJSk,10
|
|
30
|
+
siglab_py-0.1.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|