openfund-maker 1.0.11__py3-none-any.whl → 1.0.13__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.
@@ -38,7 +38,29 @@ class ThreeLineOrdergBot:
38
38
  self.logger = logger
39
39
  self.position_mode = self.get_position_mode() # 获取持仓模式
40
40
 
41
-
41
+ def getMarket(self,symbol):
42
+ self.exchange.load_markets()
43
+ return self.exchange.market(symbol)
44
+
45
+ def get_tick_size(self,symbol):
46
+ return float(self.getMarket(symbol)['precision']['price'])
47
+
48
+ # 获取价格精度
49
+ def get_precision_length(self,symbol) -> int:
50
+ tick_size = self.get_tick_size(symbol)
51
+ return len(f"{tick_size:.10f}".rstrip('0').split('.')[1]) if '.' in f"{tick_size:.10f}" else 0
52
+
53
+ # def decimal_to_precision(self,symbol,price) -> float:
54
+ # from ccxt.base.decimal_to_precision import DECIMAL_PLACES, TICK_SIZE, NO_PADDING, TRUNCATE, ROUND, ROUND_UP, ROUND_DOWN, SIGNIFICANT_DIGITS
55
+ # tick_size = self.get_tick_size(symbol)
56
+ # new_px = self.exchange.decimal_to_precision(
57
+ # n=float(price),
58
+ # precision=tick_size,
59
+ # rounding_mode=ROUND,
60
+ # counting_mode=TICK_SIZE
61
+ # )
62
+
63
+ # return new_px
42
64
 
43
65
  def get_position_mode(self):
44
66
  try:
@@ -145,32 +167,31 @@ class ThreeLineOrdergBot:
145
167
  atr = sum(trs[-period:]) / period
146
168
  return atr
147
169
 
148
- def calculate_sma_pandas(self,kLines,period):
170
+ def calculate_sma_pandas(self,symbol, kLines, period) -> pd.Series:
149
171
  """
150
172
  使用 pandas 计算 SMA
151
173
  :param KLines K线
152
174
  :param period: SMA 周期
153
175
  :return: SMA 值
154
176
  """
177
+ precision= self.get_precision_length(symbol)
155
178
  df = pd.DataFrame(kLines, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
156
- sma = df['close'].rolling(window=period).mean()
179
+ sma = df['close'].rolling(window=period).mean().round(precision)
157
180
  return sma
158
-
159
-
160
- def calculate_ema_pandas(self,kLines, period):
181
+
182
+ def calculate_ema_pandas(self,symbol, kLines, period) -> pd.Series:
161
183
  """
162
184
  使用 pandas 计算 EMA
163
185
  :param KLines K线
164
186
  :param period: EMA 周期
165
187
  :return: EMA 值
166
188
  """
167
-
189
+ precision= self.get_precision_length(symbol)
168
190
  df = pd.DataFrame(kLines, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
169
191
  # 计算EMA
170
- ema = df['close'].ewm(span=period, adjust=False).mean()
192
+ ema = df['close'].ewm(span=period, adjust=False).mean().round(precision)
171
193
  return ema
172
194
 
173
-
174
195
  def calculate_average_amplitude(self,klines, period=60):
175
196
  amplitudes = []
176
197
  for i in range(len(klines) - period, len(klines)):
@@ -247,16 +268,6 @@ class ThreeLineOrdergBot:
247
268
  price_precision = market['precision']['price']
248
269
  adjusted_price = self.round_price_to_tick(price, price_precision)
249
270
 
250
- # okx api
251
- # if instId not in self.instrument_info_dict:
252
- # tick_size = float(self.instrument_info_dict[instId]['tickSz'])
253
- # adjusted_price = self.round_price_to_tick(price, tick_size)
254
-
255
- # response = public_api.convert_contract_coin(type='1', instId=instId, sz=str(amount_usdt), px=str(adjusted_price), unit='usdt', opType='open')
256
-
257
- # 使用ccxt进行单位换算:将USDT金额转换为合约张数
258
- # contract_amount = self.exchange.amount_to_precision(symbol, amount_usdt / float(adjusted_price))
259
- # if float(contract_amount) > 0:
260
271
  if amount_usdt > 0:
261
272
  if side == 'buy':
262
273
  pos_side = 'long'
@@ -304,75 +315,102 @@ class ThreeLineOrdergBot:
304
315
  self.logger.info(f"--------- ++ {symbol} Order placed done! --------")
305
316
 
306
317
  # 定义根据均线斜率判断 K 线方向的函数: 0 空 1 多 -1 平
307
- def judge_k_line_direction(self,symbol, pair_config, ema) -> int:
308
- tick_size = float(self.exchange.market(symbol)['precision']['price'])
309
-
318
+ def judge_k_line_direction(self,symbol, pair_config, ema:pd.Series) -> int:
319
+ """
320
+ 判断K线方向
321
+ Args:
322
+ symbol: 交易对
323
+ pair_config: 配置参数
324
+ ema: EMA数据
325
+ Returns:
326
+ int: -1:平, 0:空, 1:多
327
+ """
328
+ def check_ema_range(ema_data: pd.Series, period: int, limit: float, tick_size: float) -> bool:
329
+ """检查EMA是否在指定范围内震荡"""
330
+ ema_window = ema_data[-period:]
331
+ price_range = ema_window.max() - ema_window.min()
332
+ return abs(price_range) <= limit * tick_size
333
+
334
+ def get_trend_direction(slope: float) -> int:
335
+ """根据斜率判断趋势方向"""
336
+ if slope > 0:
337
+ return 1 # 上升趋势
338
+ elif slope < 0:
339
+ return 0 # 下降趋势
340
+ return -1 # 震荡趋势
341
+
342
+ # 获取配置参数
343
+ tick_size = self.get_tick_size(symbol)
310
344
  ema_range_period = int(pair_config.get('ema_range_period', 3))
311
345
  ema_range_limit = float(pair_config.get('ema_range_limit', 1))
312
- # 20250210 判断EMA均线是否走平,用EMA周期内的极差计算,极差在阈值范围内为平
313
- ema_ranges = ema.rolling(window=ema_range_period).max() - ema.rolling(window=ema_range_period).min()
314
- ema_slope = ema.diff()
315
- latest_ema_slope = ema_slope.iloc[-1]
316
- latest_ema_range = ema_ranges.abs().iloc[-1]
317
346
 
318
- direction = -1
319
- threshold = ema_range_limit * tick_size # 极差阈值,用tick_size计算
320
- if latest_ema_range <= threshold: # 判断EMA极差范围
347
+ # 判断是否在震荡区间
348
+ if check_ema_range(ema, ema_range_period, ema_range_limit, tick_size):
321
349
  direction = -1
322
- elif latest_ema_slope > 0: # 判断斜率情况
323
- direction = 1
324
- elif latest_ema_slope < 0: # 判断斜率情况
325
- direction = 0
326
-
350
+ else:
351
+ # 计算最新斜率并判断方向
352
+ latest_slope = ema.diff().iloc[-1]
353
+ direction = get_trend_direction(latest_slope)
354
+
355
+ self.logger.debug(f"{symbol}: 极差={abs(ema[-ema_range_period:].max() - ema[-ema_range_period:].min()):.9f} "
356
+ f"斜率={ema.diff().iloc[-1]:.9f}, K线方向 {direction}")
327
357
 
328
- self.logger.debug(f"{symbol}: 极差={latest_ema_range:.9f} 斜率={latest_ema_slope:.9f}, K线方向 {direction}")
329
-
330
358
  return direction
331
359
 
332
360
  def judge_cross_direction(self,fastklines,slowklines) :
333
-
334
- # 将输入转换为 pandas 的 Series 类型
335
- fastk = pd.Series(fastklines)
336
- slowk = pd.Series(slowklines)
337
-
338
- # 判断金叉:当前 fastk 大于 slowk 且前一个 fastk 小于 slowk
339
- golden_cross = (fastk > slowk) & (fastk.shift(1) < slowk.shift(1))
340
- # 判断死叉:当前 fastk 小于 slowk 且前一个 fastk 大于 slowk
341
- death_cross = (fastk < slowk) & (fastk.shift(1) > slowk.shift(1))
342
-
343
- # 从后往前查找第一个金叉或死叉
344
- for i in range(len(fastk) - 1, -1, -1):
345
-
346
- if golden_cross[i]:
347
- return {
348
- 'cross': 1, # 金叉
349
- 'index': i
350
- }
351
- elif death_cross[i]:
352
- return {
353
- 'cross': 0, # 死叉
354
- 'index': i
355
- }
356
-
357
- return {
358
- 'cross': -1, # 无交叉
359
- 'index': None
360
- }
361
+ # 创建DataFrame
362
+ df = pd.DataFrame({
363
+ 'fast': fastklines,
364
+ 'slow': slowklines
365
+ })
366
+
367
+ # 判断金叉和死叉
368
+ df['golden_cross'] = (df['fast'] > df['slow']) & (df['fast'].shift(1) < df['slow'].shift(1))
369
+ df['death_cross'] = (df['fast'] < df['slow']) & (df['fast'].shift(1) > df['slow'].shift(1))
370
+
371
+ # 从后往前找最近的交叉点
372
+ last_golden = df['golden_cross'].iloc[::-1].idxmax() if df['golden_cross'].any() else None
373
+ last_death = df['death_cross'].iloc[::-1].idxmax() if df['death_cross'].any() else None
374
+
375
+ # 判断最近的交叉类型
376
+ if last_golden is None and last_death is None:
377
+ return {
378
+ 'cross': -1, # 无交叉
379
+ 'index': None
380
+ }
381
+
382
+ # 如果金叉更近或只有金叉
383
+ if last_golden is not None and (last_death is None or last_golden > last_death):
384
+ return {
385
+ 'cross': 1, # 金叉
386
+ 'index': last_golden
387
+ }
388
+ # 如果死叉更近或只有死叉
389
+ else:
390
+ return {
391
+ 'cross': 0, # 死叉
392
+ 'index': last_death
393
+ }
361
394
 
362
395
  def judge_ma_apex(self,symbol, fastklines,slowklines) -> bool:
363
- df = pd.DataFrame()
364
- df['ema'] = fastklines
365
- df['sma'] = slowklines
396
+
397
+ df = pd.DataFrame({
398
+ 'ema': fastklines,
399
+ 'sma': slowklines
400
+ })
366
401
  # 快线和慢线的差值
402
+ # 将ema和sma转换为tick_size精度
403
+ # df['diff'] = df['ema'].apply(lambda x: float(self.round_price_to_tick(x, tick_size))) - df['sma'].apply(lambda x: float(self.round_price_to_tick(x, tick_size)))
367
404
  df['diff'] = df['ema']-df['sma']
368
405
  # 计算斜率,【正】表示两线距离扩张,【负】表示两线距离收缩
369
- df['slope'] = df['diff'].abs().diff().round(6)
406
+ df['slope'] = df['diff'].abs().diff().round(4)
407
+ df['flag'] = df['slope'] <= 0.0
370
408
 
371
- self.logger.debug(f"{symbol}: slopes = {df['slope'].iloc[-6:-1]} ")
409
+ self.logger.debug(f"{symbol}: slopes = \n{df[['ema','sma','diff','slope','flag']].iloc[-6:-1]} ")
372
410
  # 检查最后两个斜率是否都为负
373
411
  # 取slopes最新的第2个和第3个值进行判断
374
- return all(slope < 0 for slope in df['slope'].iloc[-3:-1])
375
- return all(slope < 0 for slope in df['slope'].tail(2))
412
+
413
+ return all(slope <= 0.0 for slope in df['slope'].iloc[-3:-1])
376
414
 
377
415
 
378
416
  def calculate_range_diff(self,prices:pd.Series) -> float:
@@ -436,8 +474,8 @@ class ThreeLineOrdergBot:
436
474
  sma_length = pair_config.get('sma', 50)
437
475
 
438
476
  # 增加 金叉死叉 方向确认的 20250209
439
- fastk = self.calculate_ema_pandas(klines, period=ema_length)
440
- slowk = self.calculate_sma_pandas(klines, period=sma_length)
477
+ fastk = self.calculate_ema_pandas(symbol, klines, period=ema_length)
478
+ slowk = self.calculate_sma_pandas(symbol, klines, period=sma_length)
441
479
 
442
480
  cross_direction = self.judge_cross_direction(fastklines=fastk,slowklines=slowk)
443
481
  # 更新交叉状态
@@ -476,8 +514,8 @@ class ThreeLineOrdergBot:
476
514
  self.logger.debug(f"{symbol} 当前没有金叉死叉,以快线趋势为准。!")
477
515
 
478
516
 
479
- if not is_bullish_trend and not is_bearish_trend :
480
- self.logger.info(f"{symbol} 当前是震荡趋势(平),不挂单!!")
517
+ if (not is_bullish_trend and not is_bearish_trend) or direction == -1 :
518
+ self.logger.info(f"{symbol} 当前是震荡趋势(平),不挂单!!direction={direction}")
481
519
  return
482
520
 
483
521
  '''
maker/main.py CHANGED
@@ -28,7 +28,7 @@ def main():
28
28
  import importlib.metadata
29
29
  version = importlib.metadata.version("openfund-maker")
30
30
 
31
- wick_reversal_config_path = os.getenv('config_path','config.json')
31
+ wick_reversal_config_path = 'config.json'
32
32
  with open(wick_reversal_config_path, 'r') as f:
33
33
  config_data = json.load(f)
34
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openfund-maker
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: Openfund-maker.
5
5
  Requires-Python: >=3.9,<4.0
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,13 +1,13 @@
1
- maker/ThreeLineOrderBot.py,sha256=xNckEErdT6O-Yz80akLpHQnO8FSdxWep12o3w1j2FLw,24073
1
+ maker/ThreeLineOrderBot.py,sha256=e-KVx6a4cW2Afe0kNOKcA8isDObnzM_7wEmIlfw9tcI,25741
2
2
  maker/WickReversalOrderBot.py,sha256=Oc6wChdWu39lfWh3NRHM8BqvaRIYDNZiDR6PDnE9XUM,17374
3
3
  maker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  maker/config.py,sha256=YPxghO5i0vgRg9Cja8kGj9O7pgSbbtzOgf3RexqXXwY,1188
5
- maker/main.py,sha256=GoBlRswmnWL0Wz8MioI1yhLEPtDFsPCYJGZW4y5tlww,1899
5
+ maker/main.py,sha256=Ad1LpVfoP0JHTaKpDPku2sVqb1vvbKczwf9eIEIAU0c,1874
6
6
  maker/main_m.py,sha256=0PzDTnuBrxfpy5WDfsIHKAzZ_7pkuvuqqeWik0vpWio,15522
7
7
  maker/okxapi.py,sha256=_9G0U_o0ZC8NxaT6PqpiLgxBm9gPobC9PsFHZE1c5w0,553
8
8
  maker/zhen.py.bak,sha256=HNkrQbJts8G9umE9chEFsc0cLQApcM9KOVNMYPpkBXM,10918
9
9
  maker/zhen_2.py,sha256=4IaHVtTCMSlrLGSTZrWpW2q-f7HZsUNRkW_-5QgWv24,10509
10
- openfund_maker-1.0.11.dist-info/METADATA,sha256=bhNzNGW-n-WBwIydo9WUECHF-OZVJXBSgMbojqW5VcY,1966
11
- openfund_maker-1.0.11.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
12
- openfund_maker-1.0.11.dist-info/entry_points.txt,sha256=gKMytICEKcMRFQDFkHZLnIpID7UQFoTIM_xcpiiV6Ns,50
13
- openfund_maker-1.0.11.dist-info/RECORD,,
10
+ openfund_maker-1.0.13.dist-info/METADATA,sha256=-3hwWTGK021ZzoGPD0rzO6hLFpiP5QOGskNyJevdHuE,1966
11
+ openfund_maker-1.0.13.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
12
+ openfund_maker-1.0.13.dist-info/entry_points.txt,sha256=gKMytICEKcMRFQDFkHZLnIpID7UQFoTIM_xcpiiV6Ns,50
13
+ openfund_maker-1.0.13.dist-info/RECORD,,