openfund-taker 1.1.5__py3-none-any.whl → 1.2.7__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.1.5.dist-info → openfund_taker-1.2.7.dist-info}/METADATA +4 -3
- {openfund_taker-1.1.5.dist-info → openfund_taker-1.2.7.dist-info}/RECORD +6 -6
- taker/MultiAssetNewTradingBot.py +215 -74
- taker/main.py +19 -6
- {openfund_taker-1.1.5.dist-info → openfund_taker-1.2.7.dist-info}/WHEEL +0 -0
- {openfund_taker-1.1.5.dist-info → openfund_taker-1.2.7.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.
|
3
|
+
Version: 1.2.7
|
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.
|
13
|
-
openfund_taker-1.
|
14
|
-
openfund_taker-1.
|
15
|
-
openfund_taker-1.
|
11
|
+
taker/main.py,sha256=dTi-Innb_DSKp-esWPc6dVQekrGnv7dNHlv49xmVDfo,2516
|
12
|
+
openfund_taker-1.2.7.dist-info/METADATA,sha256=rlwEtnPudCYEkzK1SCkCm2AmDB94XV30TfQDkzu_UAk,7527
|
13
|
+
openfund_taker-1.2.7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
14
|
+
openfund_taker-1.2.7.dist-info/entry_points.txt,sha256=a7mG8F7aOA5-Gk2vPWuAR4537faxaHUgM_jwIDBZoEc,50
|
15
|
+
openfund_taker-1.2.7.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') # 初始化为浮点数最大值
|
@@ -231,7 +231,8 @@ class MultiAssetNewTradingBot:
|
|
231
231
|
def check_reverse_position(self,symbol,position,pair_config):
|
232
232
|
side = position['side']
|
233
233
|
try:
|
234
|
-
|
234
|
+
klines_period = str(pair_config.get('klines_period', '1m'))
|
235
|
+
klines = self.get_historical_klines(symbol=symbol,bar=klines_period)
|
235
236
|
|
236
237
|
# 计算 快线EMA & 慢线SMA
|
237
238
|
ema_length = pair_config.get('ema', 15)
|
@@ -352,7 +353,7 @@ class MultiAssetNewTradingBot:
|
|
352
353
|
# self.logger.debug("已重置最高总盈利和档位状态")
|
353
354
|
# FIXME 目前只支持 单symbol
|
354
355
|
def reset_take_profie(self):
|
355
|
-
self.
|
356
|
+
self.global_symbol_stop_loss_price.clear()
|
356
357
|
self.global_symbol_stop_loss_flag.clear()
|
357
358
|
# 保留在止盈挂单中最高最低两个价格,计算止盈价格。
|
358
359
|
self.max_market_price = 0.0
|
@@ -392,32 +393,131 @@ class MultiAssetNewTradingBot:
|
|
392
393
|
# self.logger.debug(f"Order {algo_ids} cancelled:{rs}")
|
393
394
|
except Exception as e:
|
394
395
|
self.logger.error(f"{symbol} Error cancelling order {algo_ids}: {e}")
|
395
|
-
|
396
|
-
def set_stop_loss_take_profit(self, symbol, position, stop_loss_price=None,
|
397
|
-
|
398
|
-
|
399
|
-
|
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
|
400
401
|
if not position:
|
401
402
|
self.logger.warning(f"{symbol}: No position found for {symbol}")
|
402
|
-
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)
|
403
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
|
+
# 计算下单数量
|
404
418
|
amount = abs(float(position['contracts']))
|
405
|
-
|
419
|
+
|
406
420
|
if amount <= 0:
|
407
421
|
self.logger.warning(f"{symbol}: amount is 0 for {symbol}")
|
408
422
|
return
|
409
423
|
|
410
|
-
|
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
|
+
|
411
432
|
|
412
|
-
|
413
|
-
|
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
|
490
|
+
|
491
|
+
if retry_count >= max_retries:
|
492
|
+
# 重试次数用完仍未成功设置止损单
|
493
|
+
self.logger.warning(f"!! {symbol} 设置止盈单时重试次数用完仍未成功设置成功。 ")
|
414
494
|
return False
|
495
|
+
return True
|
496
|
+
|
497
|
+
|
498
|
+
|
499
|
+
def set_stop_loss(self, symbol, position, stop_loss_price=None) -> bool:
|
415
500
|
|
416
|
-
|
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 = {
|
417
517
|
'slTriggerPx':adjusted_price ,
|
418
518
|
# 'slOrdPx':'-1', # 委托价格为-1时,执行市价止损
|
419
519
|
'slOrdPx' : adjusted_price,
|
420
|
-
'slTriggerPxType':'
|
520
|
+
'slTriggerPxType':'last',
|
421
521
|
'tdMode':position['marginMode'],
|
422
522
|
'sz': str(amount),
|
423
523
|
# 'closeFraction': '1',
|
@@ -433,21 +533,26 @@ class MultiAssetNewTradingBot:
|
|
433
533
|
|
434
534
|
max_retries = 3
|
435
535
|
retry_count = 0
|
436
|
-
|
536
|
+
|
437
537
|
while retry_count < max_retries:
|
438
538
|
try:
|
539
|
+
|
439
540
|
self.logger.debug(f"{symbol} - {orderSide}:Pre Stop loss order set for {symbol} at {stop_loss_price} Starting.... ")
|
541
|
+
|
440
542
|
self.exchange.create_order(
|
441
543
|
symbol=symbol,
|
442
|
-
type='
|
544
|
+
type='optimal_limit_ioc',
|
545
|
+
# type='conditional',
|
443
546
|
# type='limit',
|
444
547
|
price=adjusted_price,
|
445
548
|
side=orderSide,
|
446
549
|
amount=amount,
|
447
|
-
params=
|
550
|
+
params=sl_params
|
448
551
|
)
|
449
552
|
self.logger.debug(f"{symbol} - {orderSide}: Stop loss order set for {symbol} at {stop_loss_price} Done.")
|
450
|
-
|
553
|
+
break
|
554
|
+
|
555
|
+
|
451
556
|
except ccxt.NetworkError as e:
|
452
557
|
# 处理网络相关错误
|
453
558
|
retry_count += 1
|
@@ -466,10 +571,14 @@ class MultiAssetNewTradingBot:
|
|
466
571
|
self.logger.warning(f"!! 设置止损单时发生未知错误,正在进行第{retry_count}次重试: {str(e)}")
|
467
572
|
time.sleep(0.1)
|
468
573
|
continue
|
574
|
+
|
575
|
+
if retry_count >= max_retries:
|
576
|
+
# 重试次数用完仍未成功设置止损单
|
577
|
+
self.logger.warning(f"!! {symbol} 设置止损单时重试次数用完仍未成功设置成功。 ")
|
578
|
+
return False
|
579
|
+
|
580
|
+
return True
|
469
581
|
|
470
|
-
# 重试次数用完仍未成功设置止损单
|
471
|
-
self.logger.warning(f"!! {symbol} 设置止损单时重试次数用完仍未成功设置成功。 ")
|
472
|
-
return False
|
473
582
|
|
474
583
|
def set_global_stop_loss(self, symbol, position, stop_loss_pct=None):
|
475
584
|
"""设置全局止损
|
@@ -482,7 +591,7 @@ class MultiAssetNewTradingBot:
|
|
482
591
|
"""
|
483
592
|
# 如果已经触发过全局止损并且有止损单,则跳过
|
484
593
|
if self.global_symbol_stop_loss_flag.get(symbol, False):
|
485
|
-
|
594
|
+
|
486
595
|
return
|
487
596
|
else :
|
488
597
|
self.logger.debug(f"{symbol} - 是否设置过全局止损 {self.global_symbol_stop_loss_flag.get(symbol, False)} ")
|
@@ -492,55 +601,85 @@ class MultiAssetNewTradingBot:
|
|
492
601
|
# 根据持仓方向计算止损价格
|
493
602
|
side = position['side']
|
494
603
|
if side == 'long':
|
495
|
-
|
604
|
+
sl_price = position['entryPrice'] * (1 - stop_loss_pct/100)
|
605
|
+
tp_price = position['entryPrice'] * (1 + stop_loss_pct*2/100)
|
496
606
|
elif side == 'short':
|
497
|
-
|
607
|
+
sl_price = position['entryPrice'] * (1 + stop_loss_pct/100)
|
608
|
+
tp_price = position['entryPrice'] * (1 - stop_loss_pct*2/100)
|
498
609
|
|
499
|
-
|
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))
|
612
|
+
|
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:
|
615
|
+
self.global_symbol_stop_loss_flag[symbol] = True
|
616
|
+
self.logger.debug(f"{symbol} - {side} 全局止损价没变化: {last_sl_price} = {sl_order_price}")
|
617
|
+
return
|
500
618
|
|
501
619
|
try:
|
502
620
|
# 设置止损单
|
503
621
|
if_success = self.set_stop_loss_take_profit(
|
504
622
|
symbol=symbol,
|
505
623
|
position=position,
|
506
|
-
stop_loss_price=
|
624
|
+
stop_loss_price=sl_order_price,
|
625
|
+
take_profit_price=tp_order_price
|
507
626
|
)
|
508
627
|
if if_success:
|
509
628
|
# 设置全局止损标志
|
510
|
-
self.logger.debug(f"{symbol} - {side} 设置全局止损价: {
|
629
|
+
self.logger.debug(f"{symbol} - {side} 设置全局止损价: {sl_order_price}")
|
511
630
|
self.global_symbol_stop_loss_flag[symbol] = True
|
512
|
-
self.
|
631
|
+
self.global_symbol_stop_loss_price[symbol] = sl_order_price
|
513
632
|
|
514
633
|
except Exception as e:
|
515
634
|
error_msg = f"{symbol} - 设置止损时发生错误: {str(e)}"
|
516
635
|
self.logger.error(error_msg)
|
517
636
|
self.send_feishu_notification(error_msg)
|
518
637
|
|
519
|
-
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:
|
520
660
|
tick_size = float(self.exchange.market(symbol)['precision']['price'])
|
521
661
|
market_price = position['markPrice']
|
522
662
|
entry_price = position['entryPrice']
|
523
663
|
side = position['side']
|
524
664
|
# base_price = abs(market_price-entry_price) * (1-stop_loss_pct)
|
525
665
|
# 计算止盈价格,用市场价格(取持仓期间历史最高)减去开仓价格的利润,再乘以不同阶段的止盈百分比。
|
526
|
-
|
666
|
+
latest_stop_loss_price = self.exchange.safe_float(self.global_symbol_stop_loss_price,symbol,None)
|
527
667
|
if side == 'long':
|
528
668
|
self.max_market_price = max(market_price,self.max_market_price)
|
529
669
|
base_price = abs(self.max_market_price - entry_price) * (1-stop_loss_pct)
|
530
|
-
|
531
|
-
if
|
532
|
-
|
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)
|
533
673
|
|
534
674
|
elif side == 'short':
|
535
675
|
self.min_market_price = min(market_price,self.min_market_price)
|
536
676
|
base_price = abs(self.min_market_price - entry_price) * (1-stop_loss_pct)
|
537
|
-
|
538
|
-
if
|
539
|
-
|
540
|
-
return
|
541
|
-
|
542
|
-
# 平仓
|
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
|
543
681
|
|
682
|
+
# 市价仓位平仓
|
544
683
|
def close_all_positions(self,symbol,position):
|
545
684
|
|
546
685
|
amount = abs(float(position['contracts']))
|
@@ -563,6 +702,7 @@ class MultiAssetNewTradingBot:
|
|
563
702
|
|
564
703
|
'mgnMode': td_mode,
|
565
704
|
'posSide': pos_side,
|
705
|
+
# 当市价全平时,平仓单是否需要自动撤销,默认为false. false:不自动撤单 true:自动撤单
|
566
706
|
'autoCxl': 'true'
|
567
707
|
|
568
708
|
}
|
@@ -582,39 +722,39 @@ class MultiAssetNewTradingBot:
|
|
582
722
|
self.logger.error(f"{symbol} Error closing position for {symbol}: {e}")
|
583
723
|
self.send_feishu_notification(f"{symbol} Error closing position for {symbol}: {e}")
|
584
724
|
|
585
|
-
def
|
725
|
+
def check_stop_loss_trigger(self, symbol: str, position: dict) -> bool:
|
586
726
|
"""
|
587
|
-
|
727
|
+
检查是否触发止损条件
|
588
728
|
Args:
|
589
729
|
symbol: 交易对
|
590
730
|
position: 持仓信息
|
591
731
|
Returns:
|
592
732
|
bool: 是否需要平仓
|
593
733
|
"""
|
594
|
-
|
595
|
-
if
|
596
|
-
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} 未设置止损价格,执行平仓")
|
597
737
|
return True
|
598
738
|
|
599
739
|
mark_price = position['markPrice']
|
600
740
|
side = position['side']
|
601
741
|
|
602
|
-
if side == 'long' and mark_price <
|
603
|
-
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},触发全局止盈")
|
604
744
|
return True
|
605
|
-
elif side == 'short' and mark_price >
|
606
|
-
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},触发全局止盈")
|
607
747
|
return True
|
608
748
|
|
609
749
|
return False
|
610
750
|
|
611
751
|
def check_position(self, symbol, position):
|
612
752
|
# 清理趋势相反的仓位
|
613
|
-
pair_config = self.trading_pairs_config.get(symbol, {})
|
614
|
-
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)
|
615
755
|
|
616
|
-
#
|
617
|
-
if self.
|
756
|
+
# 检查止损是否触发止盈
|
757
|
+
if self.check_stop_loss_trigger(symbol, position):
|
618
758
|
self.close_all_positions(symbol=symbol, position=position)
|
619
759
|
return
|
620
760
|
|
@@ -655,57 +795,58 @@ class MultiAssetNewTradingBot:
|
|
655
795
|
self.logger.info(f"{symbol} 低档回撤止盈阈值: {self.low_trail_stop_loss_pct:.2f}%")
|
656
796
|
if total_profit >= self.low_trail_stop_loss_pct:
|
657
797
|
|
658
|
-
|
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)
|
659
800
|
# 判断止盈价格是否变化,无变化不需要设置
|
660
|
-
|
661
|
-
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:
|
662
803
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
663
804
|
return
|
664
|
-
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 )
|
665
806
|
if if_success:
|
666
|
-
self.logger.info(f"{symbol} 总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,市场价格:{position['markPrice']},设置止盈位: {
|
667
|
-
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
|
668
809
|
self.reset_highest_profit_and_tier()
|
669
|
-
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}")
|
670
811
|
return
|
671
812
|
elif self.current_tier == "第一档移动止盈":
|
672
813
|
trail_stop_loss = self.highest_total_profit * (1 - self.trail_stop_loss_pct)
|
673
814
|
self.logger.info(f"{symbol} 第一档回撤止盈阈值: {trail_stop_loss:.2f}%")
|
674
815
|
if total_profit >= trail_stop_loss:
|
675
|
-
|
816
|
+
sl_price = self.calculate_stop_loss_price(symbol=symbol, position=position,stop_loss_pct=self.trail_stop_loss_pct )
|
676
817
|
# 判断止盈价格是否变化,无变化不需要设置
|
677
|
-
|
678
|
-
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 :
|
679
820
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
680
821
|
return
|
681
|
-
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)
|
682
823
|
if if_success:
|
683
824
|
self.logger.info(
|
684
|
-
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}")
|
685
826
|
# 记录一下止盈价格
|
686
|
-
self.
|
827
|
+
self.global_symbol_stop_loss_price[symbol] = float(sl_price)
|
687
828
|
self.reset_highest_profit_and_tier()
|
688
829
|
self.send_feishu_notification(
|
689
|
-
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}")
|
690
831
|
return
|
691
832
|
|
692
833
|
elif self.current_tier == "第二档移动止盈":
|
693
834
|
trail_stop_loss = self.highest_total_profit * (1 - self.higher_trail_stop_loss_pct)
|
694
835
|
self.logger.info(f"{symbol} 第二档回撤止盈阈值: {trail_stop_loss:.2f}%")
|
695
836
|
if total_profit >= trail_stop_loss:
|
696
|
-
|
837
|
+
sl_price = self.calculate_stop_loss_price(symbol=symbol, position=position,stop_loss_pct=self.higher_trail_stop_loss_pct)
|
697
838
|
# 判断止盈价格是否变化,无变化不需要设置
|
698
|
-
|
699
|
-
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:
|
700
841
|
self.logger.debug(f"{symbol} 止盈价格未变化,不设置")
|
701
842
|
return
|
702
|
-
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)
|
703
844
|
if if_success:
|
704
|
-
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}")
|
705
846
|
# 记录一下止盈价格
|
706
|
-
self.
|
847
|
+
self.global_symbol_stop_loss_price[symbol] = sl_price
|
707
848
|
self.reset_highest_profit_and_tier()
|
708
|
-
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}")
|
709
850
|
return
|
710
851
|
else :
|
711
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
|