siglab-py 0.1.0__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/__init__.py +0 -0
- siglab_py/constants.py +3 -0
- siglab_py/exchanges/__init__.py +0 -0
- siglab_py/exchanges/any_exchange.py +20 -0
- siglab_py/market_data_providers/__init__.py +0 -0
- siglab_py/market_data_providers/aggregated_orderbook_provider.py +451 -0
- siglab_py/market_data_providers/candles_provider.py +342 -0
- siglab_py/market_data_providers/candles_ta_provider.py +263 -0
- siglab_py/market_data_providers/deribit_options_expiry_provider.py +197 -0
- siglab_py/market_data_providers/orderbooks_provider.py +359 -0
- siglab_py/market_data_providers/test_provider.py +70 -0
- siglab_py/ordergateway/__init__.py +0 -0
- siglab_py/ordergateway/client.py +137 -0
- siglab_py/ordergateway/encrypt_keys_util.py +43 -0
- siglab_py/ordergateway/gateway.py +658 -0
- siglab_py/ordergateway/test_ordergateway.py +140 -0
- siglab_py/tests/__init__.py +0 -0
- siglab_py/tests/integration/__init__.py +0 -0
- siglab_py/tests/integration/market_data_util_tests.py +123 -0
- siglab_py/tests/unit/__init__.py +0 -0
- siglab_py/util/__init__.py +0 -0
- siglab_py/util/analytic_util.py +792 -0
- siglab_py/util/aws_util.py +47 -0
- siglab_py/util/market_data_util.py +385 -0
- siglab_py/util/retry_util.py +15 -0
- siglab_py-0.1.0.dist-info/METADATA +36 -0
- siglab_py-0.1.0.dist-info/RECORD +29 -0
- siglab_py-0.1.0.dist-info/WHEEL +5 -0
- siglab_py-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import List, Dict, Any
|
|
3
|
+
|
|
4
|
+
from ccxt.base.types import Position
|
|
5
|
+
|
|
6
|
+
from constants import JSON_SERIALIZABLE_TYPES
|
|
7
|
+
from exchanges.any_exchange import AnyExchange
|
|
8
|
+
|
|
9
|
+
'''
|
|
10
|
+
Example,
|
|
11
|
+
spot 'BTC/USDT'
|
|
12
|
+
perpetual 'BTC/USDT:USDT'
|
|
13
|
+
In both cases, BTC is base ccy, and USDT is quote ccy.
|
|
14
|
+
|
|
15
|
+
crypto/CCXT convention is,
|
|
16
|
+
For spot, in base ccy.
|
|
17
|
+
For perpetual contracts, this is in # contracts, not base ccy.
|
|
18
|
+
Here, Order.amount is always in base ccy regardless whether you're trading spot or perpetual.
|
|
19
|
+
|
|
20
|
+
leg_room_bps:
|
|
21
|
+
For limit orders, when order is executed, limit price be ...
|
|
22
|
+
buy order: best ask * (1 + leg_room_bps/10000)
|
|
23
|
+
sell order: best bid * (1 - leg_room_bps/10000)
|
|
24
|
+
Thus a positive leg room means you're more aggressive to trying to get the order filled: Buy at higher price, Sell at lower price.
|
|
25
|
+
'''
|
|
26
|
+
class Order:
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
ticker : str,
|
|
30
|
+
side : str, # buy/sell
|
|
31
|
+
amount : float,
|
|
32
|
+
order_type : str, # market/limit
|
|
33
|
+
leg_room_bps : float = 0
|
|
34
|
+
) -> None:
|
|
35
|
+
self.ticker = ticker
|
|
36
|
+
self.side = side.strip().lower()
|
|
37
|
+
self.amount = amount
|
|
38
|
+
self.order_type = order_type.strip().lower()
|
|
39
|
+
self.leg_room_bps = leg_room_bps
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> Dict[JSON_SERIALIZABLE_TYPES, JSON_SERIALIZABLE_TYPES]:
|
|
42
|
+
return {
|
|
43
|
+
"ticker" : self.ticker,
|
|
44
|
+
"side" : self.side,
|
|
45
|
+
"amount" : self.amount,
|
|
46
|
+
"order_type" : self.order_type,
|
|
47
|
+
"leg_room_bps" : self.leg_room_bps
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
'''
|
|
51
|
+
For limit orders, if not filled within wait_fill_threshold_ms, we'd try cancel and resend un-filled amount as market order.
|
|
52
|
+
wait_fill_threshold_ms default to -1: Means wait forever until fully filled.
|
|
53
|
+
'''
|
|
54
|
+
class DivisiblePosition(Order):
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
ticker : str,
|
|
58
|
+
side : str, # buy/sell
|
|
59
|
+
amount : float,
|
|
60
|
+
order_type : str, # market/limit
|
|
61
|
+
leg_room_bps : float,
|
|
62
|
+
slices : int = 1,
|
|
63
|
+
wait_fill_threshold_ms : float = -1
|
|
64
|
+
) -> None:
|
|
65
|
+
super().__init__(ticker, side, amount, order_type, leg_room_bps)
|
|
66
|
+
self.slices = slices
|
|
67
|
+
self.wait_fill_threshold_ms = wait_fill_threshold_ms
|
|
68
|
+
self.multiplier = 1
|
|
69
|
+
self.filled_amount = 0
|
|
70
|
+
self.average_cost = 0
|
|
71
|
+
|
|
72
|
+
self.executions : Dict[str, Dict[str, Any]] = {}
|
|
73
|
+
|
|
74
|
+
def to_slices(self) -> List[Order]:
|
|
75
|
+
slices : List[Order] = []
|
|
76
|
+
|
|
77
|
+
remaining_amount_in_base_ccy : float = self.amount
|
|
78
|
+
slice_amount_in_base_ccy : float = self.amount / self.slices
|
|
79
|
+
for i in range(self.slices):
|
|
80
|
+
if remaining_amount_in_base_ccy>0:
|
|
81
|
+
if remaining_amount_in_base_ccy >= slice_amount_in_base_ccy:
|
|
82
|
+
slice = Order(
|
|
83
|
+
ticker=self.ticker,
|
|
84
|
+
side=self.side,
|
|
85
|
+
amount=slice_amount_in_base_ccy,
|
|
86
|
+
leg_room_bps=self.leg_room_bps,
|
|
87
|
+
order_type=self.order_type)
|
|
88
|
+
|
|
89
|
+
else:
|
|
90
|
+
# Last slice
|
|
91
|
+
slice = Order(
|
|
92
|
+
ticker=self.ticker,
|
|
93
|
+
side=self.side,
|
|
94
|
+
amount=remaining_amount_in_base_ccy,
|
|
95
|
+
leg_room_bps=self.leg_room_bps,
|
|
96
|
+
order_type=self.order_type)
|
|
97
|
+
|
|
98
|
+
slices.append(slice)
|
|
99
|
+
|
|
100
|
+
return slices
|
|
101
|
+
|
|
102
|
+
def append_execution(
|
|
103
|
+
self,
|
|
104
|
+
order_id : str,
|
|
105
|
+
execution : Dict[str, Any]
|
|
106
|
+
):
|
|
107
|
+
self.executions[order_id] = execution
|
|
108
|
+
|
|
109
|
+
def get_execution(
|
|
110
|
+
self,
|
|
111
|
+
order_id : str
|
|
112
|
+
) -> Dict[str, Any]:
|
|
113
|
+
return self.executions[order_id]
|
|
114
|
+
|
|
115
|
+
def get_executions(self) -> Dict[str, Dict[str, Any]]:
|
|
116
|
+
return self.executions
|
|
117
|
+
|
|
118
|
+
def get_filled_amount(self) -> float:
|
|
119
|
+
# filled_amount is in base ccy
|
|
120
|
+
filled_amount = sum([ self.executions[order_id]['filled'] * self.multiplier for order_id in self.executions ])
|
|
121
|
+
self.filled_amount = filled_amount
|
|
122
|
+
return filled_amount
|
|
123
|
+
|
|
124
|
+
def get_average_cost(self) -> float:
|
|
125
|
+
average_cost = sum([ self.executions[order_id]['average'] * self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
126
|
+
average_cost = average_cost / sum([ self.executions[order_id]['amount'] for order_id in self.executions ])
|
|
127
|
+
self.average_cost = average_cost
|
|
128
|
+
return average_cost
|
|
129
|
+
|
|
130
|
+
def to_dict(self) -> Dict[JSON_SERIALIZABLE_TYPES, JSON_SERIALIZABLE_TYPES]:
|
|
131
|
+
rv = super().to_dict()
|
|
132
|
+
rv['slices'] = self.slices
|
|
133
|
+
rv['wait_fill_threshold_ms'] = self.wait_fill_threshold_ms
|
|
134
|
+
rv['executions'] = self.executions
|
|
135
|
+
rv['filled_amount'] = self.filled_amount
|
|
136
|
+
rv['average_cost'] = self.average_cost
|
|
137
|
+
return rv
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from util.aws_util import AwsKmsUtil
|
|
3
|
+
|
|
4
|
+
'''
|
|
5
|
+
From command line, run 'aws configure' with IAM user's Access key ID and Secret access key. (Assume you have awscli installed)
|
|
6
|
+
aws configure
|
|
7
|
+
AWS Access Key ID [****************ABCD]: <-- ***ABCD is your IAM user
|
|
8
|
+
AWS Secret Access Key [****************xxx]: <-- xxx is password to your IAM user
|
|
9
|
+
Default region name [us-east-1]: <-- Region need be where your KMS key resides!
|
|
10
|
+
Default output format [None]:
|
|
11
|
+
|
|
12
|
+
Remember that when you create your KMS Key, you need to grant permission of the key newly created key to IAM user (This is done on KMS side, not IAM).
|
|
13
|
+
'''
|
|
14
|
+
key_id : Union[str, None] = None
|
|
15
|
+
api_key : Union[str, None] = None
|
|
16
|
+
secret : Union[str, None] = None
|
|
17
|
+
passphrase : Union[str, None] = None
|
|
18
|
+
|
|
19
|
+
print("enter key_id")
|
|
20
|
+
key_id = input()
|
|
21
|
+
|
|
22
|
+
print("enter apikey")
|
|
23
|
+
apikey = input()
|
|
24
|
+
|
|
25
|
+
print("enter secret")
|
|
26
|
+
secret = input()
|
|
27
|
+
|
|
28
|
+
print("enter passphrase")
|
|
29
|
+
passphrase = input()
|
|
30
|
+
|
|
31
|
+
aws_kms = AwsKmsUtil(key_id=key_id, profile_name=None)
|
|
32
|
+
|
|
33
|
+
apikey = aws_kms.encrypt(apikey).decode("utf-8")
|
|
34
|
+
secret = aws_kms.encrypt(secret).decode("utf-8")
|
|
35
|
+
|
|
36
|
+
if passphrase:
|
|
37
|
+
passphrase = aws_kms.encrypt(passphrase).decode("utf-8")
|
|
38
|
+
|
|
39
|
+
print(f"apikey: {apikey}")
|
|
40
|
+
print(f"secret: {secret}")
|
|
41
|
+
|
|
42
|
+
if passphrase:
|
|
43
|
+
print(f"passphrase: {passphrase}")
|