This commit is contained in:
dsyoon
2025-09-07 19:21:48 +09:00
parent 1fa1de3b0a
commit 49aee49a82

View File

@@ -227,18 +227,26 @@ class Monitor(HTS):
# ------------- Strategy ------------- # ------------- Strategy -------------
def buy_sell_ticker_1h(self, symbol: str, data: pd.DataFrame, balances=None, is_inverse: bool = False) -> bool: def buy_sell_ticker_1h(self, symbol: str, data: pd.DataFrame, balances=None, is_inverse: bool = False) -> bool:
try: try:
# BUY_MINUTE_LIMIT 이내라면 매수하지 않음
current_time = datetime.now()
last_buy_dt = self.buy_cooldown.get(symbol, {}).get('buy', {}).get('datetime')
if last_buy_dt:
time_diff = current_time - last_buy_dt
if time_diff.total_seconds() < BUY_MINUTE_LIMIT:
print(f"{symbol}: 매수 금지 중 (남은 시간: {BUY_MINUTE_LIMIT - time_diff.total_seconds():.0f}초)")
return False
# 신호 생성 및 최신 포인트 확인 # 신호 생성 및 최신 포인트 확인
data = self.annotate_signals(symbol, data) data = self.annotate_signals(symbol, data)
if data['point'].iloc[-1] != 1: if data['point'].iloc[-1] != 1:
return False return False
# 인버스 데이터: 매수 신호를 매도로 처리 (fall_6p, deviation40 만 허용)
if is_inverse: if is_inverse:
# 인버스 데이터: 매수 신호를 매도로 처리 (fall_6p, deviation40 만 허용)
# 허용된 인버스 매도 신호만 처리 # 허용된 인버스 매도 신호만 처리
last_signal = str(data['signal'].iloc[-1]) if 'signal' in data.columns else '' last_signal = str(data['signal'].iloc[-1]) if 'signal' in data.columns else ''
if last_signal not in ['fall_6p', 'deviation40']: if last_signal not in ['fall_6p', 'deviation40']:
return False return False
current_time = datetime.now()
available_balance = 0 available_balance = 0
try: try:
if balances and symbol in balances: if balances and symbol in balances:
@@ -260,91 +268,70 @@ class Monitor(HTS):
self.sendMsg("[KRW-COIN]\n" + f"• 매도 [COIN] {KR_COINS[symbol]} ({symbol}): {data['signal'].iloc[-1]} ({''}{data['Close'].iloc[-1]:.4f})") self.sendMsg("[KRW-COIN]\n" + f"• 매도 [COIN] {KR_COINS[symbol]} ({symbol}): {data['signal'].iloc[-1]} ({''}{data['Close'].iloc[-1]:.4f})")
return True return True
check_5_week_lowest = False
# 5주봉이 20주봉이나 40주봉보다 아래에 있는지 체크
try:
# Convert hourly data to week-based rolling periods (5, 20, 40 weeks)
hours_in_week = 24 * 7 # 168 hours
period_5w = 5 * hours_in_week # 840 hours
period_20w = 20 * hours_in_week # 3,360 hours
period_40w = 40 * hours_in_week # 6,720 hours
if len(data) >= period_40w:
wma5 = data['Close'].rolling(window=period_5w).mean().iloc[-1]
wma20 = data['Close'].rolling(window=period_20w).mean().iloc[-1]
wma40 = data['Close'].rolling(window=period_40w).mean().iloc[-1]
# 5-week MA is the lowest among 5, 20, 40 week MAs
if (wma5 < wma20) and (wma5 < wma40):
check_5_week_lowest = True
except Exception:
# Ignore errors in MA calculation so as not to block trading logic
pass
buy_amount = 5100
current_time = datetime.now()
if data['signal'].iloc[-1] == 'fall_6p':
if data['Close'].iloc[-1] > 100:
buy_amount = 600000
else:
buy_amount = 300000
last_buy_dt = self.buy_cooldown.get(symbol, {}).get('buy', {}).get('datetime')
if last_buy_dt and self.last_signal.get(symbol) == 'fall_6p':
time_diff = current_time - last_buy_dt
if time_diff.total_seconds() < 4000:
print(f"{symbol}: 매수 금지 중 (남은 시간: {600 - time_diff.total_seconds():.0f}초)")
return False
else: else:
last_buy_dt = self.buy_cooldown.get(symbol, {}).get('buy', {}).get('datetime') check_5_week_lowest = False
if last_buy_dt:
time_diff = current_time - last_buy_dt
if time_diff.total_seconds() < BUY_MINUTE_LIMIT:
print(f"{symbol}: 매수 금지 중 (남은 시간: {BUY_MINUTE_LIMIT - time_diff.total_seconds():.0f}초)")
return False
if data['signal'].iloc[-1] == 'movingaverage': try:
buy_amount = 10000 # 5주봉이 20주봉이나 40주봉보다 아래에 있는지 체크
elif data['signal'].iloc[-1] == 'deviation40': # Convert hourly data to week-based rolling periods (5, 20, 40 weeks)
buy_amount = 50000 hours_in_week = 24 * 7 # 168 hours
elif data['signal'].iloc[-1] == 'deviation240': period_5w = 5 * hours_in_week # 840 hours
buy_amount = 60000 period_20w = 20 * hours_in_week # 3,360 hours
elif data['signal'].iloc[-1] == 'deviation1440': period_40w = 40 * hours_in_week # 6,720 hours
if symbol in ['BONK', 'PEPE', 'TON']:
buy_amount = 100000 if len(data) >= period_40w:
wma5 = data['Close'].rolling(window=period_5w).mean().iloc[-1]
wma20 = data['Close'].rolling(window=period_20w).mean().iloc[-1]
wma40 = data['Close'].rolling(window=period_40w).mean().iloc[-1]
# 5-week MA is the lowest among 5, 20, 40 week MAs
if (wma5 < wma20) and (wma5 < wma40):
check_5_week_lowest = True
except Exception:
# Ignore errors in MA calculation so as not to block trading logic
pass
# 체크: fall_6p
buy_amount = 5100
current_time = datetime.now()
if data['signal'].iloc[-1] == 'fall_6p':
if data['Close'].iloc[-1] > 100:
buy_amount = 300000
else: else:
buy_amount = 150000 buy_amount = 150000
elif data['signal'].iloc[-1] == 'movingaverage':
buy_amount = 10000
elif data['signal'].iloc[-1] == 'deviation40':
buy_amount = 30000
elif data['signal'].iloc[-1] == 'deviation240':
buy_amount = 7000
elif data['signal'].iloc[-1] == 'deviation1440':
if symbol in ['BONK', 'PEPE', 'TON']:
buy_amount = 50000
else:
buy_amount = 70000
if data['signal'].iloc[-1] in ['movingaverage', 'deviation40', 'deviation240', 'deviation1440']: if data['signal'].iloc[-1] in ['movingaverage', 'deviation40', 'deviation240', 'deviation1440']:
if check_5_week_lowest: if check_5_week_lowest:
buy_amount *= 2 buy_amount *= 2
""" # 매수를 진행함
# 분봉 시스널이 없을 때는 이전 봉보다 높으면 60분 마다 매수 buy_amount = self.hts.buyCoinMarket(symbol, buy_amount)
if data['point'].iloc[-1] != 1:
last_buy_dt = self.buy_cooldown.get(symbol, {}).get('buy', {}).get('datetime')
if last_buy_dt:
time_diff = current_time - last_buy_dt
if time_diff.total_seconds() < 3600:
print(f"{symbol}: 매수 금지 중 (남은 시간: {3600 - time_diff.total_seconds():.0f}초)")
return False
"""
buy_amount = self.hts.buyCoinMarket(symbol, buy_amount)
if self.cooldown_file is not None:
# 최근 매수 신호를 함께 기록하여 [신규] 포맷으로 저장 # 최근 매수 신호를 함께 기록하여 [신규] 포맷으로 저장
try: if self.cooldown_file is not None:
self.last_signal[symbol] = str(data['signal'].iloc[-1]) try:
except Exception: self.last_signal[symbol] = str(data['signal'].iloc[-1])
self.last_signal[symbol] = '' except Exception:
self.buy_cooldown.setdefault(symbol, {})['buy'] = {'datetime': current_time, 'signal': str(data['signal'].iloc[-1])} self.last_signal[symbol] = ''
# 매수를 저장함 self.buy_cooldown.setdefault(symbol, {})['buy'] = {'datetime': current_time, 'signal': str(data['signal'].iloc[-1])}
self._save_buy_cooldown()
print(f"{KR_COINS[symbol]} ({symbol}) [{data['signal'].iloc[-1]}], 현재가: {data['Close'].iloc[-1]:.4f}, 20분간 매수 금지 시작") # 매수를 저장함
self.sendMsg("{}".format(self.format_message(symbol, KR_COINS[symbol], data['Close'].iloc[-1], data['signal'].iloc[-1], buy_amount))) self._save_buy_cooldown()
print(f"{KR_COINS[symbol]} ({symbol}) [{data['signal'].iloc[-1]}], 현재가: {data['Close'].iloc[-1]:.4f}, 20분간 매수 금지 시작")
self.sendMsg("{}".format(self.format_message(symbol, KR_COINS[symbol], data['Close'].iloc[-1], data['signal'].iloc[-1], buy_amount)))
except Exception as e: except Exception as e:
print(f"Error buying {symbol}: {str(e)}") print(f"Error buying {symbol}: {str(e)}")
return False return False