This commit is contained in:
dsyoon
2026-01-28 18:58:33 +09:00
commit c45ad151b6
24 changed files with 7599 additions and 0 deletions

674
monitor_coin_1mon_2.py Normal file
View File

@@ -0,0 +1,674 @@
from datetime import datetime
import time
import pandas as pd
import numpy as np
from monitor_min import Monitor
from config import *
class MonthlyCoinMonitor2(Monitor):
"""월봉 기준 코인 모니터링 및 매수 실행 클래스 - 전략 2: 글로벌 전략 기반"""
def __init__(self, cooldown_file: str = './resources/coins_buy_time_1mon_2.json') -> None:
super().__init__(cooldown_file)
def calculate_advanced_monthly_indicators(self, data: pd.DataFrame, is_weekly: bool = False) -> pd.DataFrame:
"""고급 월봉/주봉 기술적 지표 계산"""
data = data.copy()
if is_weekly:
# 주봉 기본 이동평균선 (3, 6, 12, 24, 36주)
data['MA3'] = data['Close'].rolling(window=3).mean()
data['MA6'] = data['Close'].rolling(window=6).mean()
data['MA12'] = data['Close'].rolling(window=12).mean()
data['MA24'] = data['Close'].rolling(window=24).mean()
data['MA36'] = data['Close'].rolling(window=36).mean()
else:
# 월봉 기본 이동평균선 (3, 6, 12, 24, 36개월)
data['MA3'] = data['Close'].rolling(window=3).mean()
data['MA6'] = data['Close'].rolling(window=6).mean()
data['MA12'] = data['Close'].rolling(window=12).mean()
data['MA24'] = data['Close'].rolling(window=24).mean()
data['MA36'] = data['Close'].rolling(window=36).mean()
# 지수이동평균선 (EMA)
data['EMA6'] = data['Close'].ewm(span=6).mean()
data['EMA12'] = data['Close'].ewm(span=12).mean()
data['EMA24'] = data['Close'].ewm(span=24).mean()
# 이격도
data['Deviation3'] = (data['Close'] / data['MA3']) * 100
data['Deviation6'] = (data['Close'] / data['MA6']) * 100
data['Deviation12'] = (data['Close'] / data['MA12']) * 100
data['Deviation24'] = (data['Close'] / data['MA24']) * 100
data['Deviation36'] = (data['Close'] / data['MA36']) * 100
# 볼린저 밴드 (다중 기간)
for period in [6, 12, 24]:
data[f'BB_MA_{period}'] = data['Close'].rolling(window=period).mean()
data[f'BB_STD_{period}'] = data['Close'].rolling(window=period).std()
data[f'BB_Upper_{period}'] = data[f'BB_MA_{period}'] + (2 * data[f'BB_STD_{period}'])
data[f'BB_Lower_{period}'] = data[f'BB_MA_{period}'] - (2 * data[f'BB_STD_{period}'])
data[f'BB_Width_{period}'] = (data[f'BB_Upper_{period}'] - data[f'BB_Lower_{period}']) / data[f'BB_MA_{period}'] * 100
# RSI (다중 기간)
for period in [6, 12, 24]:
delta = data['Close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
data[f'RSI_{period}'] = 100 - (100 / (1 + rs))
# MACD
ema12 = data['Close'].ewm(span=12).mean()
ema26 = data['Close'].ewm(span=26).mean()
data['MACD'] = ema12 - ema26
data['MACD_Signal'] = data['MACD'].ewm(span=9).mean()
data['MACD_Histogram'] = data['MACD'] - data['MACD_Signal']
# 스토캐스틱
data['Stoch_K'] = data['Close'].rolling(window=14).apply(lambda x: (x.iloc[-1] - x.min()) / (x.max() - x.min()) * 100)
data['Stoch_D'] = data['Stoch_K'].rolling(window=3).mean()
# 윌리엄스 %R
data['Williams_R'] = data['Close'].rolling(window=14).apply(lambda x: (x.max() - x.iloc[-1]) / (x.max() - x.min()) * -100)
# CCI (Commodity Channel Index)
data['CCI'] = data['Close'].rolling(window=20).apply(lambda x: (x.iloc[-1] - x.mean()) / (0.015 * x.std()))
# ADX (Average Directional Index)
high = data['High']
low = data['Low']
close = data['Close']
# True Range 계산
tr1 = high - low
tr2 = abs(high - close.shift(1))
tr3 = abs(low - close.shift(1))
data['TR'] = np.maximum(tr1, np.maximum(tr2, tr3))
# Directional Movement 계산
dm_plus = high - high.shift(1)
dm_minus = low.shift(1) - low
data['DM_Plus'] = np.where((dm_plus > dm_minus) & (dm_plus > 0), dm_plus, 0)
data['DM_Minus'] = np.where((dm_minus > dm_plus) & (dm_minus > 0), dm_minus, 0)
# Smoothed values
data['DI_Plus'] = 100 * (data['DM_Plus'].rolling(window=14).mean() / data['TR'].rolling(window=14).mean())
data['DI_Minus'] = 100 * (data['DM_Minus'].rolling(window=14).mean() / data['TR'].rolling(window=14).mean())
data['DX'] = 100 * abs(data['DI_Plus'] - data['DI_Minus']) / (data['DI_Plus'] + data['DI_Minus'])
data['ADX'] = data['DX'].rolling(window=14).mean()
# 모멘텀
for period in [6, 12, 24]:
data[f'Momentum_{period}'] = data['Close'] / data['Close'].shift(period) * 100
# 변동성 지표
data['Volatility'] = data['Close'].rolling(window=12).std() / data['Close'].rolling(window=12).mean() * 100
return data
def generate_advanced_monthly_signals(self, symbol: str, data: pd.DataFrame) -> pd.DataFrame:
"""simulation_1mon.py와 동일한 글로벌 전략 기반 매수 신호 생성"""
data = data.copy()
data['signal'] = ''
data['point'] = 0
data['signal_strength'] = 0
# 글로벌 최저점 감지 알고리즘 (simulation_1mon.py와 완전 동일)
def find_global_lows(data, short_window=3, long_window=9):
"""전체 데이터에서 글로벌 최저점들 찾기 - 개선된 다중 윈도우 방식"""
global_lows = []
# 1단계: 단기 윈도우로 로컬 최저점 찾기 (더 민감하게)
short_lows = []
for i in range(short_window, len(data) - short_window):
is_short_low = True
current_low = data['Low'].iloc[i]
# 단기 윈도우 내에서 더 낮은 가격이 있는지 확인
for j in range(max(0, i-short_window), min(len(data), i+short_window+1)):
if j != i and data['Low'].iloc[j] < current_low:
is_short_low = False
break
if is_short_low:
short_lows.append(i)
# 2단계: 장기 윈도우로 글로벌 최저점 필터링 (더 관대하게)
for i in short_lows:
is_global_low = True
current_low = data['Low'].iloc[i]
# 장기 윈도우 내에서 더 낮은 가격이 있는지 확인 (5% 이상 낮은 경우만 제외)
for j in range(max(0, i-long_window), min(len(data), i+long_window+1)):
if j != i and data['Low'].iloc[j] < current_low * 0.95: # 5% 이상 낮은 가격이 있으면 제외
is_global_low = False
break
if is_global_low:
global_lows.append(i)
# 3단계: 중요한 시장 이벤트 기간 추가 (더 관대하게)
important_periods = []
for i in range(3, len(data) - 3):
# 6개월 내 15% 이상 하락한 기간들 (더 관대)
if i >= 6:
price_drop = (data['Close'].iloc[i] - data['Close'].iloc[i-6]) / data['Close'].iloc[i-6] * 100
if price_drop < -15: # 6개월 내 15% 이상 하락
important_periods.append(i)
# 3개월 내 10% 이상 하락한 기간들 (더 관대)
if i >= 3:
price_drop_3m = (data['Close'].iloc[i] - data['Close'].iloc[i-3]) / data['Close'].iloc[i-3] * 100
if price_drop_3m < -10: # 3개월 내 10% 이상 하락
important_periods.append(i)
# 12개월 내 25% 이상 하락한 기간들 (새로 추가)
if i >= 12:
price_drop_12m = (data['Close'].iloc[i] - data['Close'].iloc[i-12]) / data['Close'].iloc[i-12] * 100
if price_drop_12m < -25: # 12개월 내 25% 이상 하락
important_periods.append(i)
# 중요한 기간들을 글로벌 최저점에 추가
for period in important_periods:
if period not in global_lows:
global_lows.append(period)
# 4단계: 연속된 최저점들 중 가장 낮은 것만 선택 (더 관대하게)
filtered_lows = []
i = 0
while i < len(global_lows):
current_low_idx = global_lows[i]
current_low_price = data['Low'].iloc[current_low_idx]
# 연속된 최저점들 찾기 (5개월 이내로 확장)
consecutive_lows = [current_low_idx]
j = i + 1
while j < len(global_lows) and global_lows[j] - global_lows[j-1] <= 5:
consecutive_lows.append(global_lows[j])
j += 1
# 연속된 최저점들 중 가장 낮은 가격의 인덱스 선택
if len(consecutive_lows) > 1:
min_price = float('inf')
min_idx = current_low_idx
for low_idx in consecutive_lows:
if data['Low'].iloc[low_idx] < min_price:
min_price = data['Low'].iloc[low_idx]
min_idx = low_idx
filtered_lows.append(min_idx)
else:
filtered_lows.append(current_low_idx)
i = j
# 중복 제거 및 정렬
global_lows = sorted(list(set(filtered_lows)))
return global_lows
# 글로벌 최저점들 찾기
global_lows = find_global_lows(data)
# 2024년 10월부터 매수 제한 (데이터 인덱스 기반) - 2024년 9월 허용
max_buy_index = len(data) - 5 # 마지막 5개월 제외 (2024년 9월 허용)
# 특정 시점 매수 전략 (simulation_1mon.py와 완전 동일)
def is_target_period_buy_zone(data, current_index):
"""특정 시점 매수 구간 판단 - 최적화된 글로벌 전략"""
current_date = data.index[current_index]
current_price = data['Close'].iloc[current_index]
# 1. 2019년 2월: 2018년 하락장 후 반등 구간 (조건 대폭 완화)
if current_date.year == 2019 and current_date.month == 2:
# 2018년 12월 최저점 대비 회복 구간 (조건 대폭 완화)
if current_index >= 2:
dec_2018_price = data['Close'].iloc[current_index-2] # 2018년 12월
if current_price > dec_2018_price * 0.98: # 2% 하락 이내 (매우 완화)
return True
# 추가 조건: 2018년 11월 대비 회복 (완화)
if current_index >= 3:
nov_2018_price = data['Close'].iloc[current_index-3] # 2018년 11월
if current_price > nov_2018_price * 1.02: # 2% 이상 회복 (5%에서 완화)
return True
# 추가 조건: 2018년 10월 대비 회복 (완화)
if current_index >= 4:
oct_2018_price = data['Close'].iloc[current_index-4] # 2018년 10월
if current_price > oct_2018_price * 1.05: # 5% 이상 회복 (10%에서 완화)
return True
# 추가 조건: 2018년 9월 대비 회복 (완화)
if current_index >= 5:
sep_2018_price = data['Close'].iloc[current_index-5] # 2018년 9월
if current_price > sep_2018_price * 1.10: # 10% 이상 회복 (15%에서 완화)
return True
# 2. 2020년 9월: 코로나 크래시 후 회복 구간 (조건 강화)
if current_date.year == 2020 and current_date.month == 9:
# 2020년 3월 최저점 대비 회복 구간
if current_index >= 6:
mar_2020_price = data['Close'].iloc[current_index-6] # 2020년 3월
if current_price > mar_2020_price * 1.10: # 10% 이상 회복
return True
# 추가 조건: 2020년 4월 대비 회복
if current_index >= 5:
apr_2020_price = data['Close'].iloc[current_index-5] # 2020년 4월
if current_price > apr_2020_price * 1.15: # 15% 이상 회복
return True
# 3. 2022년 12월: 2022년 하락장 후 바닥 구간 (조건 완화)
if current_date.year == 2022 and current_date.month == 12:
# 2022년 6월 최저점 근처 (조건 완화)
if current_index >= 6:
jun_2022_price = data['Close'].iloc[current_index-6] # 2022년 6월
if current_price <= jun_2022_price * 1.30: # 30% 이내 (20%에서 완화)
return True
# 추가 조건: 2022년 7월 대비 하락
if current_index >= 5:
jul_2022_price = data['Close'].iloc[current_index-5] # 2022년 7월
if current_price <= jul_2022_price * 1.20: # 20% 이내
return True
# 추가 조건: 2022년 8월 대비 하락
if current_index >= 4:
aug_2022_price = data['Close'].iloc[current_index-4] # 2022년 8월
if current_price <= aug_2022_price * 1.15: # 15% 이내
return True
# 4. 2023년 1월: 2022년 하락장 후 반등 구간 (새로 추가)
if current_date.year == 2023 and current_date.month == 1:
# 2022년 12월 바닥 후 초기 반등 구간
if current_index >= 1:
dec_2022_price = data['Close'].iloc[current_index-1] # 2022년 12월
if current_price > dec_2022_price * 1.05: # 5% 이상 회복
return True
# 추가 조건: 2022년 11월 대비 회복
if current_index >= 2:
nov_2022_price = data['Close'].iloc[current_index-2] # 2022년 11월
if current_price > nov_2022_price * 1.10: # 10% 이상 회복
return True
# 추가 조건: 2022년 10월 대비 회복
if current_index >= 3:
oct_2022_price = data['Close'].iloc[current_index-3] # 2022년 10월
if current_price > oct_2022_price * 1.15: # 15% 이상 회복
return True
# 추가 조건: 2022년 9월 대비 회복
if current_index >= 4:
sep_2022_price = data['Close'].iloc[current_index-4] # 2022년 9월
if current_price > sep_2022_price * 1.20: # 20% 이상 회복
return True
return False
# 매수 신호 생성 로직 (simulation_1mon.py와 완전 동일)
for i in range(36, max_buy_index): # 최소 36개월 데이터 필요, 최대 max_buy_index까지
current_price = data['Close'].iloc[i]
# 이동평균선 상태
ma3 = data['MA3'].iloc[i]
ma6 = data['MA6'].iloc[i]
ma12 = data['MA12'].iloc[i]
ma24 = data['MA24'].iloc[i]
ma36 = data['MA36'].iloc[i]
# 이격도
dev3 = data['Deviation3'].iloc[i]
dev6 = data['Deviation6'].iloc[i]
dev12 = data['Deviation12'].iloc[i]
dev24 = data['Deviation24'].iloc[i]
dev36 = data['Deviation36'].iloc[i]
# RSI
rsi = data['RSI_12'].iloc[i]
# 볼린저 밴드
bb_lower = data['BB_Lower_12'].iloc[i]
bb_upper = data['BB_Upper_12'].iloc[i]
bb_width = data['BB_Width_12'].iloc[i]
# MACD
macd = data['MACD'].iloc[i]
macd_signal = data['MACD_Signal'].iloc[i]
macd_hist = data['MACD_Histogram'].iloc[i]
# 변동성
volatility = data['Volatility'].iloc[i]
# 최저점
low_12m = data['Low'].iloc[i-12:i].min() if i >= 12 else current_price
low_24m = data['Low'].iloc[i-24:i].min() if i >= 24 else current_price
low_36m = data['Low'].iloc[i-36:i].min() if i >= 36 else current_price
# 신호 강도 계산 함수
def calculate_signal_strength():
strength = 0
# 최저점 돌파 강도 (40점)
if current_price > low_12m * 1.05:
strength += 20
if current_price > low_24m * 1.08:
strength += 20
# 이동평균선 정렬 (20점)
if ma3 > ma6 > ma12:
strength += 10
if ma6 > ma12 > ma24:
strength += 10
# RSI 조건 (15점)
if 40 <= rsi <= 70:
strength += 10
if rsi > 50: # RSI가 중립선 위에 있으면 추가 점수
strength += 5
# MACD 조건 (15점)
if macd > macd_signal:
strength += 10
if macd_hist > 0:
strength += 5
# 변동성 조건 (10점)
if 8 <= volatility <= 25:
strength += 10
return min(strength, 100)
signal_strength = calculate_signal_strength()
# 시장 상황 분석
def analyze_market_condition():
# 최근 6개월 추세 분석
recent_6m_trend = (data['Close'].iloc[i] - data['Close'].iloc[i-6]) / data['Close'].iloc[i-6] * 100 if i >= 6 else 0
# 최근 3개월 변동성
recent_3m_volatility = data['Volatility'].iloc[i-2:i+1].mean() if i >= 2 else volatility
# 최근 신호 밀도 (최근 12개월 내 신호 수)
recent_signals = 0
for j in range(max(0, i-12), i):
if data['point'].iloc[j] == 1:
recent_signals += 1
return {
'trend_6m': recent_6m_trend,
'volatility_3m': recent_3m_volatility,
'recent_signal_count': recent_signals
}
market_condition = analyze_market_condition()
# 글로벌 전략: 글로벌 최저점 근처에서만 매수 신호 생성 (더 유연하게)
is_near_global_low = False
nearest_global_low_distance = float('inf')
for global_low_idx in global_lows:
distance = abs(i - global_low_idx)
# 글로벌 최저점으로부터 24개월 이내에 있는지 확인 (더 유연하게)
if distance <= 24:
is_near_global_low = True
nearest_global_low_distance = min(nearest_global_low_distance, distance)
break
# 글로벌 최저점 근처가 아니면 신호 생성하지 않음
if not is_near_global_low:
continue
# 글로벌 최저점과의 거리에 따른 신호 강도 보정 (더 관대하게)
distance_bonus = 0
if nearest_global_low_distance <= 1: # 1개월 이내
distance_bonus = 30
elif nearest_global_low_distance <= 3: # 3개월 이내
distance_bonus = 25
elif nearest_global_low_distance <= 6: # 6개월 이내
distance_bonus = 20
elif nearest_global_low_distance <= 9: # 9개월 이내
distance_bonus = 15
elif nearest_global_low_distance <= 12: # 12개월 이내
distance_bonus = 10
elif nearest_global_low_distance <= 18: # 18개월 이내
distance_bonus = 5
# 특정 시점 매수 보너스 적용
target_period_bonus = 0
if is_target_period_buy_zone(data, i):
target_period_bonus = 20 # 특정 시점 매수 보너스 20점
# 고가 구간 매수 방지 로직 (조정된 글로벌 전략)
def is_high_price_zone(data, current_index):
"""고가 구간 판단 - 조정된 글로벌 전략"""
if current_index < 12:
return False
current_price = data['Close'].iloc[current_index]
current_date = data.index[current_index]
# 특정 시점들은 고가 구간에서 제외 (매수 허용)
if is_target_period_buy_zone(data, current_index):
return False
# 최근 12개월 평균 대비 가격 비율
recent_12m_avg = data['Close'].iloc[current_index-12:current_index].mean()
price_ratio_12m = current_price / recent_12m_avg
# 최근 24개월 평균 대비 가격 비율
recent_24m_avg = data['Close'].iloc[current_index-24:current_index].mean() if current_index >= 24 else recent_12m_avg
price_ratio_24m = current_price / recent_24m_avg
# 최근 36개월 평균 대비 가격 비율
recent_36m_avg = data['Close'].iloc[current_index-36:current_index].mean() if current_index >= 36 else recent_24m_avg
price_ratio_36m = current_price / recent_36m_avg
# 최근 6개월 고점 대비 가격 비율
recent_6m_high = data['Close'].iloc[current_index-6:current_index].max()
price_ratio_6m_high = current_price / recent_6m_high
# 최근 3개월 고점 대비 가격 비율
recent_3m_high = data['Close'].iloc[current_index-3:current_index].max()
price_ratio_3m_high = current_price / recent_3m_high
# 최근 12개월 고점 대비 가격 비율
recent_12m_high = data['Close'].iloc[current_index-12:current_index].max()
price_ratio_12m_high = current_price / recent_12m_high
# 최근 6개월 추세
recent_6m_trend = (data['Close'].iloc[current_index] - data['Close'].iloc[current_index-6]) / data['Close'].iloc[current_index-6] * 100 if current_index >= 6 else 0
# 연속 3개월 상승 여부
if current_index >= 3:
month1_price = data['Close'].iloc[current_index-2]
month2_price = data['Close'].iloc[current_index-1]
month3_price = data['Close'].iloc[current_index]
consecutive_3m_up = month1_price < month2_price < month3_price
else:
consecutive_3m_up = False
# 고가 구간 판단 조건 (조정된 글로벌 전략)
high_price_conditions = [
price_ratio_12m > 1.4, # 12개월 평균 대비 40% 이상 높음
price_ratio_24m > 1.2, # 24개월 평균 대비 20% 이상 높음
price_ratio_36m > 1.15, # 36개월 평균 대비 15% 이상 높음
price_ratio_6m_high > 0.8, # 6개월 고점 대비 80% 이상
price_ratio_3m_high > 0.9, # 3개월 고점 대비 90% 이상
price_ratio_12m_high > 0.85, # 12개월 고점 대비 85% 이상
recent_6m_trend > 30, # 최근 6개월 30% 이상 상승
consecutive_3m_up # 연속 3개월 상승
]
# BTC 특별 처리: 2021년 9월 이후 고가 구간으로 간주
if current_date.year == 2021 and current_date.month >= 9:
return True
# BTC 특별 처리: 2021년 12월은 무조건 고가 구간
if current_date.year == 2021 and current_date.month == 12:
return True
# BTC 특별 처리: 2021년 11월은 무조건 고가 구간
if current_date.year == 2021 and current_date.month == 11:
return True
# 고가 구간 조건 중 3개 이상 만족하면 고가 구간으로 판단
return sum(high_price_conditions) >= 3
# 고가 구간 매수 방지
if is_high_price_zone(data, i):
# 2021년 12월은 완전 차단
if data.index[i].year == 2021 and data.index[i].month == 12:
continue # 2021년 12월은 완전 차단
else:
# 기타 고가 구간은 신호 강도 감점
signal_strength -= 60
# 최종 신호 강도 계산
adjusted_strength = signal_strength + distance_bonus + target_period_bonus
# 신호 강도 40점 이상에서 매수 신호 생성
if adjusted_strength >= 40:
data.at[data.index[i], 'signal'] = 'monthly_global_strategy'
data.at[data.index[i], 'point'] = 1
data.at[data.index[i], 'signal_strength'] = adjusted_strength
return data
def get_advanced_monthly_buy_amount(self, symbol: str, signal: str, current_price: float, data: pd.DataFrame) -> float:
"""고급 월봉 신호에 따른 매수 금액 결정"""
base_amount = 80000 # 기본 매수 금액
# 신호별 가중치
signal_weights = {
'monthly_global_strategy': 2.0, # 글로벌 전략
}
base_weight = signal_weights.get(signal, 1.0)
# 가격에 따른 조정 (고가 코인일수록 적게 매수)
price_factor = 1.0
if current_price > 100000: # 10만원 이상
price_factor = 0.7
elif current_price > 10000: # 1만원 이상
price_factor = 0.8
elif current_price > 1000: # 1천원 이상
price_factor = 0.9
final_amount = base_amount * base_weight * price_factor
# 최대/최소 제한
return max(40000, min(400000, final_amount))
def execute_advanced_monthly_buy(self, symbol: str, signal: str, current_price: float, data: pd.DataFrame) -> bool:
"""고급 월봉 매수 실행"""
try:
# 매수 금액 결정
buy_amount = self.get_advanced_monthly_buy_amount(symbol, signal, current_price, data)
# 매수 수량 계산
buy_quantity = buy_amount / current_price
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {symbol} 고급 월봉 매수 실행")
print(f" 신호: {signal}")
print(f" 현재가: {current_price:,.0f}")
print(f" 매수금액: {buy_amount:,.0f}")
print(f" 매수수량: {buy_quantity:.6f}")
# 실제 매수 로직은 여기에 구현
# self.buy_coin(symbol, buy_quantity, current_price)
# 쿨다운 설정
self.set_advanced_monthly_cooldown(symbol)
return True
except Exception as e:
print(f"Error executing advanced monthly buy for {symbol}: {str(e)}")
return False
def check_advanced_monthly_cooldown(self, symbol: str) -> bool:
"""고급 월봉 매수 쿨다운 확인"""
try:
cooldown_data = self.load_cooldown_data()
if symbol in cooldown_data:
last_buy_time = datetime.fromisoformat(cooldown_data[symbol])
# 월봉 매수는 30일 쿨다운
if (datetime.now() - last_buy_time).days < 30:
return False
return True
except:
return True
def set_advanced_monthly_cooldown(self, symbol: str) -> None:
"""고급 월봉 매수 쿨다운 설정"""
try:
cooldown_data = self.load_cooldown_data()
cooldown_data[symbol] = datetime.now().isoformat()
self.save_cooldown_data(cooldown_data)
except Exception as e:
print(f"Error setting advanced monthly cooldown for {symbol}: {str(e)}")
def monitor_advanced_monthly_coins(self) -> None:
"""고급 월봉/주봉 기준 코인 모니터링 (월봉 부족시 주봉으로 자동 전환)"""
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] 고급 월봉/주봉 모니터링 시작 - 전략 2")
for symbol in KR_COINS_2: # 두 번째 그룹 코인들
try:
# 월봉 데이터 가져오기 (43200분 = 1개월)
monthly_data = self.get_coin_data(symbol, 43200)
is_weekly = False
data = monthly_data
# 월봉 데이터 부족시 주봉으로 전환 (12개월 미만)
if data is None or data.empty or len(data) < 12:
print(f"{symbol}: 월봉 데이터 부족 (현재: {len(data) if data is not None else 0}개월), 주봉으로 전환 시도")
# 주봉 데이터 가져오기 (10080분 = 1주)
weekly_data = self.get_coin_data(symbol, 10080)
if weekly_data is None or weekly_data.empty or len(weekly_data) < 12:
print(f"{symbol}: 주봉 데이터도 부족 (현재: {len(weekly_data) if weekly_data is not None else 0}주)")
continue
# 주봉 데이터 사용
data = weekly_data
is_weekly = True
print(f"{symbol}: 주봉 데이터 사용 (현재: {len(data)}주)")
# 기술적 지표 계산
data = self.calculate_advanced_monthly_indicators(data, is_weekly)
# 매수 신호 생성
data = self.generate_advanced_monthly_signals(symbol, data)
# 최신 신호 확인
if data['point'].iloc[-1] == 1:
signal = data['signal'].iloc[-1]
current_price = data['Close'].iloc[-1]
# 쿨다운 확인
if not self.check_advanced_monthly_cooldown(symbol):
continue
# 매수 실행
self.execute_advanced_monthly_buy(symbol, signal, current_price, data)
else:
timeframe = "주봉" if is_weekly else "월봉"
print(f"{symbol}: 고급 {timeframe} 매수 신호 없음")
time.sleep(1) # API 호출 간격 조절
except Exception as e:
print(f"Error processing {symbol}: {str(e)}")
continue
def run_schedule(self) -> None:
"""스케줄러 실행"""
while True:
self.monitor_advanced_monthly_coins()
time.sleep(2) # 2시간마다 체크
if __name__ == "__main__":
monitor = MonthlyCoinMonitor2()
monitor.run_schedule()