openfund-maker 1.0.17__py3-none-any.whl → 1.1.0__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.
@@ -49,18 +49,6 @@ class ThreeLineOrdergBot:
49
49
  def get_precision_length(self,symbol) -> int:
50
50
  tick_size = self.get_tick_size(symbol)
51
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
64
52
 
65
53
  def get_position_mode(self):
66
54
  try:
@@ -78,7 +66,6 @@ class ThreeLineOrdergBot:
78
66
  except Exception as e:
79
67
  self.logger.error(f"无法检测持仓模式: {e}")
80
68
  return None
81
-
82
69
 
83
70
  def fetch_and_store_all_instruments(self,instType='SWAP'):
84
71
  try:
@@ -123,7 +110,6 @@ class ThreeLineOrdergBot:
123
110
  else:
124
111
  raise ValueError("Unexpected response structure or missing 'c' value")
125
112
 
126
-
127
113
  def get_mark_price(self,symbol):
128
114
  # response = market_api.get_ticker(instId)
129
115
  ticker = self.exchange.fetch_ticker(symbol)
@@ -202,118 +188,47 @@ class ThreeLineOrdergBot:
202
188
  amplitudes.append(amplitude)
203
189
  average_amplitude = sum(amplitudes) / len(amplitudes)
204
190
  return average_amplitude
205
-
206
- def cancel_all_orders(self,symbol):
207
- try:
208
- # 获取所有未完成订单
209
- params = {
210
- # 'instId': instId
211
- }
212
- open_orders = self.exchange.fetch_open_orders(symbol=symbol,params=params)
213
-
214
- # 取消每个订单
215
- for order in open_orders:
216
- self.exchange.cancel_order(order['id'], symbol,params=params)
217
-
218
- self.logger.info(f"{symbol} 挂单取消成功.")
219
- except Exception as e:
220
- self.logger.error(f"{symbol} 取消订单失败: {str(e)}")
221
191
 
222
- def set_leverage(self,symbol, leverage, mgnMode='isolated',posSide=None):
223
- try:
224
- # 设置杠杆
225
- params = {
226
- # 'instId': instId,
227
- 'leverage': leverage,
228
- 'marginMode': mgnMode
229
- }
230
- if posSide:
231
- params['side'] = posSide
232
-
233
- self.exchange.set_leverage(leverage, symbol=symbol, params=params)
234
- self.logger.debug(f"{symbol} Successfully set leverage to {leverage}x")
235
- except Exception as e:
236
- self.logger.error(f"{symbol} Error setting leverage: {e}")
237
- #
238
- def check_position(self,symbol) -> bool:
192
+ def calculate_range_diff(self,prices:pd.Series) -> float:
239
193
  """
240
- 检查指定交易对是否有持仓
241
-
194
+ 计算价格列表中最后一个价格与第一个价格的差值。
242
195
  Args:
243
- symbol: 交易对ID
244
-
196
+ prices: 价格列表。
245
197
  Returns:
246
- bool: 是否有持仓
198
+ diff: 计算最高价列的最大值与最小值的差值
199
+
247
200
  """
248
- try:
249
- position = self.exchange.fetch_position(symbol=symbol)
250
- if position and position['contracts']> 0:
251
- self.logger.debug(f"{symbol} 有持仓合约数: {position['contracts']}")
252
- return True
253
- return False
254
- except Exception as e:
255
- self.logger.error(f"{symbol} 检查持仓失败: {str(e)}")
256
- return False
257
-
258
-
259
- def place_order(self,symbol, price, amount_usdt, side):
260
-
261
-
262
- markets = self.exchange.load_markets()
263
- if symbol not in markets:
264
- self.logger.error(f"{symbol}: Instrument {symbol} not found in markets")
265
- return
266
- market = markets[symbol]
267
- # 获取价格精度
268
- price_precision = market['precision']['price']
269
- adjusted_price = self.round_price_to_tick(price, price_precision)
270
-
271
- if amount_usdt > 0:
272
- if side == 'buy':
273
- pos_side = 'long'
274
- else:
275
- pos_side = 'short'
276
- # 设置杠杆
277
- self.set_leverage(symbol=symbol, leverage=self.leverage_value, mgnMode='isolated',posSide=pos_side)
278
- params = {
279
-
280
- "tdMode": 'isolated',
281
- "side": side,
282
- "ordType": 'limit',
283
- # "sz": amount_usdt,
284
- "px": str(adjusted_price)
285
- }
286
-
287
- # 模拟盘(demo_trading)需要 posSide
288
- if self.is_demo_trading == 1 :
289
- params["posSide"] = pos_side
290
-
291
- # self.logger.debug(f"---- Order placed params: {params}")
292
- try:
293
- order = {
294
- 'symbol': symbol,
295
- 'side': side,
296
- 'type': 'limit',
297
- 'amount': amount_usdt,
298
- 'price': float(adjusted_price),
299
- 'params': params
300
- }
301
- # 使用ccxt创建订单
302
- self.logger.debug(f"Pre Order placed: {order} ")
303
- order_result = self.exchange.create_order(
304
- **order
305
- # symbol=symbol,
306
- # type='limit',
307
- # side=side,
308
- # amount=amount_usdt,
309
- # price=float(adjusted_price),
310
- # params=params
311
- )
312
- # self.logger.debug(f"{symbol} ++ Order placed rs : {order_result}")
313
- except Exception as e:
314
- self.logger.error(f"{symbol} Failed to place order: {e}")
315
- self.logger.info(f"--------- ++ {symbol} Order placed done! --------")
201
+ if prices.empty:
202
+ return None
203
+ # 将价格列表转换为pandas Series格式
204
+
205
+ diff = prices.max() - prices.min()
316
206
 
207
+ return diff
208
+
209
+ def calculate_place_order_price(self, symbol,side,base_price, amplitude_limit, offset=1) -> float:
210
+ """
211
+ 计算开仓价格
212
+ Args:
213
+ symbol: 交易对
214
+ side: 开仓方向
215
+ base_price: 开盘价格
216
+ amplitude_limit: 振幅限制
217
+ offset: 偏移量
218
+ Returns:
219
+ place_order_price: 开仓价格
220
+ """
221
+ tick_size = self.get_tick_size(symbol)
222
+ place_order_price = None
223
+ # 计算止盈价格,用市场价格(取持仓期间历史最高)减去开仓价格的利润,再乘以不同阶段的止盈百分比。
224
+
225
+ if side == 'buy':
226
+ place_order_price = base_price * (1- amplitude_limit/100) - offset * tick_size
227
+ else:
228
+ place_order_price = base_price * (1 + amplitude_limit/100) + offset * tick_size
229
+ self.logger.debug(f"++++ {symbol} 下单价格: {place_order_price:.9f} 方向 {side} 基准价格{base_price} 振幅限制 {amplitude_limit} ")
230
+ return float(self.round_price_to_tick(place_order_price,tick_size))
231
+
317
232
  # 定义根据均线斜率判断 K 线方向的函数: 0 空 1 多 -1 平
318
233
  def judge_k_line_direction(self, symbol, pair_config, ema: pd.Series, klines) -> int:
319
234
  """
@@ -369,7 +284,8 @@ class ThreeLineOrdergBot:
369
284
  elif all(ema_4_diff >= 0) and any(ema_4_diff > 0) :
370
285
  # 上升趋势
371
286
  direction = 1
372
- else:
287
+ # 都是 (0 0 0) 或 (+ 0 -) 这两种情况认为都是震荡
288
+ else:
373
289
  # 震荡趋势
374
290
  direction = -1
375
291
  self.logger.debug(f"{symbol}: EMA极差={ema_4_diff.map('{:.4f}'.format).values} ,EMA方向={direction}")
@@ -433,9 +349,8 @@ class ThreeLineOrdergBot:
433
349
  is_expanding_or_contracting = all(df['slope'].tail(period) <= 0 ) and any(df['slope'].tail(period) < 0)
434
350
 
435
351
  return is_expanding_or_contracting
436
-
437
-
438
- def calculate_range_diff(self,prices:pd.Series) -> float:
352
+
353
+ def judge_range_diff(self,symbol,pair_config,prices:pd.Series) -> bool:
439
354
  """
440
355
  计算价格列表中最后一个价格与第一个价格的差值。
441
356
  Args:
@@ -444,37 +359,126 @@ class ThreeLineOrdergBot:
444
359
  diff: 计算最高价列的最大值与最小值的差值
445
360
 
446
361
  """
362
+ limit = int(pair_config.get('ema_range_limit', 1))
363
+ period = int(pair_config.get('ema_range_period', 3))
364
+ tick_size = self.get_tick_size(symbol)
447
365
  if prices.empty:
448
- return None
449
- # 将价格列表转换为pandas Series格式
366
+ return None
450
367
 
451
- diff = prices.max() - prices.min()
452
-
453
- return diff
454
-
455
- def calculate_place_order_price(self, symbol,side,base_price, amplitude_limit, offset=1) -> float:
368
+ diff = prices.tail(period).max() - prices.tail(period).min()
369
+ self.logger.debug(f"{symbol}: 最高价列的最大值与最小值的差值 = {diff:.9f}")
370
+ return abs(diff) <= tick_size * limit
371
+
372
+ def set_leverage(self,symbol, leverage, mgnMode='isolated',posSide=None):
373
+ try:
374
+ # 设置杠杆
375
+ params = {
376
+ # 'instId': instId,
377
+ 'leverage': leverage,
378
+ 'marginMode': mgnMode
379
+ }
380
+ if posSide:
381
+ params['side'] = posSide
382
+
383
+ self.exchange.set_leverage(leverage, symbol=symbol, params=params)
384
+ self.logger.debug(f"{symbol} Successfully set leverage to {leverage}x")
385
+ except Exception as e:
386
+ self.logger.error(f"{symbol} Error setting leverage: {e}")
387
+ #
388
+ def check_position(self,symbol) -> bool:
456
389
  """
457
- 计算开仓价格
390
+ 检查指定交易对是否有持仓
391
+
458
392
  Args:
459
- symbol: 交易对
460
- side: 开仓方向
461
- base_price: 开盘价格
462
- amplitude_limit: 振幅限制
463
- offset: 偏移量
393
+ symbol: 交易对ID
394
+
464
395
  Returns:
465
- place_order_price: 开仓价格
396
+ bool: 是否有持仓
466
397
  """
467
- tick_size = float(self.exchange.market(symbol)['precision']['price'])
468
- place_order_price = None
469
- # 计算止盈价格,用市场价格(取持仓期间历史最高)减去开仓价格的利润,再乘以不同阶段的止盈百分比。
470
-
471
- if side == 'buy':
472
- place_order_price = base_price * (1- amplitude_limit/100) - offset * tick_size
473
- else:
474
- place_order_price = base_price * (1 + amplitude_limit/100) + offset * tick_size
475
- self.logger.debug(f"++++ {symbol} 下单价格: {place_order_price:.9f} 方向 {side} 基准价格{base_price} 振幅限制 {amplitude_limit} ")
476
- return float(self.round_price_to_tick(place_order_price,tick_size))
477
-
398
+ try:
399
+ position = self.exchange.fetch_position(symbol=symbol)
400
+ if position and position['contracts']> 0:
401
+ self.logger.debug(f"{symbol} 有持仓合约数: {position['contracts']}")
402
+ return True
403
+ return False
404
+ except Exception as e:
405
+ self.logger.error(f"{symbol} 检查持仓失败: {str(e)}")
406
+ return False
407
+
408
+ def place_order(self,symbol, price, amount_usdt, side):
409
+
410
+
411
+ markets = self.exchange.load_markets()
412
+ if symbol not in markets:
413
+ self.logger.error(f"{symbol}: Instrument {symbol} not found in markets")
414
+ return
415
+ market = markets[symbol]
416
+ # 获取价格精度
417
+ price_precision = market['precision']['price']
418
+ adjusted_price = self.round_price_to_tick(price, price_precision)
419
+
420
+ if amount_usdt > 0:
421
+ if side == 'buy':
422
+ pos_side = 'long'
423
+ else:
424
+ pos_side = 'short'
425
+ # 设置杠杆
426
+ self.set_leverage(symbol=symbol, leverage=self.leverage_value, mgnMode='isolated',posSide=pos_side)
427
+ params = {
428
+
429
+ "tdMode": 'isolated',
430
+ "side": side,
431
+ "ordType": 'limit',
432
+ # "sz": amount_usdt,
433
+ "px": str(adjusted_price)
434
+ }
435
+
436
+ # 模拟盘(demo_trading)需要 posSide
437
+ if self.is_demo_trading == 1 :
438
+ params["posSide"] = pos_side
439
+
440
+ # self.logger.debug(f"---- Order placed params: {params}")
441
+ try:
442
+ order = {
443
+ 'symbol': symbol,
444
+ 'side': side,
445
+ 'type': 'limit',
446
+ 'amount': amount_usdt,
447
+ 'price': float(adjusted_price),
448
+ 'params': params
449
+ }
450
+ # 使用ccxt创建订单
451
+ self.logger.debug(f"Pre Order placed: {order} ")
452
+ order_result = self.exchange.create_order(
453
+ **order
454
+ # symbol=symbol,
455
+ # type='limit',
456
+ # side=side,
457
+ # amount=amount_usdt,
458
+ # price=float(adjusted_price),
459
+ # params=params
460
+ )
461
+ # self.logger.debug(f"{symbol} ++ Order placed rs : {order_result}")
462
+ except Exception as e:
463
+ self.logger.error(f"{symbol} Failed to place order: {e}")
464
+ self.logger.info(f"--------- ++ {symbol} Order placed done! --------")
465
+
466
+ def cancel_all_orders(self,symbol):
467
+ try:
468
+ # 获取所有未完成订单
469
+ params = {
470
+ # 'instId': instId
471
+ }
472
+ open_orders = self.exchange.fetch_open_orders(symbol=symbol,params=params)
473
+
474
+ # 取消每个订单
475
+ for order in open_orders:
476
+ self.exchange.cancel_order(order['id'], symbol,params=params)
477
+
478
+ self.logger.info(f"{symbol} 挂单取消成功.")
479
+ except Exception as e:
480
+ self.logger.error(f"{symbol} 取消订单失败: {str(e)}")
481
+
478
482
  def process_pair(self,symbol,pair_config):
479
483
  # 检查是否有持仓,有持仓不进行下单
480
484
  if self.check_position(symbol=symbol) :
@@ -518,19 +522,28 @@ class ThreeLineOrdergBot:
518
522
  # 结合金叉死叉判断是否是周期顶部和底部
519
523
  is_apex = self.judge_ma_apex(symbol=symbol,pair_config=pair_config, fastklines=fastk,slowklines=slowk)
520
524
  ema_direction = self.judge_ema_direction(symbol=symbol, pair_config=pair_config,ema=fastk)
525
+ if_inner_range = self.judge_range_diff(symbol=symbol, pair_config=pair_config, prices=fastk)
521
526
  # 金叉死叉逻辑
522
527
  if last_cross_direction and last_cross_direction['cross'] == 1 : # 金叉
523
528
  self.logger.debug(f"{symbol} 金叉:{last_cross_direction},清理空单,挂多单!!")
524
529
  is_bearish_trend = False
525
- if is_apex or ema_direction == -1:
526
- self.logger.debug(f"{symbol} 金叉:{last_cross_direction},周期见顶={is_apex} ,ema_平={ema_direction},不开单!!")
530
+ # 强校验下单条件
531
+ if is_apex or ema_direction == -1 or if_inner_range:
532
+ self.logger.debug(f"{symbol} 强校验 - 死叉:{last_cross_direction},两线收缩={is_apex} ,ema_平={ema_direction},均线振幅={if_inner_range} ,不开单!!")
533
+ # 弱校验下单条件
534
+ # if is_apex or ema_direction == -1:
535
+ # self.logger.debug(f"{symbol} 金叉:{last_cross_direction},两线收缩={is_apex} ,ema_平={ema_direction},不开单!!")
527
536
  is_bullish_trend = False
528
537
 
529
538
  elif last_cross_direction and last_cross_direction['cross'] == 0 : # 死叉
530
539
  self.logger.debug(f"{symbol} 死叉:{last_cross_direction},清理多单,挂空单!!")
531
540
  is_bullish_trend = False
532
- if is_apex or ema_direction == -1:
533
- self.logger.debug(f"{symbol} 死叉:{last_cross_direction},周期见顶={is_apex} ,ema_平={ema_direction},不开单!!")
541
+ # 强校验下单条件
542
+ if is_apex or ema_direction == -1 or if_inner_range :
543
+ self.logger.debug(f"{symbol} 强校验 - 死叉:{last_cross_direction},两线收缩={is_apex} ,ema_平={ema_direction},均线振幅={if_inner_range} ,不开单!!")
544
+ # 弱校验下单条件
545
+ # if is_apex or ema_direction == -1:
546
+ # self.logger.debug(f"{symbol} 死叉:{last_cross_direction},两线收缩={is_apex} ,ema_平={ema_direction},不开单!!")
534
547
  is_bearish_trend = False
535
548
 
536
549
  else:
@@ -558,9 +571,7 @@ class ThreeLineOrdergBot:
558
571
 
559
572
  amplitude_limit = pair_config.get('amplitude_limit', 0.32)
560
573
 
561
- self.logger.debug(f"{symbol} 当前K线的前三根K线 最高价: {max_high}, 最低价: {min_low}")
562
-
563
-
574
+ self.logger.debug(f"{symbol} 当前K线的前三根K线 最高价: {max_high}, 最低价: {min_low}")
564
575
 
565
576
  long_amount_usdt = pair_config.get('long_amount_usdt', 5)
566
577
  short_amount_usdt = pair_config.get('short_amount_usdt', 5)
@@ -573,6 +584,7 @@ class ThreeLineOrdergBot:
573
584
  close_price = klines[-1][4]
574
585
  self.logger.debug(f"-- {symbol} 最新K线 {klines[-1]}")
575
586
 
587
+ # FIXME calculate_range_diff 去掉
576
588
  if is_bullish_trend:
577
589
  diff = self.calculate_range_diff(prices=low_prices)
578
590
  cur_amplitude_limit = diff / close_price * 100
@@ -602,8 +614,6 @@ class ThreeLineOrdergBot:
602
614
  self.logger.error(error_message,exc_info=True)
603
615
  traceback.print_exc()
604
616
  self.send_feishu_notification(error_message)
605
-
606
-
607
617
 
608
618
  def monitor_klines(self):
609
619
  symbols = list(self.trading_pairs_config.keys()) # 获取所有币对的ID
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openfund-maker
3
- Version: 1.0.17
3
+ Version: 1.1.0
4
4
  Summary: Openfund-maker.
5
5
  Requires-Python: >=3.9,<4.0
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,4 +1,4 @@
1
- maker/ThreeLineOrderBot.py,sha256=c9RTJAGFYaSBOpA4OKxTm-LxFPyiof-EkKUOvjfyfaw,26378
1
+ maker/ThreeLineOrderBot.py,sha256=UBWtLMJtL6mAS4CLYThja5Z_XE7UCD4bBhik0T0Xp0s,27521
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
@@ -7,7 +7,7 @@ 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.17.dist-info/METADATA,sha256=tYHu6KxF0Da_dVhzZMWvTcdCnq6baxN4jrF6H_Q78G0,1966
11
- openfund_maker-1.0.17.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
12
- openfund_maker-1.0.17.dist-info/entry_points.txt,sha256=gKMytICEKcMRFQDFkHZLnIpID7UQFoTIM_xcpiiV6Ns,50
13
- openfund_maker-1.0.17.dist-info/RECORD,,
10
+ openfund_maker-1.1.0.dist-info/METADATA,sha256=y6UyUbgh-IJwrJiklJxR4mBCK-SQg56J2EpDI8cIIVc,1965
11
+ openfund_maker-1.1.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
12
+ openfund_maker-1.1.0.dist-info/entry_points.txt,sha256=gKMytICEKcMRFQDFkHZLnIpID7UQFoTIM_xcpiiV6Ns,50
13
+ openfund_maker-1.1.0.dist-info/RECORD,,