siglab-py 0.1.19__py3-none-any.whl → 0.6.33__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.
Files changed (45) hide show
  1. siglab_py/algo/__init__.py +0 -0
  2. siglab_py/algo/macdrsi_crosses_15m_tc_strategy.py +107 -0
  3. siglab_py/algo/strategy_base.py +122 -0
  4. siglab_py/algo/strategy_executor.py +1308 -0
  5. siglab_py/algo/tp_algo.py +529 -0
  6. siglab_py/backtests/__init__.py +0 -0
  7. siglab_py/backtests/backtest_core.py +2405 -0
  8. siglab_py/backtests/coinflip_15m_crypto.py +432 -0
  9. siglab_py/backtests/fibonacci_d_mv_crypto.py +541 -0
  10. siglab_py/backtests/macdrsi_crosses_15m_tc_crypto.py +473 -0
  11. siglab_py/constants.py +26 -1
  12. siglab_py/exchanges/binance.py +38 -0
  13. siglab_py/exchanges/deribit.py +83 -0
  14. siglab_py/exchanges/futubull.py +33 -3
  15. siglab_py/market_data_providers/candles_provider.py +11 -10
  16. siglab_py/market_data_providers/candles_ta_provider.py +5 -5
  17. siglab_py/market_data_providers/ccxt_candles_ta_to_csv.py +238 -0
  18. siglab_py/market_data_providers/futu_candles_ta_to_csv.py +224 -0
  19. siglab_py/market_data_providers/google_monitor.py +320 -0
  20. siglab_py/market_data_providers/orderbooks_provider.py +15 -12
  21. siglab_py/market_data_providers/tg_monitor.py +428 -0
  22. siglab_py/market_data_providers/{test_provider.py → trigger_provider.py} +9 -8
  23. siglab_py/ordergateway/client.py +172 -41
  24. siglab_py/ordergateway/encrypt_keys_util.py +1 -1
  25. siglab_py/ordergateway/gateway.py +456 -344
  26. siglab_py/ordergateway/test_ordergateway.py +8 -7
  27. siglab_py/tests/integration/market_data_util_tests.py +80 -6
  28. siglab_py/tests/unit/analytic_util_tests.py +67 -4
  29. siglab_py/tests/unit/market_data_util_tests.py +96 -0
  30. siglab_py/tests/unit/simple_math_tests.py +252 -0
  31. siglab_py/tests/unit/trading_util_tests.py +65 -0
  32. siglab_py/util/analytic_util.py +484 -66
  33. siglab_py/util/datetime_util.py +39 -0
  34. siglab_py/util/market_data_util.py +564 -74
  35. siglab_py/util/module_util.py +40 -0
  36. siglab_py/util/notification_util.py +78 -0
  37. siglab_py/util/retry_util.py +16 -3
  38. siglab_py/util/simple_math.py +262 -0
  39. siglab_py/util/slack_notification_util.py +59 -0
  40. siglab_py/util/trading_util.py +118 -0
  41. {siglab_py-0.1.19.dist-info → siglab_py-0.6.33.dist-info}/METADATA +5 -13
  42. siglab_py-0.6.33.dist-info/RECORD +56 -0
  43. {siglab_py-0.1.19.dist-info → siglab_py-0.6.33.dist-info}/WHEEL +1 -1
  44. siglab_py-0.1.19.dist-info/RECORD +0 -31
  45. {siglab_py-0.1.19.dist-info → siglab_py-0.6.33.dist-info}/top_level.txt +0 -0
File without changes
@@ -0,0 +1,107 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from typing import List, Dict, Any, Union
4
+
5
+ from siglab_py.algo.strategy_base import StrategyBase
6
+
7
+ class MACDRSICrosses15mTCStrategy(StrategyBase):
8
+ def __init__(self, *args: object) -> None:
9
+ pass
10
+
11
+ @staticmethod
12
+ def order_notional_adj(
13
+ algo_param : Dict,
14
+ ) -> Dict[str, float]:
15
+ return StrategyBase.order_notional_adj(algo_param) # type: ignore
16
+
17
+ @staticmethod
18
+ def allow_entry_initial(
19
+ lo_row_tm1,
20
+ hi_row_tm1,
21
+ last_candles
22
+ ) -> Dict[str, bool]:
23
+ allow_long : bool = (
24
+ lo_row_tm1['macd_cross'] == 'bullish'
25
+ # use 'macd_cross_last' instead in combinations with 'macd_bullish_cross_last_id' if you want to make more entries
26
+ '''
27
+ and (
28
+ lo_row_tm1.name >= lo_row_tm1['macd_bullish_cross_last_id']
29
+ and
30
+ (lo_row_tm1.name - lo_row_tm1['macd_bullish_cross_last_id']) < 5
31
+ )
32
+ '''
33
+ and lo_row_tm1['rsi_trend']=="up"
34
+ and lo_row_tm1['close']>hi_row_tm1['ema_close']
35
+ )
36
+ allow_short : bool = (
37
+ lo_row_tm1['macd_cross'] == 'bearish'
38
+ '''
39
+ and (
40
+ lo_row_tm1.name >= lo_row_tm1['macd_bearish_cross_last_id']
41
+ and
42
+ (lo_row_tm1.name - lo_row_tm1['macd_bearish_cross_last_id']) < 5
43
+ )
44
+ '''
45
+ and lo_row_tm1['rsi_trend']=="down"
46
+ and lo_row_tm1['close']<hi_row_tm1['ema_close']
47
+ )
48
+ return {
49
+ 'long' : allow_long,
50
+ 'short' : allow_short
51
+ }
52
+
53
+ @staticmethod
54
+ def allow_entry_final(
55
+ lo_row,
56
+ algo_param : Dict
57
+ ) -> Dict[str, Union[bool, float, None]]:
58
+ open : float = lo_row['open']
59
+
60
+ entry_price_long, entry_price_short = open, open
61
+ allow_long, allow_short = True, True
62
+ reference_price = None
63
+
64
+ pnl_potential_bps = algo_param['tp_max_percent']*100
65
+
66
+ target_price_long = entry_price_long * (1 + pnl_potential_bps/10000)
67
+ target_price_short = entry_price_short * (1 - pnl_potential_bps/10000)
68
+
69
+ return {
70
+ 'long' : allow_long,
71
+ 'short' : allow_short,
72
+
73
+ # In additional to allow or not, allow_entry_final also calculate a few things which you may need to mark the entry trades.
74
+ 'entry_price_long' : entry_price_long,
75
+ 'entry_price_short' : entry_price_short,
76
+ 'target_price_long' : target_price_long,
77
+ 'target_price_short' : target_price_short,
78
+ 'reference_price' : reference_price
79
+ }
80
+
81
+ @staticmethod
82
+ def trailing_stop_threshold_eval(
83
+ algo_param : Dict,
84
+ *args: Any, **kwargs: Any
85
+ ) -> Dict[str, float]:
86
+ result = StrategyBase.trailing_stop_threshold_eval(algo_param)
87
+ tp_min_percent = result['tp_min_percent']
88
+ tp_max_percent = result['tp_max_percent']
89
+ return {
90
+ 'tp_min_percent' : tp_min_percent,
91
+ 'tp_max_percent' : tp_max_percent
92
+ }
93
+
94
+ @staticmethod
95
+ def tp_eval (
96
+ lo_row,
97
+ this_ticker_open_trades : List[Dict],
98
+ algo_param : Dict
99
+ ) -> bool:
100
+ return StrategyBase.tp_eval(lo_row, this_ticker_open_trades, algo_param)
101
+
102
+ @staticmethod
103
+ def get_strategy_indicators() -> List[str]:
104
+ return [
105
+ 'lo_row_tm1:macd_cross', 'lo_row_tm1:macd_bullish_cross_last_id', 'lo_row_tm1:macd_bearish_cross_last_id',
106
+ 'lo_row_tm1:rsi_trend', 'lo_row_tm1:rsi', 'lo_row_tm1:rsi_max', 'lo_row_tm1:rsi_min', 'lo_row_tm1:rsi_idmax', 'lo_row_tm1:rsi_idmin'
107
+ ]
@@ -0,0 +1,122 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from typing import List, Dict, Any, Union
4
+
5
+ from siglab_py.backtests.backtest_core import generic_tp_eval
6
+
7
+ class StrategyBase(ABC):
8
+ def __init__(self, *args: object) -> None:
9
+ pass
10
+
11
+ @staticmethod
12
+ def reversal(
13
+ direction : str, # up or down
14
+ last_candles
15
+ ) -> bool:
16
+ if direction == "down" and all([ candle[1]<candle[4] for candle in last_candles ]): # All green?
17
+ return True
18
+ elif direction == "up" and all([ candle[1]>candle[4] for candle in last_candles ]): # All red?
19
+ return True
20
+ else:
21
+ return False
22
+
23
+ @staticmethod
24
+ def order_notional_adj(
25
+ algo_param : Dict,
26
+ *args: Any, **kwargs: Any
27
+ ) -> Dict[str, float]:
28
+ target_order_notional = algo_param['amount_base_ccy']
29
+ return {
30
+ 'target_order_notional' : target_order_notional
31
+ }
32
+
33
+ @staticmethod
34
+ def allow_entry_initial(
35
+ *args: Any, **kwargs: Any
36
+ ) -> Dict[str, bool]:
37
+ return {
38
+ 'long' : False,
39
+ 'short' : False
40
+ }
41
+
42
+ @staticmethod
43
+ def allow_entry_final(
44
+ lo_row,
45
+ algo_param : Dict,
46
+ *args: Any, **kwargs: Any
47
+ ) -> Dict[str, Union[bool, float, None]]:
48
+ open : float = lo_row['open']
49
+
50
+ entry_price_long, entry_price_short = open, open
51
+ allow_long, allow_short = False, False
52
+ reference_price = None
53
+
54
+ pnl_potential_bps = algo_param['tp_max_percent']*100
55
+
56
+ target_price_long = entry_price_long * (1 + pnl_potential_bps/10000)
57
+ target_price_short = entry_price_short * (1 - pnl_potential_bps/10000)
58
+
59
+ return {
60
+ 'long' : allow_long,
61
+ 'short' : allow_short,
62
+
63
+ # In additional to allow or not, allow_entry_final also calculate a few things which you may need to mark the entry trades.
64
+ 'entry_price_long' : entry_price_long,
65
+ 'entry_price_short' : entry_price_short,
66
+ 'target_price_long' : target_price_long,
67
+ 'target_price_short' : target_price_short,
68
+ 'reference_price' : reference_price
69
+ }
70
+
71
+ @staticmethod
72
+ def sl_adj(
73
+ algo_param : Dict,
74
+ *args: Any, **kwargs: Any
75
+ ) -> Dict[str, float]:
76
+ running_sl_percent_hard = algo_param['sl_hard_percent']
77
+ return {
78
+ 'running_sl_percent_hard' : running_sl_percent_hard
79
+ }
80
+
81
+ @staticmethod
82
+ def trailing_stop_threshold_eval(
83
+ algo_param : Dict,
84
+ *args: Any, **kwargs: Any
85
+ ) -> Dict[str, float]:
86
+ tp_min_percent = algo_param['tp_min_percent']
87
+ tp_max_percent = algo_param['tp_max_percent']
88
+ return {
89
+ 'tp_min_percent' : tp_min_percent,
90
+ 'tp_max_percent' : tp_max_percent
91
+ }
92
+
93
+ @staticmethod
94
+ def tp_eval (
95
+ lo_row,
96
+ this_ticker_open_trades : List[Dict],
97
+ algo_param : Dict
98
+ ) -> bool:
99
+ '''
100
+ Be very careful, backtest_core 'generic_pnl_eval' may use a) some indicator (tp_indicator_name), or b) target_price to evaluate 'unrealized_pnl_tp'.
101
+ 'tp_eval' only return True or False but it needs be congruent with backtest_core 'generic_pnl_eval', otherwise incorrect rosy pnl may be reported.
102
+ '''
103
+ return generic_tp_eval(lo_row, this_ticker_open_trades)
104
+
105
+ # List of TA/indicators you wish to include in POSITION_CACHE_COLUMNS from strategy_executor (Display concern only)
106
+ @staticmethod
107
+ def get_strategy_indicators() -> List[str]:
108
+ return []
109
+
110
+ @staticmethod
111
+ def get_strategy_algo_params() -> List[Dict[str, Any]]:
112
+ '''
113
+ [
114
+ {
115
+ 'key' : 'rsi_lower',
116
+ 'val' : 30
117
+ }
118
+ ]
119
+ '''
120
+ return [
121
+
122
+ ]