openfund-taker 2.0.5__tar.gz → 2.0.6__tar.gz

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,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openfund-taker
3
- Version: 2.0.5
3
+ Version: 2.0.6
4
4
  Summary: Openfund-taker
5
5
  Requires-Python: >=3.9,<4.0
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openfund-taker"
3
- version = "2.0.5"
3
+ version = "2.0.6"
4
4
  description = "Openfund-taker"
5
5
  authors = []
6
6
  readme = "README.md"
@@ -9,6 +9,7 @@ class SMCSLAndTPTaker(TrailingSLTaker):
9
9
  self.global_symbol_take_profit_flag = {} # 记录每个symbol是否设置全局止盈标志
10
10
  self.global_symbol_take_profit_price = {} # 记录每个symbol的止盈价格
11
11
  self.htf_liquidities = {}
12
+ self.all_TP_SL_ratio = float(platform_config.get("all_TP_SL_ratio",1.5)) #The profit-loss ratio 盈亏比
12
13
 
13
14
  @override
14
15
  def check_reverse_position(self,symbol,position,pair_config):
@@ -200,17 +201,7 @@ class SMCSLAndTPTaker(TrailingSLTaker):
200
201
  prev_lows = data['low'].iloc[max(0,index - period):index]
201
202
  next_lows = data['low'].iloc[index :min(len(data),index + period + 1)]
202
203
  return all(current_low <= prev_lows) and all(current_low <= next_lows)
203
- @override
204
- def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None,take_profit_price=None) -> bool:
205
- if not stop_loss_price :
206
- self.logger.warning(f"{symbol}: No stop loss price or take profit price provided for {symbol}")
207
- return False
208
- if not position:
209
- self.logger.warning(f"{symbol}: No position found for {symbol}")
210
- return False
211
204
 
212
- return self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=stop_loss_price)
213
-
214
205
 
215
206
  def set_sl_by_profit(self, symbol, position, profit, pair_config, kLines=None):
216
207
 
@@ -269,6 +260,8 @@ class SMCSLAndTPTaker(TrailingSLTaker):
269
260
  if sl_price == latest_sl_price:
270
261
  self.logger.debug(f"{symbol}: 回撤止损价格{latest_sl_price}未变化,不设置")
271
262
  return
263
+
264
+ self.cancel_all_algo_orders(symbol=symbol, attachType='SL')
272
265
 
273
266
  # 移动止损保护
274
267
  if_success = self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=sl_price)
@@ -278,7 +271,7 @@ class SMCSLAndTPTaker(TrailingSLTaker):
278
271
 
279
272
  self.global_symbol_stop_loss_price[symbol] = sl_price
280
273
  self.global_symbol_stop_loss_flag[symbol] = True
281
-
274
+ cur_highest_total_profit = self.highest_total_profit.get(symbol, 0.0)
282
275
 
283
276
  # 发送通知
284
277
  msg = (f"{symbol}: 盈利达到【{current_tier}】阈值,最高总盈利: {cur_highest_total_profit:.2f}%,"
@@ -345,35 +338,39 @@ class SMCSLAndTPTaker(TrailingSLTaker):
345
338
 
346
339
  return df_valid_liquidities.loc[result_indices].sort_index(ascending=False)
347
340
 
348
- def calculate_tp_price_by_liquidity(self, symbol, position, df_liquidities, offset=1) -> float:
341
+ def calculate_tp_price_by_liquidity(self, symbol, position, df_liquidities, tp_sl_ratio=1.5, offset=1) -> float:
349
342
  """_summary_
350
343
  计算止盈价格,根据流动性,做多则止盈价格在流动性之上,做空则止盈价格在流动性之下。
351
344
  Args:
352
345
  symbol (_type_): _description_
353
346
  position (_type_): _description_
354
347
  df_liquidities (_type_): _description_
348
+ strategy (_type_): _description_
349
+ offset (int, optional): _description_. Defaults to 1.
355
350
 
356
351
  Returns:
357
352
  float: _description_
358
- """
353
+ """
354
+
359
355
  tp_price = 0.0
360
- market_price = float(position['markPrice'])
356
+ # market_price = float(position['markPrice'])
361
357
 
362
358
  is_buy = position['side'] == 'long'
363
359
  price_col = 'Up' if is_buy else 'Dn'
364
360
 
365
- sl_price = self.global_symbol_stop_loss_price.get(symbol, 0.0)
361
+ sl_price = self.global_symbol_stop_loss_price.get(symbol, float(position['markPrice']))
366
362
  entry_price = float(position['entryPrice'])
367
- threshold = market_price
363
+
368
364
  if is_buy and sl_price > 0 :
369
- threshold = (entry_price - sl_price ) * 1.5 + entry_price
365
+ threshold = (entry_price - sl_price ) * tp_sl_ratio + entry_price
370
366
  elif not is_buy and sl_price > 0:
371
- threshold = entry_price - (sl_price - entry_price ) * 1.5
367
+ threshold = entry_price - (sl_price - entry_price ) * tp_sl_ratio
368
+
372
369
 
373
370
  # 过滤有效的流动性价格
374
371
  valid_mask = df_liquidities[price_col] > threshold if is_buy else df_liquidities[price_col] < threshold
375
372
  df_valid_liquidities = df_liquidities[valid_mask]
376
-
373
+ self.logger.debug(f"{symbol} : threshold={threshold} sl_price={sl_price} 有效的流动=\n {df_valid_liquidities[['timestamp','Up','Dn']]}")
377
374
  # 获取止盈价格
378
375
  tp_price = df_valid_liquidities.iloc[0][price_col] if len(df_valid_liquidities) > 0 else 0.0
379
376
  tick_size = self.get_tick_size(symbol)
@@ -394,6 +391,7 @@ class SMCSLAndTPTaker(TrailingSLTaker):
394
391
  self.global_symbol_take_profit_flag.clear()
395
392
  self.global_symbol_take_profit_price.clear()
396
393
 
394
+
397
395
  @override
398
396
  def reset_all_cache(self, symbol):
399
397
  super().reset_all_cache(symbol)
@@ -429,8 +427,10 @@ class SMCSLAndTPTaker(TrailingSLTaker):
429
427
  if len(htf_liquidity) <= 0:
430
428
  self.logger.info(f"{symbol} : 没有找到流动性,不设置止盈")
431
429
  return
430
+
431
+ tp_price = self.calculate_tp_price_by_liquidity(symbol, position, htf_liquidity, self.all_TP_SL_ratio)
432
432
 
433
- tp_price = self.calculate_tp_price_by_liquidity(symbol, position, htf_liquidity)
433
+ self.cancel_all_algo_orders(symbol=symbol, attachType='TP')
434
434
 
435
435
  if self.set_take_profit(symbol, position, tp_price):
436
436
  self.global_symbol_take_profit_flag[symbol] = True
@@ -0,0 +1,57 @@
1
+
2
+ from typing import override
3
+ from taker.TrailingSLTaker import TrailingSLTaker
4
+ '''
5
+ 自动设置移动止损单
6
+ '''
7
+ class TrailingSLAndTPTaker(TrailingSLTaker):
8
+ def __init__(self,g_config, platform_config, feishu_webhook=None, monitor_interval=4,logger=None):
9
+ super().__init__(g_config, platform_config, feishu_webhook, monitor_interval,logger)
10
+ self.global_symbol_take_profit_flag = {} # 记录每个symbol是否设置全局止盈标志
11
+ self.global_symbol_take_profit_price = {} # 记录每个symbol的止盈价格
12
+ self.all_TP_SL_ratio = float(platform_config.get("all_TP_SL_ratio",1.5)) #The profit-loss ratio 盈亏比
13
+ self.all_take_profit_pct = self.stop_loss_pct * self.all_TP_SL_ratio
14
+
15
+ def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None, take_profit_price=None) -> bool:
16
+ if not stop_loss_price and not take_profit_price:
17
+ self.logger.warning(f"{symbol}: No stop loss price or take profit price provided for {symbol}")
18
+ return False
19
+ if not position:
20
+ self.logger.warning(f"{symbol}: No position found for {symbol}")
21
+ return False
22
+
23
+ # 取消所有策略订单
24
+ if_success = self.cancel_all_algo_orders(symbol=symbol)
25
+
26
+ if if_success:
27
+ self.global_symbol_stop_loss_price[symbol] = None
28
+ self.global_symbol_stop_loss_flag[symbol] = False
29
+ return
30
+
31
+ if_stop_loss_success ,if_take_profit_success = True , True
32
+
33
+ if stop_loss_price :
34
+ if_stop_loss_success = self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=stop_loss_price)
35
+ if take_profit_price :
36
+ if_take_profit_success = self.set_take_profit(symbol=symbol, position=position, take_profit_price=take_profit_price)
37
+
38
+ is_successful = if_stop_loss_success and if_take_profit_success
39
+
40
+ order_take_profit_price = take_profit_price
41
+ if take_profit_price is None:
42
+ order_take_profit_price = self.calculate_take_profile_price(symbol, position, self.all_take_profit_pct)
43
+ is_successful = self.set_take_profit(symbol, position, order_take_profit_price)
44
+
45
+ return is_successful
46
+
47
+ @override
48
+ def close_all_cache(self):
49
+ super().close_all_cache()
50
+ self.global_symbol_take_profit_flag.clear()
51
+ self.global_symbol_take_profit_price.clear()
52
+ @override
53
+ def reset_all_cache(self, symbol):
54
+ self.reset_highest_profit_and_tier(symbol)
55
+ self.reset_take_profie(symbol)
56
+ self.global_symbol_take_profit_flag[symbol] = False
57
+ self.global_symbol_take_profit_price[symbol] = None
@@ -40,6 +40,7 @@ class TrailingSLTaker:
40
40
 
41
41
  self.global_symbol_stop_loss_flag = {} # 记录每个symbol是否设置全局止损
42
42
  self.global_symbol_stop_loss_price = {} # 记录每个symbol的止损价格
43
+
43
44
  # 保留在止盈挂单中最高最低两个价格,计算止盈价格。
44
45
  self.max_market_price = {}
45
46
  self.min_market_price = {}
@@ -403,7 +404,7 @@ class TrailingSLTaker:
403
404
  self.highest_total_profit[symbol] = 0.0
404
405
 
405
406
  # self.logger.debug("已重置最高总盈利")
406
- # FIXME 目前只支持 单symbol
407
+
407
408
  def reset_take_profie(self,symbol=None):
408
409
  if not symbol:
409
410
  self.global_symbol_stop_loss_price.clear()
@@ -431,50 +432,66 @@ class TrailingSLTaker:
431
432
  return f"{adjusted_price:.{tick_decimals}f}"
432
433
  # 放弃当前委托
433
434
 
434
- def cancel_all_algo_orders(self,symbol):
435
+ def cancel_all_algo_orders(self, symbol, attachType=None) -> bool:
436
+ """_summary_
437
+
438
+ Args:
439
+ symbol (_type_): _description_
440
+ attachType (_type_, optional): "TP"|"SL". Defaults to None.
441
+ """
435
442
 
436
443
  params = {
437
444
  "ordType": "conditional",
438
445
  }
439
446
  orders = self.fetch_open_orders(symbol=symbol,params=params)
440
447
  # 如果没有委托订单则直接返回
441
- if not orders:
448
+ if len(orders) == 0:
442
449
  self.global_symbol_stop_loss_flag[symbol] = False
443
450
  self.logger.debug(f"{symbol} 未设置策略订单列表。")
444
451
  return
445
452
 
446
- algo_ids = [order['info']['algoId'] for order in orders if 'info' in order and 'algoId' in order['info']]
453
+ # algo_ids = [order['info']['algoId'] for order in orders if 'info' in order and 'algoId' in order['info']]
454
+ algo_ids = []
455
+ if attachType and attachType == 'SL':
456
+ algo_ids = [order['id'] for order in orders if order['stopLossPrice'] and order['stopLossPrice'] > 0.0 ]
457
+ elif attachType and attachType == 'TP':
458
+ algo_ids = [order['id'] for order in orders if order['takeProfitPrice'] and order['takeProfitPrice'] > 0.0]
459
+ else :
460
+ algo_ids = [order['id'] for order in orders ]
461
+
462
+ if len(algo_ids) == 0 :
463
+ self.logger.debug(f"{symbol} 未设置策略订单列表。")
464
+ return
465
+
447
466
  try:
448
467
  params = {
449
468
  "algoId": algo_ids,
450
469
  "trigger": 'trigger'
451
470
  }
452
471
  rs = self.exchange.cancel_orders(ids=algo_ids, symbol=symbol, params=params)
453
- self.global_symbol_stop_loss_flag[symbol] = False
472
+
473
+ return len(rs) > 0
474
+ # self.global_symbol_stop_loss_flag[symbol] = False
454
475
  # self.logger.debug(f"Order {algo_ids} cancelled:{rs}")
455
476
  except Exception as e:
456
477
  self.logger.error(f"{symbol} Error cancelling order {algo_ids}: {e}")
457
478
 
458
479
  def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None,take_profit_price=None) -> bool:
459
- if not stop_loss_price and not take_profit_price:
480
+ if not stop_loss_price :
460
481
  self.logger.warning(f"{symbol}: No stop loss price or take profit price provided for {symbol}")
461
482
  return False
462
483
  if not position:
463
484
  self.logger.warning(f"{symbol}: No position found for {symbol}")
464
485
  return False
465
486
 
466
- # 取消所有策略订单
467
- self.cancel_all_algo_orders(symbol=symbol)
468
-
469
- if_stop_loss_success = True
470
- if_take_profit_success = True
471
-
472
- if stop_loss_price :
473
- if_stop_loss_success = self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=stop_loss_price)
474
- if take_profit_price :
475
- if_take_profit_success = self.set_take_profit(symbol=symbol, position=position, take_profit_price=take_profit_price)
476
-
477
- return if_stop_loss_success and if_take_profit_success
487
+
488
+ if self.cancel_all_algo_orders(symbol=symbol, attachType='SL'):
489
+ self.global_symbol_stop_loss_flag[symbol] = False
490
+ return
491
+
492
+ return self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=stop_loss_price)
493
+
494
+
478
495
 
479
496
  def set_take_profit(self, symbol, position, take_profit_price=None) -> bool:
480
497
 
@@ -485,8 +502,6 @@ class TrailingSLTaker:
485
502
  self.logger.warning(f"{symbol}: amount is 0 for {symbol}")
486
503
  return
487
504
 
488
- # 取消所有策略订单
489
- # self.cancel_all_algo_orders(symbol=symbol)
490
505
 
491
506
  # 止损单逻辑
492
507
  adjusted_price = self.round_price_to_tick(symbol, take_profit_price)
@@ -561,8 +576,15 @@ class TrailingSLTaker:
561
576
 
562
577
 
563
578
 
564
- def set_stop_loss(self, symbol, position, stop_loss_price=None , ord_type='market') -> bool:
565
-
579
+ def set_stop_loss(self, symbol, position, stop_loss_price=None , ord_type='conditional') -> bool:
580
+ """
581
+ 设置止盈单
582
+ :param symbol: 交易对
583
+ :param position: 持仓信息
584
+ :param stop_loss_price: 止损价格
585
+ :param ord_type: 订单类型 ord_type: 'conditional'|'market'|'limit'
586
+ :return: 是否成功设置止盈单
587
+ """
566
588
  # 计算下单数量
567
589
  amount = abs(float(position['contracts']))
568
590
 
@@ -588,10 +610,7 @@ class TrailingSLTaker:
588
610
  if ord_type == 'limit':
589
611
  sl_params['slOrdPx'] = adjusted_price
590
612
 
591
- side = 'short'
592
- if position['side'] == side: # 和持仓反向相反下单
593
- side ='long'
594
-
613
+ side = 'long' if position['side'] == 'short' else 'short' # 和持仓反向相反下单
595
614
  orderSide = 'buy' if side == 'long' else 'sell'
596
615
 
597
616
  max_retries = 3
@@ -605,7 +624,7 @@ class TrailingSLTaker:
605
624
  self.exchange.create_order(
606
625
  symbol=symbol,
607
626
  # type='optimal_limit_ioc',
608
- type='conditional',
627
+ type=ord_type,
609
628
  # type='limit',
610
629
  price=adjusted_price,
611
630
  side=orderSide,
@@ -614,8 +633,7 @@ class TrailingSLTaker:
614
633
  )
615
634
  self.logger.info(f"{symbol}: SL at {adjusted_price} Done.")
616
635
 
617
- break
618
-
636
+ break
619
637
 
620
638
  except ccxt.NetworkError as e:
621
639
  # 处理网络相关错误
@@ -715,8 +733,8 @@ class TrailingSLTaker:
715
733
 
716
734
 
717
735
 
718
- last_sl_price= self.global_symbol_stop_loss_price.get(symbol,None)
719
- if last_sl_price is not None and last_sl_price == sl_order_price:
736
+ last_sl_price= self.global_symbol_stop_loss_price.get(symbol,0.0)
737
+ if last_sl_price != 0.0 and last_sl_price == sl_order_price:
720
738
  self.global_symbol_stop_loss_flag[symbol] = True
721
739
  self.logger.debug(f"{symbol} : [{side}] 全局止损价没变化, {last_sl_price} = {sl_order_price}")
722
740
  return
@@ -955,7 +973,7 @@ class TrailingSLTaker:
955
973
  return
956
974
 
957
975
  # 设置止损
958
- if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=sl_price)
976
+ if_success = self.set_stop_loss(symbol, position, stop_loss_price=sl_price)
959
977
 
960
978
  if if_success:
961
979
  # 更新回撤止损价格
@@ -1,21 +0,0 @@
1
-
2
- from taker.TrailingSLTaker import TrailingSLTaker
3
- '''
4
- 自动设置移动止损单
5
- '''
6
- class TrailingSLAndTPTaker(TrailingSLTaker):
7
- def __init__(self,g_config, platform_config, feishu_webhook=None, monitor_interval=4,logger=None):
8
- super().__init__(g_config, platform_config, feishu_webhook, monitor_interval,logger)
9
- self.all_TP_SL_ratio = float(platform_config.get("all_TP_SL_ratio",1.5)) #The profit-loss ratio 盈亏比
10
- self.all_take_profit_pct = self.stop_loss_pct * self.all_TP_SL_ratio
11
-
12
- def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None, take_profit_price=None) -> bool:
13
- is_successful = super().set_stop_loss_take_profit(symbol, position, stop_loss_price, take_profit_price)
14
-
15
- order_take_profit_price = take_profit_price
16
- if take_profit_price is None:
17
- order_take_profit_price = self.calculate_take_profile_price(symbol, position, self.all_take_profit_pct)
18
- is_successful = self.set_take_profit(symbol, position, order_take_profit_price)
19
-
20
- return is_successful
21
-
File without changes