openfund-maker 2.2.5__py3-none-any.whl → 2.2.7__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.
- maker/BestFVGStrategyMaker.py +23 -14
- maker/MACDStrategyMaker.py +2 -2
- maker/SMCStrategyMaker.py +50 -189
- maker/ThreeLineStrategyMaker.py +88 -49
- maker/main.py +16 -33
- {openfund_maker-2.2.5.dist-info → openfund_maker-2.2.7.dist-info}/METADATA +1 -1
- openfund_maker-2.2.7.dist-info/RECORD +15 -0
- {openfund_maker-2.2.5.dist-info → openfund_maker-2.2.7.dist-info}/WHEEL +1 -1
- maker/main_m.py +0 -378
- openfund_maker-2.2.5.dist-info/RECORD +0 -16
- /maker/{WickReversalStrategyMaker.py → history_code/WickReversalStrategyMaker.py} +0 -0
- /maker/{config.py → history_code/config.py} +0 -0
- /maker/{okxapi.py → history_code/okxapi.py} +0 -0
- /maker/{zhen.py.bak → history_code/zhen.py.bak} +0 -0
- /maker/{zhen_2.py → history_code/zhen_2.py} +0 -0
- {openfund_maker-2.2.5.dist-info → openfund_maker-2.2.7.dist-info}/entry_points.txt +0 -0
maker/BestFVGStrategyMaker.py
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import traceback
|
3
3
|
from typing import override
|
4
|
-
import pandas as pd
|
5
4
|
|
6
|
-
from maker.SMCStrategyMaker import SMCStrategyMaker
|
7
5
|
|
6
|
+
from maker.SMCStrategyMaker import SMCStrategyMaker
|
8
7
|
|
9
8
|
class BestFVGStrategyMaker(SMCStrategyMaker):
|
10
|
-
def __init__(self, config, platform_config, feishu_webhook=None,logger=None):
|
11
|
-
super().__init__(config, platform_config, feishu_webhook, logger)
|
9
|
+
def __init__(self, config, platform_config, common_config, feishu_webhook=None,logger=None):
|
10
|
+
super().__init__(config, platform_config, common_config, feishu_webhook, logger)
|
11
|
+
|
12
12
|
|
13
13
|
self.htf_last_CHoCH = {} #记录HTF的CHoCH struct
|
14
14
|
|
@@ -27,13 +27,22 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
27
27
|
return False
|
28
28
|
|
29
29
|
data = df.copy()
|
30
|
-
if struct_index is not None:
|
31
|
-
data = data.iloc[struct_index:]
|
32
30
|
|
33
31
|
fvg_top = fvg["top"]
|
34
32
|
fvg_bot = fvg["bot"]
|
35
33
|
fvg_index = fvg["index"]
|
36
34
|
|
35
|
+
# bug2.2.5_1,未等到折价区FVG就开单
|
36
|
+
# if struct_index is not None:
|
37
|
+
# data = data.iloc[struct_index:]
|
38
|
+
'''
|
39
|
+
FixMe: bug2.2.5_1 20230502
|
40
|
+
检查价格是否在FVG范围内,bar_index,跳过FVG相关的三根K线,从FVG下一根的K线开始检查
|
41
|
+
'''
|
42
|
+
if fvg_index is not None:
|
43
|
+
data = data.iloc[min(len(data),fvg_index+2):]
|
44
|
+
|
45
|
+
|
37
46
|
# 检查价格是否在FVG范围内,bar_index 从struct_index
|
38
47
|
if side == 'buy':
|
39
48
|
# 多头趋势检查最低价是否进入FVG区域
|
@@ -88,7 +97,7 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
88
97
|
|
89
98
|
htf_Klines = self.get_historical_klines(symbol=symbol, bar=htf)
|
90
99
|
htf_df = self.format_klines(htf_Klines)
|
91
|
-
|
100
|
+
precision = self.get_precision_length(symbol)
|
92
101
|
|
93
102
|
# 初始化HTF趋势相关变量
|
94
103
|
htf_side, valid_htf_struct = None, None
|
@@ -144,7 +153,7 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
144
153
|
}
|
145
154
|
|
146
155
|
self.logger.info(f"{symbol} : {htf} 趋势={htf_struct_label} 匹配 {htf_entry_struct} struct")
|
147
|
-
self.logger.debug(f"{symbol} : {htf}\npivot_high={htf_pivot_high} pivot_low={htf_pivot_low} mid_line={htf_mid_line}\n溢价区={premium_box}\n折价区={discount_box}")
|
156
|
+
self.logger.debug(f"{symbol} : {htf}\npivot_high={htf_pivot_high:.{precision}} pivot_low={htf_pivot_low:.{precision}} mid_line={htf_mid_line:.{precision}}\n溢价区={premium_box}\n折价区={discount_box}")
|
148
157
|
|
149
158
|
# 3. find HTF FVG
|
150
159
|
|
@@ -162,7 +171,7 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
162
171
|
self.logger.debug(f"{symbol} : 价格[未进入] HTF_FVG区域,不进行下单")
|
163
172
|
return
|
164
173
|
else:
|
165
|
-
self.logger.debug(f"{symbol} : 价格[进入] HTF_FVG
|
174
|
+
self.logger.debug(f"{symbol} : 价格[进入] HTF_FVG区域,开始下单。\n fvgbox={htf_fvg_boxes[-1]}")
|
166
175
|
|
167
176
|
# 4. LTF 判断struct趋势是否有CHoCH
|
168
177
|
|
@@ -190,7 +199,7 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
190
199
|
}
|
191
200
|
|
192
201
|
self.logger.info(f"{symbol} : {ltf} 趋势={ltf_struct_label} struct={ltf_struct}")
|
193
|
-
self.logger.debug(f"{symbol} : {ltf} \npivot_high={ltf_last_pivot_high} pivot_low={ltf_last_pivot_low} mid_line={ltf_last_mid_line}\n溢价区={ltf_premium_box}\n折价区={ltf_discount_box}")
|
202
|
+
self.logger.debug(f"{symbol} : {ltf} \npivot_high={ltf_last_pivot_high} pivot_low={ltf_last_pivot_low:.{precision}} mid_line={ltf_last_mid_line:.{precision}}\n溢价区={ltf_premium_box}\n折价区={ltf_discount_box}")
|
194
203
|
|
195
204
|
|
196
205
|
# 5. LTF 寻找FVG,下单
|
@@ -218,11 +227,11 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
218
227
|
|
219
228
|
|
220
229
|
# 4. LTF 寻找FVG,下单
|
221
|
-
order_price = ltf_fvg_boxes[-1]["top"] if ltf_struct_side == "buy" else ltf_fvg_boxes[-1]["bot"]
|
230
|
+
order_price = self.toDecimal(ltf_fvg_boxes[-1]["top"] if ltf_struct_side == "buy" else ltf_fvg_boxes[-1]["bot"] )
|
222
231
|
|
223
|
-
latest_order_price = self.place_order_prices.get(symbol,0
|
232
|
+
latest_order_price = self.toDecimal(self.place_order_prices.get(symbol,0))
|
224
233
|
if order_price == latest_order_price:
|
225
|
-
self.logger.debug(f"{symbol} : 下单价格 {order_price} 未变化,不进行下单。")
|
234
|
+
self.logger.debug(f"{symbol} : 下单价格 {order_price:.{precision}} 未变化,不进行下单。")
|
226
235
|
return
|
227
236
|
|
228
237
|
|
@@ -230,7 +239,7 @@ class BestFVGStrategyMaker(SMCStrategyMaker):
|
|
230
239
|
self.cancel_all_orders(symbol=symbol)
|
231
240
|
self.place_order(symbol=symbol, price=order_price, side=ltf_struct_side, pair_config=pair_config)
|
232
241
|
self.place_order_prices[symbol] = order_price # 记录下单价格,过滤重复下单
|
233
|
-
self.logger.debug(f"{symbol} : {ltf_struct_side}, 下单价格 {order_price}")
|
242
|
+
self.logger.debug(f"{symbol} : {ltf_struct_side}, 下单价格 {order_price:.{precision}}")
|
234
243
|
|
235
244
|
|
236
245
|
except KeyboardInterrupt:
|
maker/MACDStrategyMaker.py
CHANGED
@@ -8,8 +8,8 @@ from maker.ThreeLineStrategyMaker import ThreeLineStrategyMaker
|
|
8
8
|
|
9
9
|
|
10
10
|
class MACDStrategyMaker(ThreeLineStrategyMaker):
|
11
|
-
def __init__(self, config, platform_config, feishu_webhook=None,logger=None):
|
12
|
-
super().__init__(config, platform_config, feishu_webhook, logger)
|
11
|
+
def __init__(self, config, platform_config, common_config, feishu_webhook=None,logger=None):
|
12
|
+
super().__init__(config, platform_config, common_config, feishu_webhook, logger)
|
13
13
|
|
14
14
|
def get_macd_cross_direction(self, symbol, kLines, strategy=None) -> dict:
|
15
15
|
# 计算最近三个交叉点
|
maker/SMCStrategyMaker.py
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import traceback
|
3
3
|
import pandas as pd
|
4
|
+
from decimal import Decimal
|
4
5
|
|
5
|
-
from maker.ThreeLineStrategyMaker import ThreeLineStrategyMaker
|
6
6
|
|
7
|
+
from maker.ThreeLineStrategyMaker import ThreeLineStrategyMaker
|
7
8
|
|
8
9
|
class SMCStrategyMaker(ThreeLineStrategyMaker):
|
9
|
-
def __init__(self, config, platform_config, feishu_webhook=None,logger=None):
|
10
|
-
super().__init__(config, platform_config, feishu_webhook, logger)
|
10
|
+
def __init__(self, config, platform_config, common_config, feishu_webhook=None,logger=None):
|
11
|
+
super().__init__(config, platform_config, common_config, feishu_webhook, logger)
|
12
|
+
|
11
13
|
self.place_order_prices = {} # 记录每个symbol的挂单价格
|
12
14
|
|
13
|
-
def place_order(self,symbol, price, side,pair_config):
|
15
|
+
def place_order(self,symbol, price:Decimal, side,pair_config):
|
14
16
|
"""_summary_
|
15
17
|
下单
|
16
18
|
Args:
|
@@ -81,8 +83,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
81
83
|
OB_boxes = [
|
82
84
|
{
|
83
85
|
'index': idx,
|
84
|
-
'top':
|
85
|
-
'bot':
|
86
|
+
'top': self.toDecimal(df.loc[idx, 'low']), # OB低点为当前K线的最低点
|
87
|
+
'bot': self.toDecimal(df.loc[idx - 1 if idx > df.index[0] else idx, 'body_high']) # OB高点为前一根K线的实体高点
|
86
88
|
}
|
87
89
|
for idx in df.index
|
88
90
|
# 判断条件:是第一根K线(极值点)或当前下降趋势大于前一个,且前一根K线实体高点小于阈值
|
@@ -94,8 +96,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
94
96
|
OB_boxes = [
|
95
97
|
{
|
96
98
|
'index': idx,
|
97
|
-
'top':
|
98
|
-
'bot':
|
99
|
+
'top': self.toDecimal(df.loc[idx, 'high']), # OB高点为当前K线的最高点
|
100
|
+
'bot': self.toDecimal(df.loc[idx - 1 if idx > df.index[0] else idx, 'body_low']) # OB低点为前一根K线的实体低点
|
99
101
|
}
|
100
102
|
for idx in df.index
|
101
103
|
# 判断条件:是第一根K线(极值点)或当前上升趋势小于前一个,且前一根K线实体低点大于阈值
|
@@ -106,7 +108,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
106
108
|
return OB_boxes
|
107
109
|
|
108
110
|
|
109
|
-
def find_fvg_boxes(self, data, side, threshold, check_balanced=True, pivot_index=0, symbol=None, pair_config=None) -> list:
|
111
|
+
def find_fvg_boxes(self, data, side, threshold:Decimal, check_balanced=True, pivot_index=0, symbol=None, pair_config=None) -> list:
|
110
112
|
"""_summary_
|
111
113
|
寻找公允价值缺口
|
112
114
|
Args:
|
@@ -123,8 +125,9 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
123
125
|
# top: FVG的上边界价格,对应K线的最高价或最低价
|
124
126
|
# bot: FVG的下边界价格,对应K线的最高价或最低价
|
125
127
|
"""
|
126
|
-
|
127
|
-
df = data.copy().iloc[pivot_index:]
|
128
|
+
# bug2.2.5_1,未到折价区,计算FVG需要前一根K线
|
129
|
+
# df = data.copy().iloc[pivot_index:]
|
130
|
+
df = data.copy().iloc[max(0,pivot_index-1):]
|
128
131
|
|
129
132
|
fvg_boxes = []
|
130
133
|
if side == 'buy' :
|
@@ -141,8 +144,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
141
144
|
fvg_boxes = [
|
142
145
|
{
|
143
146
|
'index': idx - 2, # FVG的索引
|
144
|
-
'top': min(
|
145
|
-
'bot':
|
147
|
+
'top': min(self.toDecimal(df.loc[idx - 1, 'low']),threshold), # FVG高点为右1K线的最低点
|
148
|
+
'bot': self.toDecimal(df.loc[idx - 3, 'high']) # FVG低点为左1K线的最高点
|
146
149
|
}
|
147
150
|
# [df.loc[idx - 1, 'low'], df.loc[idx - 3, 'high'], idx - 2]
|
148
151
|
for idx in valid_indices
|
@@ -166,8 +169,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
166
169
|
fvg_boxes = [
|
167
170
|
{
|
168
171
|
'index': idx - 2, # FVG的索引
|
169
|
-
'top':
|
170
|
-
'bot': max(
|
172
|
+
'top': self.toDecimal(df.loc[idx - 3, 'low']), # FVG高点为右1K线的最高点
|
173
|
+
'bot': max(self.toDecimal(df.loc[idx - 1, 'high']),threshold) # FVG低点为左1K线的最低点
|
171
174
|
}
|
172
175
|
|
173
176
|
for idx in valid_indices
|
@@ -178,153 +181,6 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
178
181
|
|
179
182
|
return fvg_boxes
|
180
183
|
|
181
|
-
|
182
|
-
# def detect_struct(self, data, prd=10, struct_key=None, check_valid_range=True, check_bounds=True, global_extremum=False, s1=True, resp=7) -> dict:
|
183
|
-
# """_summary_
|
184
|
-
# 识别SMC结构,参考 Tradingview Smart Money Concepts Probability (Expo)@Openfund
|
185
|
-
|
186
|
-
# Args:
|
187
|
-
# data (df): df格式的K线数据
|
188
|
-
# prd (int): 计算Swing Points的bar数量
|
189
|
-
# struct_key (str): 结构类型,如 'CHoCH'|'SMS'|'BMS'
|
190
|
-
# check_valid_range (bool): 结构类型在 pivot_high_index 和 pivot_low_index 之间为有效范围内,默认为False
|
191
|
-
# check_bounds (bool): 计算Swing Points是否检查边界,默认为True
|
192
|
-
# global_extremum (bool): 是否使用全局极值点,默认为False
|
193
|
-
# s1 (bool): 结构响应布尔值
|
194
|
-
# resp (int): 响应周期
|
195
|
-
# Returns:
|
196
|
-
# dict: 包含结构识别结果的字典,包含以下字段:
|
197
|
-
# "struct": 结构类型,如 'Bullish_CHoCH'|'Bullish_SMS'|'Bullish_BMS'|'Bearish_CHoCH'|'Bearish_SMS'|'Bearish_BMS'
|
198
|
-
# "index": 结构出现的位置索引
|
199
|
-
# "pivot_high": 枢轴高点价格
|
200
|
-
# "pivot_high_index": 枢轴高点索引
|
201
|
-
# "pivot_low": 枢轴低点价格
|
202
|
-
# "pivot_low_index": 枢轴低点索引
|
203
|
-
# "side": 交易方向,'buy'或'sell'
|
204
|
-
|
205
|
-
|
206
|
-
# """
|
207
|
-
|
208
|
-
# # data = data.copy()
|
209
|
-
# data['Up'] = None
|
210
|
-
# data['Dn'] = None
|
211
|
-
# data['iUp'] = None
|
212
|
-
# data['iDn'] = None
|
213
|
-
# data['pos'] = 0
|
214
|
-
# data['pattern'] = None
|
215
|
-
|
216
|
-
# # 初始化 Up 和 Dn 的第一个值
|
217
|
-
# data.at[0, 'Up'] = data.at[0, 'high']
|
218
|
-
# data.at[0, 'Dn'] = data.at[0, 'low']
|
219
|
-
|
220
|
-
|
221
|
-
# for index in range(1, len(data)):
|
222
|
-
|
223
|
-
# data.at[index, 'Up'] = max(data.at[index - 1, 'Up'], data.at[index, 'high'])
|
224
|
-
# data.at[index, 'Dn'] = min(data.at[index - 1, 'Dn'], data.at[index, 'low'])
|
225
|
-
# data.at[index, 'pos'] = data.at[index - 1, 'pos']
|
226
|
-
# data.at[index, 'iUp'] = data.at[max(0,index - 1), 'iUp'] if data.at[max(0,index - 1), 'iUp'] is not None else index
|
227
|
-
# data.at[index, 'iDn'] = data.at[max(0,index - 1), 'iDn'] if data.at[max(0,index - 1), 'iDn'] is not None else index
|
228
|
-
|
229
|
-
# # 寻找枢轴高点和低点
|
230
|
-
# pvtHi = self.is_pivot_high(data, index, prd, check_bounds)
|
231
|
-
# pvtLo = self.is_pivot_low(data, index, prd, check_bounds)
|
232
|
-
|
233
|
-
# if pvtHi:
|
234
|
-
# data.at[index, 'Up'] = data.at[index, 'high']
|
235
|
-
# data.at[index, 'iUp'] = index
|
236
|
-
# if pvtLo:
|
237
|
-
# data.at[index, 'Dn'] = data.at[index, 'low']
|
238
|
-
# data.at[index, 'iDn'] = index
|
239
|
-
# # 寻找Bullish结构
|
240
|
-
# if data.at[index, 'Up'] > data.at[index - 1, 'Up']:
|
241
|
-
|
242
|
-
# data.at[index, 'iUp'] = index
|
243
|
-
# if data.at[index - 1, 'pos'] <= 0:
|
244
|
-
# # data.at[index, 'pattern'] = 'CHoCH (Bullish)'
|
245
|
-
# data.at[index, 'pattern'] = 'Bullish_CHoCH'
|
246
|
-
# data.at[index, 'pos'] = 1
|
247
|
-
# elif data.at[index - 1, 'pos'] == 1 \
|
248
|
-
# and data.at[index - 1, 'Up'] == data.at[max(0,index - (resp if s1 else prd)), 'Up']:
|
249
|
-
# data.at[index, 'pattern'] = 'Bullish_SMS'
|
250
|
-
# data.at[index, 'pos'] = 2
|
251
|
-
|
252
|
-
# elif data.at[index - 1, 'pos'] > 1 \
|
253
|
-
# and data.at[index - 1, 'Up'] == data.at[max(0,index - (resp if s1 else prd)), 'Up']:
|
254
|
-
# data.at[index, 'pattern'] = 'Bullish_BMS'
|
255
|
-
# data.at[index, 'pos'] = data.at[index - 1, 'pos'] + 1
|
256
|
-
|
257
|
-
# elif global_extremum and data.at[index, 'Up'] < data.at[index - 1, 'Up']:
|
258
|
-
# data.at[index, 'iUp'] = data.at[index - 1, 'iUp']
|
259
|
-
|
260
|
-
# # # 寻找Bearish结构
|
261
|
-
# if data.at[index, 'Dn'] < data.at[index - 1, 'Dn']:
|
262
|
-
# data.at[index, 'iDn'] = index
|
263
|
-
# if data.at[index - 1, 'pos'] >= 0:
|
264
|
-
|
265
|
-
# data.at[index, 'pattern'] = 'Bearish_CHoCH'
|
266
|
-
# data.at[index, 'pos'] = -1
|
267
|
-
# elif data.at[index - 1, 'pos'] == -1 \
|
268
|
-
# and data.at[index - 1, 'Dn'] == data.at[max(0,index - (resp if s1 else prd)), 'Dn']:
|
269
|
-
# data.at[index, 'pattern'] = 'Bearish_SMS'
|
270
|
-
# data.at[index, 'pos'] = -2
|
271
|
-
# elif data.at[index - 1, 'pos'] < -1 \
|
272
|
-
# and data.at[index - 1, 'Dn'] == data.at[max(0,index - (resp if s1 else prd)), 'Dn']:
|
273
|
-
# data.at[index, 'pattern'] = 'Bearish_BMS'
|
274
|
-
# data.at[index, 'pos'] = data.at[index - 1, 'pos'] - 1
|
275
|
-
|
276
|
-
# elif global_extremum and data.at[index, 'Dn'] > data.at[index - 1, 'Dn']:
|
277
|
-
# data.at[index, 'iDn'] = data.at[index - 1, 'iDn']
|
278
|
-
|
279
|
-
# # 获取最后一个结构和位置
|
280
|
-
# last_struct = {
|
281
|
-
# "struct": None,
|
282
|
-
# "index": -1,
|
283
|
-
# "pivot_high": None,
|
284
|
-
# "pivot_high_index": -1,
|
285
|
-
# "pivot_low": None,
|
286
|
-
# "pivot_low_index": -1,
|
287
|
-
# "side": None
|
288
|
-
|
289
|
-
# }
|
290
|
-
|
291
|
-
|
292
|
-
# for i in range(len(data)-1, -1, -1):
|
293
|
-
# if check_valid_range:
|
294
|
-
# # 检查是否在pivot_high_index和pivot_low_index之间的有效范围内
|
295
|
-
# if data.at[i, 'iUp'] != -1 and data.at[i, 'iDn'] != -1:
|
296
|
-
# pivot_high_index = data.at[i, 'iUp']
|
297
|
-
# pivot_low_index = data.at[i, 'iDn']
|
298
|
-
# if i < min(pivot_high_index, pivot_low_index) or i > max(pivot_high_index, pivot_low_index):
|
299
|
-
# continue
|
300
|
-
|
301
|
-
# if data.at[i, 'pattern'] is not None:
|
302
|
-
# if struct_key is not None and struct_key not in data.at[i, 'pattern']:
|
303
|
-
# continue
|
304
|
-
# last_struct["struct"] = data.at[i, 'pattern']
|
305
|
-
# last_struct["index"] = i
|
306
|
-
|
307
|
-
# break
|
308
|
-
|
309
|
-
# if last_struct['struct'] is not None :
|
310
|
-
# # 找到最后一个结构的枢轴高点和低点,如果当前是孤立点,则取前一个孤立点
|
311
|
-
# # 判断交易方向
|
312
|
-
# if 'Bearish' in last_struct["struct"]:
|
313
|
-
# last_struct["side"] = 'sell'
|
314
|
-
# else :
|
315
|
-
# last_struct["side"] = 'buy'
|
316
|
-
|
317
|
-
# last_struct["pivot_high_index"] = int(data["iUp"].iloc[-1])
|
318
|
-
# last_struct["pivot_low_index"] = int(data["iDn"].iloc[-1])
|
319
|
-
|
320
|
-
# last_struct["pivot_high"] = float(data.loc[last_struct["pivot_high_index"], 'high'])
|
321
|
-
# last_struct["pivot_low"] = float(data.loc[last_struct["pivot_low_index"], 'low'])
|
322
|
-
# else:
|
323
|
-
# last_struct['struct'] = "None"
|
324
|
-
# last_struct["index"] = -1
|
325
|
-
|
326
|
-
|
327
|
-
# return last_struct
|
328
184
|
def build_struct(self, df, prd=20, check_bounds=True, global_extremum=False) :
|
329
185
|
|
330
186
|
"""_summary_
|
@@ -344,9 +200,16 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
344
200
|
|
345
201
|
|
346
202
|
for index in range(1, len(data)):
|
203
|
+
prev_up = self.toDecimal(data.at[index - 1, 'Up'])
|
204
|
+
curr_high = self.toDecimal(data.at[index, 'high'])
|
205
|
+
prev_dn = self.toDecimal(data.at[index - 1, 'Dn'])
|
206
|
+
curr_low = self.toDecimal(data.at[index, 'low'])
|
207
|
+
|
208
|
+
data.at[index, 'Up'] = max(prev_up, curr_high)
|
209
|
+
data.at[index, 'Dn'] = min(prev_dn, curr_low)
|
347
210
|
|
348
|
-
data.at[index, 'Up'] = max(data.at[index - 1, 'Up'], data.at[index, 'high'])
|
349
|
-
data.at[index, 'Dn'] = min(data.at[index - 1, 'Dn'], data.at[index, 'low'])
|
211
|
+
# data.at[index, 'Up'] = max(data.at[index - 1, 'Up'], data.at[index, 'high'])
|
212
|
+
# data.at[index, 'Dn'] = min(data.at[index - 1, 'Dn'], data.at[index, 'low'])
|
350
213
|
data.at[index, 'pos'] = data.at[index - 1, 'pos']
|
351
214
|
data.at[index, 'iUp'] = data.at[max(0,index - 1), 'iUp'] if data.at[max(0,index - 1), 'iUp'] is not None else index
|
352
215
|
data.at[index, 'iDn'] = data.at[max(0,index - 1), 'iDn'] if data.at[max(0,index - 1), 'iDn'] is not None else index
|
@@ -356,10 +219,10 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
356
219
|
pvtLo = self.is_pivot_low(data, index, prd, check_bounds)
|
357
220
|
|
358
221
|
if pvtHi:
|
359
|
-
data.at[index, 'Up'] = data.at[index, 'high']
|
222
|
+
data.at[index, 'Up'] = self.toDecimal(data.at[index, 'high'])
|
360
223
|
data.at[index, 'iUp'] = index
|
361
224
|
if pvtLo:
|
362
|
-
data.at[index, 'Dn'] = data.at[index, 'low']
|
225
|
+
data.at[index, 'Dn'] = self.toDecimal(data.at[index, 'low'])
|
363
226
|
data.at[index, 'iDn'] = index
|
364
227
|
# 寻找Bullish结构
|
365
228
|
if data.at[index, 'Up'] > data.at[index - 1, 'Up']:
|
@@ -443,8 +306,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
443
306
|
pivot_high_index = last_struct["pivot_high_index"] = int(data["iUp"].iloc[-1])
|
444
307
|
pivot_low_index = last_struct["pivot_low_index"] = int(data["iDn"].iloc[-1])
|
445
308
|
|
446
|
-
last_struct["pivot_high"] =
|
447
|
-
last_struct["pivot_low"] =
|
309
|
+
last_struct["pivot_high"] = self.toDecimal(data.loc[last_struct["pivot_high_index"], 'high'])
|
310
|
+
last_struct["pivot_low"] = self.toDecimal(data.loc[last_struct["pivot_low_index"], 'low'])
|
448
311
|
|
449
312
|
for i in range(len(data)-1, -1, -1):
|
450
313
|
if check_valid_range:
|
@@ -509,17 +372,12 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
509
372
|
next_lows = data['low'].iloc[index+1 :min(len(data),index + period)+1]
|
510
373
|
return all(current_low <= prev_lows) and all(current_low < next_lows)
|
511
374
|
|
512
|
-
def round_price(self,symbol, price):
|
513
|
-
|
514
|
-
return super().round_price_to_tick(price, tick_size)
|
375
|
+
# def round_price(self,symbol, price: Decimal) -> Decimal:
|
376
|
+
# return super().round_price_to_tick(symbol, price)
|
515
377
|
|
516
|
-
def calculate_ce(self,symbol,pivot_high , pivot_low) ->
|
378
|
+
def calculate_ce(self, symbol, pivot_high:Decimal , pivot_low:Decimal) -> Decimal:
|
517
379
|
ce = (pivot_high + pivot_low) / 2
|
518
|
-
return
|
519
|
-
|
520
|
-
def calculate_pe(self,symbol,pivot_high, pivot_low) -> float:
|
521
|
-
pe = (pivot_high + pivot_low) / 2
|
522
|
-
return float(self.round_price(symbol, pe))
|
380
|
+
return self.round_price_to_tick(symbol, ce)
|
523
381
|
|
524
382
|
def reset_all_cache(self, symbol):
|
525
383
|
"""_summary_
|
@@ -567,7 +425,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
567
425
|
swing_points_length = smc_strategy.get('swing_points_length',10)
|
568
426
|
htf_last_struct = self.detect_struct(htf_df,prd=swing_points_length)
|
569
427
|
htf_last_struct_label = htf_last_struct["struct"]
|
570
|
-
|
428
|
+
precision = self.get_precision_length(symbol)
|
571
429
|
|
572
430
|
if htf_last_struct_label is None:
|
573
431
|
self.logger.debug(f"{symbol} : {htf} 未形成 struct,不下单。{htf_last_struct}。")
|
@@ -585,8 +443,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
585
443
|
|
586
444
|
|
587
445
|
# 2. HTF 获取最新的两个极值点,设置折价(discount)区和溢价(premium)区
|
588
|
-
pivot_high = htf_last_struct["pivot_high"]
|
589
|
-
pivot_low = htf_last_struct["pivot_low"]
|
446
|
+
pivot_high = self.toDecimal(htf_last_struct["pivot_high"])
|
447
|
+
pivot_low = self.toDecimal(htf_last_struct["pivot_low"])
|
590
448
|
mid_line = self.calculate_ce(symbol,pivot_high,pivot_low)
|
591
449
|
|
592
450
|
# 计算溢价和折价区
|
@@ -601,13 +459,16 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
601
459
|
'ce': self.calculate_ce(symbol,mid_line,pivot_low)
|
602
460
|
}
|
603
461
|
|
604
|
-
self.logger.debug(f"{symbol} : {htf} 趋势={htf_last_struct_label}: \
|
462
|
+
self.logger.debug(f"{symbol} : {htf} 趋势={htf_last_struct_label}: \n" \
|
463
|
+
f"pivot_high={pivot_high:.{precision}} pivot_low={pivot_low:.{precision}} mid_line={mid_line:.{precision}}\n" \
|
464
|
+
f"溢价区={premium_box}\n"
|
465
|
+
f"折价区={discount_box}")
|
605
466
|
|
606
467
|
# 3. 根据HTF结构来分析下单位置和止盈位置
|
607
|
-
threshold = 0.0
|
468
|
+
threshold = self.toDecimal(0.0)
|
608
469
|
order_side = side
|
609
470
|
# 获取当前市场价格
|
610
|
-
market_price = ctf_df['close'].iloc[-1]
|
471
|
+
market_price = self.toDecimal(ctf_df['close'].iloc[-1])
|
611
472
|
|
612
473
|
if 'CHoCH' in htf_last_struct_label:
|
613
474
|
"""
|
@@ -660,14 +521,14 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
660
521
|
|
661
522
|
|
662
523
|
if threshold == 0.0:
|
663
|
-
self.logger.debug(f"{symbol} : 价格{market_price}不在目标区域,不下单。")
|
524
|
+
self.logger.debug(f"{symbol} : 价格{market_price:.{precision}}不在目标区域,不下单。")
|
664
525
|
# 取消所有未成交订单
|
665
526
|
self.cancel_all_orders(symbol=symbol)
|
666
527
|
return
|
667
528
|
|
668
529
|
|
669
530
|
# 4. 在CTF折价区获取FVG的位置
|
670
|
-
order_price = 0.0
|
531
|
+
order_price = self.toDecimal(0.0)
|
671
532
|
|
672
533
|
if enable_FVG and order_price == 0.0:
|
673
534
|
|
@@ -693,7 +554,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
693
554
|
if len(fvg_boxes) != 0 and order_price == 0.0:
|
694
555
|
last_fvg_box = fvg_boxes[-1]
|
695
556
|
ce_price = self.calculate_ce(symbol,last_fvg_box['top'],last_fvg_box['bot'])
|
696
|
-
self.logger.info(f"{symbol} : 方向={order_side}, FVG_ce={ce_price} FVG={last_fvg_box} ")
|
557
|
+
self.logger.info(f"{symbol} : 方向={order_side}, FVG_ce={ce_price:.{precision}} FVG={last_fvg_box} ")
|
697
558
|
order_price = ce_price
|
698
559
|
|
699
560
|
# 4. 找OB位置,OB规则孤立高点+实体低点 孤立低点+实体高点
|
@@ -712,7 +573,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
712
573
|
if len(OB_boxes) != 0 :
|
713
574
|
last_OB_box = OB_boxes[-1]
|
714
575
|
ce_price = self.calculate_ce(symbol,last_OB_box['top'],last_OB_box['bot'])
|
715
|
-
self.logger.info(f"{symbol} : 方向={order_side}, OB_ce={ce_price} , OB={last_OB_box} ")
|
576
|
+
self.logger.info(f"{symbol} : 方向={order_side}, OB_ce={ce_price:.{precision}} , OB={last_OB_box} ")
|
716
577
|
order_price = ce_price
|
717
578
|
|
718
579
|
if order_price == 0.0:
|
@@ -722,7 +583,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
722
583
|
|
723
584
|
latest_order_price = self.place_order_prices.get(symbol,0.0)
|
724
585
|
if order_price == latest_order_price:
|
725
|
-
self.logger.debug(f"{symbol} : 下单价格 {order_price} 未变化,不进行下单。")
|
586
|
+
self.logger.debug(f"{symbol} : 下单价格 {order_price:.{precision}} 未变化,不进行下单。")
|
726
587
|
return
|
727
588
|
|
728
589
|
|
@@ -730,7 +591,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
730
591
|
self.cancel_all_orders(symbol=symbol)
|
731
592
|
self.place_order(symbol=symbol, price=order_price, side=order_side, pair_config=pair_config)
|
732
593
|
self.place_order_prices[symbol] = order_price # 记录下单价格,过滤重复下单
|
733
|
-
self.logger.debug(f"{symbol} : {side}, 下单价格 {order_price}")
|
594
|
+
self.logger.debug(f"{symbol} : {side}, 下单价格 {order_price:.{precision}}")
|
734
595
|
|
735
596
|
|
736
597
|
except KeyboardInterrupt:
|