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.
@@ -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区域,开始下单。fvgbox={htf_fvg_boxes[-1]}")
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.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:
@@ -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': float(df.loc[idx, 'low']), # OB低点为当前K线的最低点
85
- 'bot': float(df.loc[idx - 1 if idx > df.index[0] else idx, 'body_high']) # OB高点为前一根K线的实体高点
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': float(df.loc[idx, 'high']), # OB高点为当前K线的最高点
98
- 'bot': float(df.loc[idx - 1 if idx > df.index[0] else idx, 'body_low']) # OB低点为前一根K线的实体低点
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(float(df.loc[idx - 1, 'low']),threshold), # FVG高点为右1K线的最低点
145
- 'bot': float(df.loc[idx - 3, 'high']) # FVG低点为左1K线的最高点
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': float(df.loc[idx - 3, 'low']), # FVG高点为右1K线的最高点
170
- 'bot': max(float(df.loc[idx - 1, 'high']),threshold) # FVG低点为左1K线的最低点
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"] = float(data.loc[last_struct["pivot_high_index"], 'high'])
447
- last_struct["pivot_low"] = float(data.loc[last_struct["pivot_low_index"], '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
- tick_size = self.get_tick_size(symbol)
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) -> float:
378
+ def calculate_ce(self, symbol, pivot_high:Decimal , pivot_low:Decimal) -> Decimal:
517
379
  ce = (pivot_high + pivot_low) / 2
518
- return float(self.round_price(symbol, ce))
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}: \npivot_high={pivot_high} pivot_low={pivot_low} mid_line={mid_line}\n溢价区={premium_box}\n折价区={discount_box}")
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: