openfund-core 1.0.8__py3-none-any.whl → 1.0.10__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.
core/Exchange.py CHANGED
@@ -24,8 +24,6 @@ class Exchange:
24
24
  self.exchange = getattr(ccxt, exchangeKey)(config)
25
25
  self.logger = logging.getLogger(__name__)
26
26
 
27
-
28
-
29
27
  def getMarket(self, symbol:str):
30
28
  # 配置交易对
31
29
  self.exchange.load_markets()
@@ -61,9 +59,7 @@ class Exchange:
61
59
 
62
60
  def amount_to_precision(self,symbol, contract_size):
63
61
  return self.exchange.amount_to_precision(symbol, contract_size)
64
-
65
-
66
-
62
+
67
63
  def set_leverage(self,symbol, leverage, mgnMode='isolated',posSide=None):
68
64
  try:
69
65
  # 设置杠杆
@@ -166,8 +162,7 @@ class Exchange:
166
162
  else:
167
163
  self.logger.warning(f"{symbol} 平仓失败,正在进行第{retry_count}次重试: {str(e)}")
168
164
  time.sleep(0.1) # 重试前等待0.1秒
169
-
170
-
165
+
171
166
  def cancel_all_orders(self, symbol):
172
167
  max_retries = 3
173
168
  retry_count = 0
@@ -257,6 +252,7 @@ class Exchange:
257
252
 
258
253
  self.logger.warning(f"{symbol} : Error cancelling order {algo_ids}: {str(e)}")
259
254
  time.sleep(0.1) # 重试前等待0.1秒
255
+
260
256
  def place_algo_orders(self, symbol, position, price: Decimal, order_type, sl_or_tp='SL', params={}) -> bool:
261
257
  """
262
258
  下单
@@ -323,47 +319,23 @@ class Exchange:
323
319
  self.logger.info(f"{symbol} : Pre Algo Order placed: {order} ")
324
320
  while retry_count < max_retries:
325
321
  try:
322
+ # 创建订单
323
+ order_result = self.exchange.create_order(**order)
324
+ self.logger.info(f"{symbol} : --------- ++ Algo Order placed done. --------")
325
+ return True
326
326
 
327
- self.exchange.create_order(
328
- **order
329
- # symbol=symbol,
330
- # type=order_type,
331
- # price=adjusted_price,
332
- # side=orderSide,
333
- # amount=amount,
334
- # params=order_params
335
- )
336
-
337
- break
338
-
339
- except ccxt.NetworkError as e:
340
- # 处理网络相关错误
341
- retry_count += 1
342
- self.logger.warning(f"{symbol} : 设置止盈止损时发生网络错误,正在进行第{retry_count}次重试: {str(e)}")
343
- time.sleep(0.1) # 重试前等待1秒
344
- continue
345
- except ccxt.ExchangeError as e:
346
- # 处理交易所API相关错误
327
+ except (ccxt.NetworkError, ccxt.ExchangeError, Exception) as e:
347
328
  retry_count += 1
348
- self.logger.warning(f"{symbol} : 设置止盈止损单时发生交易所错误,正在进行第{retry_count}次重试: {str(e)}")
349
- time.sleep(0.1)
350
- continue
351
- except Exception as e:
352
- # 处理其他未预期的错误
353
- retry_count += 1
354
- self.logger.warning(f"{symbol} : 设置止盈止损单时发生未知错误,正在进行第{retry_count}次重试: {str(e)}")
329
+ error_type = "网络" if isinstance(e, ccxt.NetworkError) else "交易所" if isinstance(e, ccxt.ExchangeError) else "未知"
330
+ self.logger.warning(f"{symbol} : 设置止盈止损单时发生{error_type}错误,正在进行第{retry_count}次重试: {str(e)}")
331
+
332
+ if retry_count == max_retries:
333
+ error_message = f"!! {symbol}: 设置止盈止损单失败(重试{max_retries}次): {str(e)}"
334
+ self.logger.error(error_message)
335
+ raise Exception(error_message)
336
+
355
337
  time.sleep(0.1)
356
- continue
357
-
358
- if retry_count >= max_retries:
359
- # 重试次数用完仍未成功设置止损单
360
- error_message = f"!! {symbol}: 设置止盈止损单时重试次数用完仍未成功设置成功。 "
361
- self.logger.error(error_message)
362
- raise Exception(error_message)
363
- self.logger.debug(f"{symbol} : --------- ++ Order placed done. --------")
364
- return True
365
338
 
366
-
367
339
  def place_order(self, symbol, price: Decimal, amount_usdt, side, leverage=20, order_type='limit', params={}) -> bool:
368
340
  """
369
341
  下单
@@ -418,40 +390,18 @@ class Exchange:
418
390
  while retry_count < max_retries:
419
391
  try:
420
392
  # 使用ccxt创建订单
421
- order_result = self.exchange.create_order(
422
- **order
423
- # symbol=symbol,
424
- # type='limit',
425
- # side=side,
426
- # amount=amount_usdt,
427
- # price=float(adjusted_price),
428
- # params=params
429
- )
430
- except ccxt.NetworkError as e:
431
- # 处理网络相关错误
432
- retry_count += 1
433
- self.logger.warning(f"{symbol} : 下单时发生网络错误,正在进行第{retry_count}次重试: {str(e)}")
434
- time.sleep(0.1) # 重试前等待1秒
435
- continue
436
- except ccxt.ExchangeError as e:
437
- # 处理交易所API相关错误
438
- retry_count += 1
439
- self.logger.warning(f"{symbol} : 下单时发生交易所错误,正在进行第{retry_count}次重试: {str(e)}")
440
- time.sleep(0.1)
441
- continue
442
- except Exception as e:
443
- # 处理其他未预期的错误
393
+ order_result = self.exchange.create_order(**order)
394
+ self.logger.info(f"{symbol} : --------- ++ Order placed done. --------")
395
+ return True
396
+ except (ccxt.NetworkError, ccxt.ExchangeError, Exception) as e:
444
397
  retry_count += 1
445
- self.logger.warning(f"{symbol} : 下单时发生未知错误,正在进行第{retry_count}次重试: {str(e)}")
446
- time.sleep(0.1)
447
- continue
448
- if retry_count >= max_retries:
449
- # 重试次数用完仍未成功设置止损单
450
- error_message = f"!! {symbol}: 下单时重试次数用完仍未成功设置成功。 "
451
- self.logger.error(error_message)
452
- raise Exception(error_message)
453
- self.logger.debug(f"{symbol} : --------- ++ Order placed done. --------")
454
- return True
398
+ error_type = "网络" if isinstance(e, ccxt.NetworkError) else "交易所" if isinstance(e, ccxt.ExchangeError) else "未知"
399
+ self.logger.warning(f"{symbol} : 下单时发生{error_type}错误,正在进行第{retry_count}次重试: {str(e)}")
400
+ if retry_count == max_retries:
401
+ error_message = f"!! {symbol}: 下单时重试{max_retries}次后仍未成功:{str(e)}"
402
+ self.logger.error(error_message)
403
+ raise Exception(error_message)
404
+ time.sleep(1)
455
405
 
456
406
  def fetch_position(self, symbol):
457
407
  """_summary_
@@ -523,6 +473,7 @@ class Exchange:
523
473
 
524
474
  self.logger.warning(f"{symbol} : Error fetching open orders: {str(e)}")
525
475
  time.sleep(0.1) # 重试前等待0.1秒
476
+
526
477
  def get_market_price(self, symbol) -> Decimal:
527
478
  """
528
479
  获取最新价格
core/smc/SMCLiquidity.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from decimal import Decimal
2
3
  from core.smc.SMCStruct import SMCStruct
3
4
 
4
5
 
@@ -27,20 +28,17 @@ class SMCLiquidity(SMCStruct):
27
28
  df = data.copy()
28
29
 
29
30
  # 识别高点
30
- df[self.LIQU_HIGH_COL] = 0
31
+ df[self.LIQU_HIGH_COL] = Decimal(0.0)
31
32
  for i in range(pivot_length, len(df) - pivot_length):
32
33
  if df[self.HIGH_COL].iloc[i] == max(df[self.HIGH_COL].iloc[i-pivot_length:i+pivot_length+1]):
33
- df.loc[df.index[i], self.LIQU_HIGH_COL] = df[self.HIGH_COL].iloc[i]
34
-
34
+ df.loc[df.index[i], self.LIQU_HIGH_COL] = df[self.HIGH_COL].iloc[i]
35
35
  # 识别低点
36
- df[self.LIQU_LOW_COL] = 0
36
+ df[self.LIQU_LOW_COL] = Decimal(0.0)
37
37
  for i in range(pivot_length, len(df) - pivot_length):
38
38
 
39
39
  if df[self.LOW_COL].iloc[i] == min(df[self.LOW_COL].iloc[i-pivot_length:i+pivot_length+1]):
40
40
  df.loc[df.index[i], self.LIQU_LOW_COL] = df[self.LOW_COL].iloc[i]
41
41
 
42
-
43
-
44
42
  return df
45
43
 
46
44
  def find_EQH_EQL(self, data, trend, end_idx=-1, atr_offset=0.1) -> dict:
@@ -63,7 +61,7 @@ class SMCLiquidity(SMCStruct):
63
61
  try:
64
62
  self.check_columns(df, check_columns)
65
63
  except ValueError as e:
66
- self.logger.warning(f"DataFrame must contain columns {check_columns} : {str(e)}")
64
+ # self.logger.warning(f"DataFrame must contain columns {check_columns} : {str(e)}")
67
65
  df = self._identify_liquidity_pivots(df)
68
66
 
69
67
  df = df[(df[self.LIQU_HIGH_COL] > 0) | (df[self.LIQU_LOW_COL] > 0)]
core/smc/SMCPDArray.py CHANGED
@@ -9,13 +9,14 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
9
9
  PD_LOW_COL = "pd_low"
10
10
  PD_MID_COL = "pd_mid"
11
11
  PD_TYPE_COL = "pd_type"
12
+ PD_WAS_BALANCED_COL = "pd_was_balanced"
12
13
 
13
14
  def __init__(self):
14
15
  super().__init__()
15
16
  self.logger = logging.getLogger(__name__)
16
17
 
17
18
  def find_PDArrays(
18
- self, struct: pd.DataFrame, side, start_index=-1, check_balanced=True,
19
+ self, struct: pd.DataFrame, side, start_index=-1, balanced=False,
19
20
  ) -> pd.DataFrame:
20
21
  """_summary_
21
22
  寻找PDArrays,包括Fair Value Gap (FVG)|Order Block (OB)|Breaker Block(BB)|Mitigation Block(BB)
@@ -23,7 +24,7 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
23
24
  data (pd.DataFrame): K线数据
24
25
  side (_type_): 交易方向 'buy'|'sell'
25
26
  start_index (int): 开始查找索引的起点,默认为-1
26
- check_balanced (bool): PD是否有效,默认为True。PD被crossed过,则是无效PD
27
+ balanced (bool): PD是否有效,默认为False。PD被crossed过,则是无效PD
27
28
 
28
29
  Returns:
29
30
  pd.DataFrame: _description_
@@ -36,11 +37,14 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
36
37
  else struct.copy().iloc[max(0, start_index - 1) :]
37
38
  )
38
39
 
39
- df_FVGs = self.find_FVGs(df, side, check_balanced, start_index)
40
- # self.logger.info(f"fvgs:\n{df_FVGs[['timestamp', self.FVG_SIDE, self.FVG_TOP, self.FVG_BOT, self.FVG_WAS_BALANCED]]}")
40
+ df_FVGs = self.find_FVGs(df, side, start_index)
41
41
 
42
+ if not balanced:
43
+ df_FVGs = df_FVGs[~df_FVGs[self.FVG_WAS_BALANCED]]
44
+ # self.logger.info(f"fvgs:\n{df_FVGs[['timestamp', self.FVG_SIDE, self.FVG_TOP, self.FVG_BOT, self.FVG_WAS_BALANCED]]}")
42
45
 
43
- df_OBs = self.find_OBs(df, side, start_index, is_valid=check_balanced)
46
+ is_valid = not balanced
47
+ df_OBs = self.find_OBs(struct=df, side=side, start_index=start_index, is_valid=is_valid)
44
48
  # self.logger.info("find_OBs:\n %s", df_OBs)
45
49
 
46
50
  # 使用更简洁的方式重命名和合并时间戳列
@@ -59,6 +63,10 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
59
63
  df_PDArrays[self.TIMESTAMP_COL] = df_PDArrays[timestamp_mapping[self.TIMESTAMP_COL][0]].fillna(
60
64
  df_PDArrays[timestamp_mapping[self.TIMESTAMP_COL][1]]
61
65
  )
66
+
67
+ df_PDArrays[self.PD_WAS_BALANCED_COL] = df_PDArrays[[self.OB_WAS_CROSSED, self.FVG_WAS_BALANCED]].apply(
68
+ lambda x: x.iloc[0] if pd.notna(x.iloc[0]) else x.iloc[1], axis=1)
69
+
62
70
  df_PDArrays[self.PD_TYPE_COL] = df_PDArrays[[self.FVG_SIDE, self.OB_DIRECTION_COL]].apply(
63
71
  lambda x: 'FVG-OB' if pd.notna(x.iloc[0]) and pd.notna(x.iloc[1]) else 'FVG' if pd.notna(x.iloc[0]) else 'OB', axis=1
64
72
  )
@@ -68,10 +76,12 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
68
76
  df_PDArrays.loc[:, self.PD_MID_COL] = (df_PDArrays[self.PD_HIGH_COL] + df_PDArrays[self.PD_LOW_COL]) / 2
69
77
 
70
78
 
71
- return df_PDArrays
79
+ # 根据balanced参数过滤PDArrays,返回符合条件的数据
80
+
81
+ return df_PDArrays[df_PDArrays[self.PD_WAS_BALANCED_COL] == balanced]
72
82
 
73
83
 
74
- def get_latest_PDArray(self, df_PDArrays: pd.DataFrame, side, start_index=-1, check_balanced=True, mask:str=None) -> dict:
84
+ def get_latest_PDArray(self, df_PDArrays: pd.DataFrame, side, start_index=-1, balanced=False, mask=None) -> dict:
75
85
  """_summary_
76
86
  过滤PDArrays,只保留指定方向的PDArrays
77
87
  Args:
@@ -89,16 +99,22 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
89
99
  self.check_columns(df, check_columns)
90
100
  except ValueError as e:
91
101
  df = self.build_struct(df)
92
-
93
- df = self.find_PDArrays(df, side, start_index, check_balanced)
94
102
 
95
- if mask:
96
- df = df[df[mask]]
103
+
104
+ check_columns = [self.PD_TYPE_COL]
105
+ try:
106
+ self.check_columns(df, check_columns)
107
+ except ValueError as e:
108
+ df = self.find_PDArrays(df, side, start_index, balanced)
109
+
110
+ if mask is not None:
111
+ df = df[mask]
97
112
 
98
113
  if len(df) == 0:
99
114
  self.logger.info("未找到PDArray.")
100
115
  return None
101
116
  else:
117
+ self.logger.debug(f"PDArray:\n{df[[self.TIMESTAMP_COL, self.PD_TYPE_COL, self.PD_HIGH_COL, self.PD_LOW_COL, self.PD_MID_COL,self.PD_WAS_BALANCED_COL,self.OB_WAS_CROSSED,self.FVG_WAS_BALANCED]]}")
102
118
  last_pd = df.iloc[-1]
103
119
  return {
104
120
  self.TIMESTAMP_COL: last_pd[self.TIMESTAMP_COL],
@@ -106,4 +122,5 @@ class SMCPDArray(SMCFVG,SMCOrderBlock):
106
122
  self.PD_HIGH_COL: last_pd[self.PD_HIGH_COL],
107
123
  self.PD_LOW_COL: last_pd[self.PD_LOW_COL],
108
124
  self.PD_MID_COL: last_pd[self.PD_MID_COL],
125
+ self.PD_WAS_BALANCED_COL: last_pd[self.PD_WAS_BALANCED_COL],
109
126
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openfund-core
3
- Version: 1.0.8
3
+ Version: 1.0.10
4
4
  Summary: Openfund-core.
5
5
  Requires-Python: >=3.9,<4.0
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,15 +1,15 @@
1
- core/Exchange.py,sha256=MDhV71jmWyM1IGaUI-iSfZqrUG9RNOpSWqm0jNV_GXU,23173
1
+ core/Exchange.py,sha256=ifZiziRKJP9-9WBCuHa2HLu4mmGIB-V6J8WirZgkCOQ,21502
2
2
  core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  core/main.py,sha256=E-VZzem7-0_J6EmOo9blLPokc5MRcgjqCbqAvbkPnWI,630
4
4
  core/smc/SMCBase.py,sha256=epRC5bWDymx7ZMIhn_bVJRjvBHItt6BCnYASO2fhSDg,4302
5
5
  core/smc/SMCFVG.py,sha256=KDyqR8dQiKYpJ25HpXeVPdxVgAxbtwc9LJ-OVrGIlZk,3009
6
- core/smc/SMCLiquidity.py,sha256=bK5iOz0TQVd5y-xNNUmTh8pny3bWr0OVVPFunAppv1Q,7976
6
+ core/smc/SMCLiquidity.py,sha256=-OvMZQCcy7qRSomU58sUmhRJt-gUGt1oPJAiW01_i7I,8009
7
7
  core/smc/SMCOrderBlock.py,sha256=lh868FUjb6RHQ0DwUeBfYymf9j-Lcv6YWJvYlJF3iUo,9918
8
- core/smc/SMCPDArray.py,sha256=jIBo2anp9_5C9_CFSe-pbwprm14Qs__zVbsfNAu2_bE,4127
8
+ core/smc/SMCPDArray.py,sha256=IjBdpQuAQd3t_nTovEzeiml-EQ-KeLNCmitFxadYxMM,5030
9
9
  core/smc/SMCStruct.py,sha256=dW3iLKNV78pDbcpyL7SjLVUyAsc1DrO8gSCJkGbrKO4,12339
10
10
  core/smc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  core/utils/OPTools.py,sha256=tJ1Jq_Caab6OWaX12xn4_g9ryf98Rm5I1zsJEEU8NIQ,1002
12
- openfund_core-1.0.8.dist-info/METADATA,sha256=is_DnPGzyBUwQUi7ysyqCnMmu9ecRpA6uP3jB5yXN0I,1953
13
- openfund_core-1.0.8.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
14
- openfund_core-1.0.8.dist-info/entry_points.txt,sha256=g8GUw3cyKFtcG5VWs8geU5VBLqiWr59GElqERuH8zD0,48
15
- openfund_core-1.0.8.dist-info/RECORD,,
12
+ openfund_core-1.0.10.dist-info/METADATA,sha256=zCl4CuqeksPfr7usyT0LvLaI8ZMVs4Zlib0Q1oyokYw,1954
13
+ openfund_core-1.0.10.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
14
+ openfund_core-1.0.10.dist-info/entry_points.txt,sha256=g8GUw3cyKFtcG5VWs8geU5VBLqiWr59GElqERuH8zD0,48
15
+ openfund_core-1.0.10.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.2
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any