openfund-taker 1.2.2__py3-none-any.whl → 1.2.8__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.
- {openfund_taker-1.2.2.dist-info → openfund_taker-1.2.8.dist-info}/METADATA +4 -3
- {openfund_taker-1.2.2.dist-info → openfund_taker-1.2.8.dist-info}/RECORD +6 -6
- taker/MultiAssetNewTradingBot.py +208 -74
- taker/main.py +19 -6
- {openfund_taker-1.2.2.dist-info → openfund_taker-1.2.8.dist-info}/WHEEL +0 -0
- {openfund_taker-1.2.2.dist-info → openfund_taker-1.2.8.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: openfund-taker
|
3
|
-
Version: 1.2.
|
3
|
+
Version: 1.2.8
|
4
4
|
Summary: Openfund-taker
|
5
5
|
Requires-Python: >=3.9,<4.0
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
@@ -9,9 +9,10 @@ Classifier: Programming Language :: Python :: 3.10
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
12
|
+
Requires-Dist: TA-Lib (>=0.6.3,<0.7.0)
|
12
13
|
Requires-Dist: ccxt (>=4.4.26,<5.0.0)
|
13
|
-
Requires-Dist:
|
14
|
-
Requires-Dist:
|
14
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
15
|
+
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
15
16
|
Description-Content-Type: text/markdown
|
16
17
|
|
17
18
|
# buou_trail
|
@@ -1,4 +1,4 @@
|
|
1
|
-
taker/MultiAssetNewTradingBot.py,sha256=
|
1
|
+
taker/MultiAssetNewTradingBot.py,sha256=bpgI6eewTwd7-Q5u2Au0UXd-mvFT1UM9S3H4CXPzf4g,42412
|
2
2
|
taker/MultiAssetOldTradingBot.py,sha256=uBh_BxglvcbaHIsWHM7GI9Qa_QjzsxXaXJAAWEOMO5c,15315
|
3
3
|
taker/ThreeLineTradingBot.py,sha256=oXIoQ8z9AzKzk0z13d0ufj2KGBOk5iHJTJNZQRDKA5U,20625
|
4
4
|
taker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -8,8 +8,8 @@ taker/chua_ok.py,sha256=5pPAoEYbFuKxfZwqNvOO890s-2cy6n69QiI0ZA0GTCQ,12474
|
|
8
8
|
taker/chua_ok_all.py,sha256=2XnZM6QdB3juSE1pqQIJyh2x1XuhlTlnBKNA3owlJ9E,15267
|
9
9
|
taker/chua_ok_bot.py,sha256=9SW0ujhi6PfN4yR1JZ9NaA37HtnXJ2QAWUfW52NG68w,13109
|
10
10
|
taker/config.py,sha256=YPxghO5i0vgRg9Cja8kGj9O7pgSbbtzOgf3RexqXXwY,1188
|
11
|
-
taker/main.py,sha256=
|
12
|
-
openfund_taker-1.2.
|
13
|
-
openfund_taker-1.2.
|
14
|
-
openfund_taker-1.2.
|
15
|
-
openfund_taker-1.2.
|
11
|
+
taker/main.py,sha256=dTi-Innb_DSKp-esWPc6dVQekrGnv7dNHlv49xmVDfo,2516
|
12
|
+
openfund_taker-1.2.8.dist-info/METADATA,sha256=I5TSrQi-mzrYZmAuE6qUft3sUgepFD2lI2V99XpY_Eo,7527
|
13
|
+
openfund_taker-1.2.8.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
14
|
+
openfund_taker-1.2.8.dist-info/entry_points.txt,sha256=a7mG8F7aOA5-Gk2vPWuAR4537faxaHUgM_jwIDBZoEc,50
|
15
|
+
openfund_taker-1.2.8.dist-info/RECORD,,
|
taker/MultiAssetNewTradingBot.py
CHANGED
@@ -26,7 +26,7 @@ class MultiAssetNewTradingBot:
|
|
26
26
|
self.current_tier = "无" # 记录当前的仓位模式
|
27
27
|
|
28
28
|
self.global_symbol_stop_loss_flag = {} # 记录每个symbol是否设置全局止损
|
29
|
-
self.
|
29
|
+
self.global_symbol_stop_loss_price = {} # 记录每个symbol的止损价格
|
30
30
|
# 保留在止盈挂单中最高最低两个价格,计算止盈价格。
|
31
31
|
self.max_market_price = 0.0
|
32
32
|
self.min_market_price = float('inf') # 初始化为浮点数最大值
|
@@ -353,7 +353,7 @@ class MultiAssetNewTradingBot:
|
|
353
353
|
# self.logger.debug("已重置最高总盈利和档位状态")
|
354
354
|
# FIXME 目前只支持 单symbol
|
355
355
|
def reset_take_profie(self):
|
356
|
-
self.
|
356
|
+
self.global_symbol_stop_loss_price.clear()
|
357
357
|
self.global_symbol_stop_loss_flag.clear()
|
358
358
|
# 保留在止盈挂单中最高最低两个价格,计算止盈价格。
|
359
359
|
self.max_market_price = 0.0
|
@@ -393,28 +393,127 @@ class MultiAssetNewTradingBot:
|
|
393
393
|
# self.logger.debug(f"Order {algo_ids} cancelled:{rs}")
|
394
394
|
except Exception as e:
|
395
395
|
self.logger.error(f"{symbol} Error cancelling order {algo_ids}: {e}")
|
396
|
-
|
397
|
-
def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None,
|
398
|
-
|
399
|
-
|
400
|
-
|
396
|
+
|
397
|
+
def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None,take_profit_price=None) -> bool:
|
398
|
+
if not stop_loss_price and not take_profit_price:
|
399
|
+
self.logger.warning(f"{symbol}: No stop loss price or take profit price provided for {symbol}")
|
400
|
+
return False
|
401
401
|
if not position:
|
402
402
|
self.logger.warning(f"{symbol}: No position found for {symbol}")
|
403
|
-
return
|
403
|
+
return False
|
404
|
+
|
405
|
+
if_stop_loss_success = False
|
406
|
+
if_take_profit_success = False
|
407
|
+
|
408
|
+
if stop_loss_price :
|
409
|
+
if_stop_loss_success = self.set_stop_loss(symbol=symbol, position=position, stop_loss_price=stop_loss_price)
|
410
|
+
if take_profit_price :
|
411
|
+
if_take_profit_success = self.set_take_profit(symbol=symbol, position=position, take_profit_price=take_profit_price)
|
404
412
|
|
413
|
+
return if_stop_loss_success or if_take_profit_success
|
414
|
+
|
415
|
+
def set_take_profit(self, symbol, position, take_profit_price=None) -> bool:
|
416
|
+
|
417
|
+
# 计算下单数量
|
405
418
|
amount = abs(float(position['contracts']))
|
406
|
-
|
419
|
+
|
407
420
|
if amount <= 0:
|
408
421
|
self.logger.warning(f"{symbol}: amount is 0 for {symbol}")
|
409
422
|
return
|
410
423
|
|
411
|
-
|
424
|
+
# 取消所有策略订单
|
425
|
+
# self.cancel_all_algo_orders(symbol=symbol)
|
426
|
+
|
427
|
+
# 止损单逻辑
|
428
|
+
adjusted_price = self.round_price_to_tick(symbol, take_profit_price)
|
429
|
+
|
430
|
+
tp_params = {
|
431
|
+
|
432
|
+
|
433
|
+
'tpTriggerPx':adjusted_price,
|
434
|
+
'tpOrdPx' : adjusted_price,
|
435
|
+
'tpOrdKind': 'condition',
|
436
|
+
'tpTriggerPxType':'last',
|
437
|
+
|
438
|
+
'tdMode':position['marginMode'],
|
439
|
+
'sz': str(amount),
|
440
|
+
# 'closeFraction': '1',
|
441
|
+
'cxlOnClosePos': True,
|
442
|
+
'reduceOnly':True
|
443
|
+
}
|
444
|
+
|
445
|
+
side = 'short'
|
446
|
+
if position['side'] == side: # 和持仓反向相反下单
|
447
|
+
side ='long'
|
448
|
+
|
449
|
+
orderSide = 'buy' if side == 'long' else 'sell'
|
450
|
+
|
451
|
+
max_retries = 3
|
452
|
+
retry_count = 0
|
453
|
+
|
454
|
+
while retry_count < max_retries:
|
455
|
+
try:
|
456
|
+
|
457
|
+
self.logger.debug(f"{symbol} - {orderSide}:Pre Take profit order set for {symbol} at {take_profit_price} Starting.... ")
|
458
|
+
|
459
|
+
self.exchange.create_order(
|
460
|
+
symbol=symbol,
|
461
|
+
type='optimal_limit_ioc',
|
462
|
+
|
463
|
+
price=adjusted_price,
|
464
|
+
side=orderSide,
|
465
|
+
amount=amount,
|
466
|
+
params=tp_params
|
467
|
+
)
|
468
|
+
self.logger.debug(f"{symbol} - {orderSide}: Take profit order set for {symbol} at {take_profit_price} Done.")
|
469
|
+
break
|
470
|
+
|
471
|
+
|
472
|
+
except ccxt.NetworkError as e:
|
473
|
+
# 处理网络相关错误
|
474
|
+
retry_count += 1
|
475
|
+
self.logger.warning(f"!! 设置止盈单时发生网络错误,正在进行第{retry_count}次重试: {str(e)}")
|
476
|
+
time.sleep(0.1) # 重试前等待1秒
|
477
|
+
continue
|
478
|
+
except ccxt.ExchangeError as e:
|
479
|
+
# 处理交易所API相关错误
|
480
|
+
retry_count += 1
|
481
|
+
self.logger.warning(f"!! 设置止盈单时发生交易所错误,正在进行第{retry_count}次重试: {str(e)}")
|
482
|
+
time.sleep(0.1)
|
483
|
+
continue
|
484
|
+
except Exception as e:
|
485
|
+
# 处理其他未预期的错误
|
486
|
+
retry_count += 1
|
487
|
+
self.logger.warning(f"!! 设置止盈单时发生未知错误,正在进行第{retry_count}次重试: {str(e)}")
|
488
|
+
time.sleep(0.1)
|
489
|
+
continue
|
412
490
|
|
413
|
-
|
414
|
-
|
491
|
+
if retry_count >= max_retries:
|
492
|
+
# 重试次数用完仍未成功设置止损单
|
493
|
+
self.logger.warning(f"!! {symbol} 设置止盈单时重试次数用完仍未成功设置成功。 ")
|
415
494
|
return False
|
495
|
+
return True
|
496
|
+
|
497
|
+
|
498
|
+
|
499
|
+
def set_stop_loss(self, symbol, position, stop_loss_price=None) -> bool:
|
416
500
|
|
417
|
-
|
501
|
+
|
502
|
+
# 计算下单数量
|
503
|
+
amount = abs(float(position['contracts']))
|
504
|
+
|
505
|
+
if amount <= 0:
|
506
|
+
self.logger.warning(f"{symbol}: amount is 0 for {symbol}")
|
507
|
+
return
|
508
|
+
|
509
|
+
# 取消所有策略订单
|
510
|
+
self.cancel_all_algo_orders(symbol=symbol)
|
511
|
+
|
512
|
+
|
513
|
+
# 止损单逻辑
|
514
|
+
adjusted_price = self.round_price_to_tick(symbol, stop_loss_price)
|
515
|
+
|
516
|
+
sl_params = {
|
418
517
|
'slTriggerPx':adjusted_price ,
|
419
518
|
# 'slOrdPx':'-1', # 委托价格为-1时,执行市价止损
|
420
519
|
'slOrdPx' : adjusted_price,
|
@@ -434,21 +533,26 @@ class MultiAssetNewTradingBot:
|
|
434
533
|
|
435
534
|
max_retries = 3
|
436
535
|
retry_count = 0
|
437
|
-
|
536
|
+
|
438
537
|
while retry_count < max_retries:
|
439
538
|
try:
|
539
|
+
|
440
540
|
self.logger.debug(f"{symbol} - {orderSide}:Pre Stop loss order set for {symbol} at {stop_loss_price} Starting.... ")
|
541
|
+
|
441
542
|
self.exchange.create_order(
|
442
543
|
symbol=symbol,
|
443
|
-
type='
|
544
|
+
type='optimal_limit_ioc',
|
545
|
+
# type='conditional',
|
444
546
|
# type='limit',
|
445
547
|
price=adjusted_price,
|
446
548
|
side=orderSide,
|
447
549
|
amount=amount,
|
448
|
-
params=
|
550
|
+
params=sl_params
|
449
551
|
)
|
450
552
|
self.logger.debug(f"{symbol} - {orderSide}: Stop loss order set for {symbol} at {stop_loss_price} Done.")
|
451
|
-
|
553
|
+
break
|
554
|
+
|
555
|
+
|
452
556
|
except ccxt.NetworkError as e:
|
453
557
|
# 处理网络相关错误
|
454
558
|
retry_count += 1
|
@@ -467,10 +571,14 @@ class MultiAssetNewTradingBot:
|
|
467
571
|
self.logger.warning(f"!! 设置止损单时发生未知错误,正在进行第{retry_count}次重试: {str(e)}")
|
468
572
|
time.sleep(0.1)
|
469
573
|
continue
|
574
|
+
|
575
|
+
if retry_count >= max_retries:
|
576
|
+
# 重试次数用完仍未成功设置止损单
|
577
|
+
self.logger.warning(f"!! {symbol} 设置止损单时重试次数用完仍未成功设置成功。 ")
|
578
|
+
return False
|
579
|
+
|
580
|
+
return True
|
470
581
|
|
471
|
-
# 重试次数用完仍未成功设置止损单
|
472
|
-
self.logger.warning(f"!! {symbol} 设置止损单时重试次数用完仍未成功设置成功。 ")
|
473
|
-
return False
|
474
582
|
|
475
583
|
def set_global_stop_loss(self, symbol, position, stop_loss_pct=None):
|
476
584
|
"""设置全局止损
|
@@ -493,16 +601,19 @@ class MultiAssetNewTradingBot:
|
|
493
601
|
# 根据持仓方向计算止损价格
|
494
602
|
side = position['side']
|
495
603
|
if side == 'long':
|
496
|
-
|
604
|
+
sl_price = position['entryPrice'] * (1 - stop_loss_pct/100)
|
605
|
+
tp_price = position['entryPrice'] * (1 + stop_loss_pct*2/100)
|
497
606
|
elif side == 'short':
|
498
|
-
|
607
|
+
sl_price = position['entryPrice'] * (1 + stop_loss_pct/100)
|
608
|
+
tp_price = position['entryPrice'] * (1 - stop_loss_pct*2/100)
|
499
609
|
|
500
|
-
|
610
|
+
sl_order_price = float(self.round_price_to_tick(symbol, sl_price))
|
611
|
+
tp_order_price = float(self.round_price_to_tick(symbol, tp_price))
|
501
612
|
|
502
|
-
|
503
|
-
if
|
613
|
+
last_sl_price= self.global_symbol_stop_loss_price.get(symbol,None)
|
614
|
+
if last_sl_price is not None and last_sl_price == sl_order_price:
|
504
615
|
self.global_symbol_stop_loss_flag[symbol] = True
|
505
|
-
self.logger.debug(f"{symbol} - {side} 全局止损价没变化: {
|
616
|
+
self.logger.debug(f"{symbol} - {side} 全局止损价没变化: {last_sl_price} = {sl_order_price}")
|
506
617
|
return
|
507
618
|
|
508
619
|
try:
|
@@ -510,44 +621,65 @@ class MultiAssetNewTradingBot:
|
|
510
621
|
if_success = self.set_stop_loss_take_profit(
|
511
622
|
symbol=symbol,
|
512
623
|
position=position,
|
513
|
-
stop_loss_price=
|
624
|
+
stop_loss_price=sl_order_price,
|
625
|
+
take_profit_price=tp_order_price
|
514
626
|
)
|
515
627
|
if if_success:
|
516
628
|
# 设置全局止损标志
|
517
|
-
self.logger.debug(f"{symbol} - {side} 设置全局止损价: {
|
629
|
+
self.logger.debug(f"{symbol} - {side} 设置全局止损价: {sl_order_price}")
|
518
630
|
self.global_symbol_stop_loss_flag[symbol] = True
|
519
|
-
self.
|
631
|
+
self.global_symbol_stop_loss_price[symbol] = sl_order_price
|
520
632
|
|
521
633
|
except Exception as e:
|
522
634
|
error_msg = f"{symbol} - 设置止损时发生错误: {str(e)}"
|
523
635
|
self.logger.error(error_msg)
|
524
636
|
self.send_feishu_notification(error_msg)
|
525
637
|
|
526
|
-
def
|
638
|
+
def calculate_take_profile_price(self, symbol, position, take_profile_pct, offset=1) -> float:
|
639
|
+
tick_size = float(self.exchange.market(symbol)['precision']['price'])
|
640
|
+
# market_price = position['markPrice']
|
641
|
+
entry_price = position['entryPrice']
|
642
|
+
side = position['side']
|
643
|
+
|
644
|
+
# 计算止盈价格。
|
645
|
+
|
646
|
+
if side == 'long':
|
647
|
+
|
648
|
+
base_price = entry_price * (1-take_profile_pct)
|
649
|
+
take_profile_price = entry_price + base_price - offset * tick_size
|
650
|
+
|
651
|
+
|
652
|
+
elif side == 'short':
|
653
|
+
|
654
|
+
base_price = entry_price * (1-take_profile_pct)
|
655
|
+
take_profile_price = entry_price - base_price + offset * tick_size
|
656
|
+
|
657
|
+
return take_profile_price
|
658
|
+
|
659
|
+
def calculate_stop_loss_price(self, symbol, position, stop_loss_pct, offset=1) -> float:
|
527
660
|
tick_size = float(self.exchange.market(symbol)['precision']['price'])
|
528
661
|
market_price = position['markPrice']
|
529
662
|
entry_price = position['entryPrice']
|
530
663
|
side = position['side']
|
531
664
|
# base_price = abs(market_price-entry_price) * (1-stop_loss_pct)
|
532
665
|
# 计算止盈价格,用市场价格(取持仓期间历史最高)减去开仓价格的利润,再乘以不同阶段的止盈百分比。
|
533
|
-
|
666
|
+
latest_stop_loss_price = self.exchange.safe_float(self.global_symbol_stop_loss_price,symbol,None)
|
534
667
|
if side == 'long':
|
535
668
|
self.max_market_price = max(market_price,self.max_market_price)
|
536
669
|
base_price = abs(self.max_market_price - entry_price) * (1-stop_loss_pct)
|
537
|
-
|
538
|
-
if
|
539
|
-
|
670
|
+
stop_loss_price = entry_price + base_price - offset * tick_size
|
671
|
+
if latest_stop_loss_price :
|
672
|
+
stop_loss_price = max(stop_loss_price,latest_stop_loss_price)
|
540
673
|
|
541
674
|
elif side == 'short':
|
542
675
|
self.min_market_price = min(market_price,self.min_market_price)
|
543
676
|
base_price = abs(self.min_market_price - entry_price) * (1-stop_loss_pct)
|
544
|
-
|
545
|
-
if
|
546
|
-
|
547
|
-
return
|
548
|
-
|
549
|
-
# 平仓
|
677
|
+
stop_loss_price = entry_price - base_price + offset * tick_size
|
678
|
+
if latest_stop_loss_price :
|
679
|
+
stop_loss_price = min(stop_loss_price,latest_stop_loss_price)
|
680
|
+
return stop_loss_price
|
550
681
|
|
682
|
+
# 市价仓位平仓
|
551
683
|
def close_all_positions(self,symbol,position):
|
552
684
|
|
553
685
|
amount = abs(float(position['contracts']))
|
@@ -570,6 +702,7 @@ class MultiAssetNewTradingBot:
|
|
570
702
|
|
571
703
|
'mgnMode': td_mode,
|
572
704
|
'posSide': pos_side,
|
705
|
+
# 当市价全平时,平仓单是否需要自动撤销,默认为false. false:不自动撤单 true:自动撤单
|
573
706
|
'autoCxl': 'true'
|
574
707
|
|
575
708
|
}
|
@@ -589,39 +722,39 @@ class MultiAssetNewTradingBot:
|
|
589
722
|
self.logger.error(f"{symbol} Error closing position for {symbol}: {e}")
|
590
723
|
self.send_feishu_notification(f"{symbol} Error closing position for {symbol}: {e}")
|
591
724
|
|
592
|
-
def
|
725
|
+
def check_stop_loss_trigger(self, symbol: str, position: dict) -> bool:
|
593
726
|
"""
|
594
|
-
|
727
|
+
检查是否触发止损条件
|
595
728
|
Args:
|
596
729
|
symbol: 交易对
|
597
730
|
position: 持仓信息
|
598
731
|
Returns:
|
599
732
|
bool: 是否需要平仓
|
600
733
|
"""
|
601
|
-
|
602
|
-
if
|
603
|
-
self.logger.warning(f"{symbol}
|
734
|
+
latest_stop_loss_price = self.exchange.safe_float(self.global_symbol_stop_loss_price, symbol, 0.0)
|
735
|
+
if latest_stop_loss_price == 0.0:
|
736
|
+
self.logger.warning(f"{symbol} 未设置止损价格,执行平仓")
|
604
737
|
return True
|
605
738
|
|
606
739
|
mark_price = position['markPrice']
|
607
740
|
side = position['side']
|
608
741
|
|
609
|
-
if side == 'long' and mark_price <
|
610
|
-
self.logger.warning(f"!![非正常关闭]: {symbol} 方向 {side} - 市场价格 {mark_price} 低于止盈 {
|
742
|
+
if side == 'long' and mark_price < latest_stop_loss_price:
|
743
|
+
self.logger.warning(f"!![非正常关闭]: {symbol} 方向 {side} - 市场价格 {mark_price} 低于止盈 {latest_stop_loss_price},触发全局止盈")
|
611
744
|
return True
|
612
|
-
elif side == 'short' and mark_price >
|
613
|
-
self.logger.warning(f"!![非正常关闭]: {symbol} 方向 {side} - 市场价格 {mark_price} 高于止盈价 {
|
745
|
+
elif side == 'short' and mark_price > latest_stop_loss_price:
|
746
|
+
self.logger.warning(f"!![非正常关闭]: {symbol} 方向 {side} - 市场价格 {mark_price} 高于止盈价 {latest_stop_loss_price},触发全局止盈")
|
614
747
|
return True
|
615
748
|
|
616
749
|
return False
|
617
750
|
|
618
751
|
def check_position(self, symbol, position):
|
619
752
|
# 清理趋势相反的仓位
|
620
|
-
pair_config = self.trading_pairs_config.get(symbol, {})
|
621
|
-
self.check_reverse_position(symbol=symbol, position=position, pair_config=pair_config)
|
753
|
+
# pair_config = self.trading_pairs_config.get(symbol, {})
|
754
|
+
# self.check_reverse_position(symbol=symbol, position=position, pair_config=pair_config)
|
622
755
|
|
623
|
-
#
|
624
|
-
if self.
|
756
|
+
# 检查止损是否触发止盈
|
757
|
+
if self.check_stop_loss_trigger(symbol, position):
|
625
758
|
self.close_all_positions(symbol=symbol, position=position)
|
626
759
|
return
|
627
760
|
|
@@ -662,57 +795,58 @@ class MultiAssetNewTradingBot:
|
|
662
795
|
self.logger.info(f"{symbol} 低档回撤止盈阈值: {self.low_trail_stop_loss_pct:.2f}%")
|
663
796
|
if total_profit >= self.low_trail_stop_loss_pct:
|
664
797
|
|
665
|
-
|
798
|
+
sl_price = self.calculate_stop_loss_price(symbol=symbol, position=position,stop_loss_pct=self.low_trail_stop_loss_pct )
|
799
|
+
# tp_price = self.calculate_take_profile_price(symbol=symbol, position=position,stop_loss_pct=self.low_trail_stop_loss_pct)
|
666
800
|
# 判断止盈价格是否变化,无变化不需要设置
|
667
|
-
|
668
|
-
if
|
801
|
+
latest_sl_price = self.exchange.safe_float(self.global_symbol_stop_loss_price,symbol,0.0)
|
802
|
+
if sl_price == latest_sl_price:
|
669
803
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
670
804
|
return
|
671
|
-
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=
|
805
|
+
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=sl_price )
|
672
806
|
if if_success:
|
673
|
-
self.logger.info(f"{symbol} 总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,市场价格:{position['markPrice']},设置止盈位: {
|
674
|
-
self.
|
807
|
+
self.logger.info(f"{symbol} 总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,市场价格:{position['markPrice']},设置止盈位: {sl_price:.9f}")
|
808
|
+
self.global_symbol_stop_loss_price[symbol] = sl_price
|
675
809
|
self.reset_highest_profit_and_tier()
|
676
|
-
self.send_feishu_notification(f"{symbol} 总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,市场价格:{position['markPrice']},设置止盈位: {
|
810
|
+
self.send_feishu_notification(f"{symbol} 总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,市场价格:{position['markPrice']},设置止盈位: {sl_price:.9f}")
|
677
811
|
return
|
678
812
|
elif self.current_tier == "第一档移动止盈":
|
679
813
|
trail_stop_loss = self.highest_total_profit * (1 - self.trail_stop_loss_pct)
|
680
814
|
self.logger.info(f"{symbol} 第一档回撤止盈阈值: {trail_stop_loss:.2f}%")
|
681
815
|
if total_profit >= trail_stop_loss:
|
682
|
-
|
816
|
+
sl_price = self.calculate_stop_loss_price(symbol=symbol, position=position,stop_loss_pct=self.trail_stop_loss_pct )
|
683
817
|
# 判断止盈价格是否变化,无变化不需要设置
|
684
|
-
|
685
|
-
if
|
818
|
+
latest_sl_price = self.exchange.safe_float(self.global_symbol_stop_loss_price,symbol,0.0)
|
819
|
+
if sl_price == latest_sl_price :
|
686
820
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
687
821
|
return
|
688
|
-
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=
|
822
|
+
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=sl_price)
|
689
823
|
if if_success:
|
690
824
|
self.logger.info(
|
691
|
-
f"{symbol} 总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {
|
825
|
+
f"{symbol} 总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {sl_price:.9f}")
|
692
826
|
# 记录一下止盈价格
|
693
|
-
self.
|
827
|
+
self.global_symbol_stop_loss_price[symbol] = float(sl_price)
|
694
828
|
self.reset_highest_profit_and_tier()
|
695
829
|
self.send_feishu_notification(
|
696
|
-
f"{symbol} 总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']}, 设置止盈位: {
|
830
|
+
f"{symbol} 总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']}, 设置止盈位: {sl_price:.9f}")
|
697
831
|
return
|
698
832
|
|
699
833
|
elif self.current_tier == "第二档移动止盈":
|
700
834
|
trail_stop_loss = self.highest_total_profit * (1 - self.higher_trail_stop_loss_pct)
|
701
835
|
self.logger.info(f"{symbol} 第二档回撤止盈阈值: {trail_stop_loss:.2f}%")
|
702
836
|
if total_profit >= trail_stop_loss:
|
703
|
-
|
837
|
+
sl_price = self.calculate_stop_loss_price(symbol=symbol, position=position,stop_loss_pct=self.higher_trail_stop_loss_pct)
|
704
838
|
# 判断止盈价格是否变化,无变化不需要设置
|
705
|
-
|
706
|
-
if
|
839
|
+
latest_sl_price = self.exchange.safe_float(self.global_symbol_stop_loss_price,symbol,0.0)
|
840
|
+
if sl_price == latest_sl_price:
|
707
841
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
708
842
|
return
|
709
|
-
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=
|
843
|
+
if_success = self.set_stop_loss_take_profit(symbol, position, stop_loss_price=sl_price)
|
710
844
|
if if_success:
|
711
|
-
self.logger.info(f"{symbol} 总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {
|
845
|
+
self.logger.info(f"{symbol} 总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {sl_price:.9f}")
|
712
846
|
# 记录一下止盈价格
|
713
|
-
self.
|
847
|
+
self.global_symbol_stop_loss_price[symbol] = sl_price
|
714
848
|
self.reset_highest_profit_and_tier()
|
715
|
-
self.send_feishu_notification(f"{symbol} 总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {
|
849
|
+
self.send_feishu_notification(f"{symbol} 总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,市场价格: {position['markPrice']},设置止盈位: {sl_price:.9f}")
|
716
850
|
return
|
717
851
|
else :
|
718
852
|
self.logger.info(f"{symbol} 全局止损阈值: {self.stop_loss_pct:.2f}%")
|
taker/main.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
import os
|
2
|
-
import json
|
3
1
|
import logging
|
2
|
+
import yaml
|
4
3
|
from logging.handlers import TimedRotatingFileHandler
|
5
4
|
|
6
5
|
from taker.MultiAssetNewTradingBot import MultiAssetNewTradingBot
|
@@ -24,17 +23,31 @@ def build_logger(log_config) -> logging.Logger:
|
|
24
23
|
logger.addHandler(console_handler)
|
25
24
|
|
26
25
|
return logger
|
27
|
-
|
26
|
+
|
27
|
+
def read_config_file(file_path):
|
28
|
+
try:
|
29
|
+
# 打开 YAML 文件
|
30
|
+
with open(file_path, 'r', encoding='utf-8') as file:
|
31
|
+
# 使用 yaml.safe_load 方法解析 YAML 文件内容
|
32
|
+
data = yaml.safe_load(file)
|
33
|
+
return data
|
34
|
+
except FileNotFoundError:
|
35
|
+
raise Exception(f"文件 {file_path} 未找到。")
|
36
|
+
except yaml.YAMLError as e:
|
37
|
+
raise Exception(f"解析 {file_path} 文件时出错: {e}")
|
28
38
|
|
29
39
|
|
30
40
|
def main():
|
31
41
|
import importlib.metadata
|
32
42
|
version = importlib.metadata.version("openfund-taker")
|
33
43
|
|
34
|
-
openfund_config_path = 'config.json'
|
44
|
+
# openfund_config_path = 'config.json'
|
45
|
+
openfund_config_path = 'taker_config.yaml'
|
46
|
+
config_data = read_config_file(openfund_config_path)
|
47
|
+
|
35
48
|
|
36
|
-
with open(openfund_config_path, 'r') as f:
|
37
|
-
|
49
|
+
# with open(openfund_config_path, 'r') as f:
|
50
|
+
# config_data = json.load(f)
|
38
51
|
|
39
52
|
platform_config = config_data['okx']
|
40
53
|
feishu_webhook_url = config_data['feishu_webhook']
|
File without changes
|
File without changes
|