113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
"""
|
|
경계값 테스트: profit_rate가 정확히 10%, 30%일 때 매도 조건 검증
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from src.signals import evaluate_sell_conditions
|
|
|
|
|
|
class TestBoundaryConditions:
|
|
"""매도 조건의 경계값 테스트"""
|
|
|
|
def test_profit_rate_exactly_10_percent_triggers_partial_sell(self):
|
|
"""수익률이 정확히 10%일 때 부분 매도(조건3) 발생"""
|
|
# Given: 매수가 100, 현재가 110 (정확히 10% 수익)
|
|
buy_price = 100.0
|
|
current_price = 110.0
|
|
max_price = 110.0
|
|
holding_info = {"partial_sell_done": False}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then
|
|
assert result["status"] == "stop_loss" # 부분 익절은 stop_loss (1시간 주기)
|
|
assert result["sell_ratio"] == 0.5
|
|
assert result["set_partial_sell_done"] is True
|
|
assert "부분 익절" in result["reasons"][0]
|
|
|
|
def test_profit_rate_exactly_30_percent_in_high_zone(self):
|
|
"""최고 수익률 30% 초과 구간에서 수익률이 정확히 30%로 떨어질 때"""
|
|
# Given: 최고가 135 (35% 수익), 현재가 130 (30% 수익)
|
|
buy_price = 100.0
|
|
current_price = 130.0
|
|
max_price = 135.0
|
|
holding_info = {"partial_sell_done": True}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then: 수익률이 30% 이하(<= 30)로 하락하여 조건5-2 발동 (stop_loss)
|
|
assert result["status"] == "stop_loss"
|
|
assert result["sell_ratio"] == 1.0
|
|
assert "수익률 보호(조건5" in result["reasons"][0] # 조건5-2도 매칭
|
|
|
|
def test_profit_rate_below_30_percent_triggers_sell(self):
|
|
"""최고 수익률 30% 초과 구간에서 수익률이 30% 미만으로 떨어질 때"""
|
|
# Given: 최고가 135 (35% 수익), 현재가 129.99 (29.99% 수익)
|
|
buy_price = 100.0
|
|
current_price = 129.99
|
|
max_price = 135.0
|
|
holding_info = {"partial_sell_done": True}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then: 조건5-2 발동 (수익률 30% 미만으로 하락)
|
|
assert result["status"] == "stop_loss"
|
|
assert result["sell_ratio"] == 1.0
|
|
assert "수익률 보호(조건5" in result["reasons"][0] # 조건5-2도 매칭
|
|
|
|
def test_profit_rate_exactly_10_percent_in_mid_zone(self):
|
|
"""최고 수익률 10~30% 구간에서 수익률이 정확히 10%일 때"""
|
|
# Given: 최고가 120 (20% 수익), 현재가 110 (10% 수익)
|
|
buy_price = 100.0
|
|
current_price = 110.0
|
|
max_price = 120.0
|
|
holding_info = {"partial_sell_done": True}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then: 수익률이 10% 이하(<= 10)로 하락하여 조건4-2 발동 (stop_loss)
|
|
assert result["status"] == "stop_loss"
|
|
assert result["sell_ratio"] == 1.0
|
|
assert "수익률 보호(조건4" in result["reasons"][0] # 조건4-2도 매칭
|
|
|
|
def test_profit_rate_below_10_percent_triggers_sell(self):
|
|
"""최고 수익률 10~30% 구간에서 수익률이 10% 미만으로 떨어질 때"""
|
|
# Given: 최고가 120 (20% 수익), 현재가 109.99 (9.99% 수익)
|
|
buy_price = 100.0
|
|
current_price = 109.99
|
|
max_price = 120.0
|
|
holding_info = {"partial_sell_done": True}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then: 조건4-2 발동 (수익률 10% 미만으로 하락)
|
|
assert result["status"] == "stop_loss"
|
|
assert result["sell_ratio"] == 1.0
|
|
assert "수익률 보호(조건4" in result["reasons"][0] # 조건4-2도 매칭
|
|
|
|
def test_partial_sell_already_done_no_duplicate(self):
|
|
"""부분 매도 이미 완료된 경우 중복 발동 안됨"""
|
|
# Given: 매수가 100, 현재가 110 (10% 수익), 이미 부분 매도 완료
|
|
buy_price = 100.0
|
|
current_price = 110.0
|
|
max_price = 110.0
|
|
holding_info = {"partial_sell_done": True}
|
|
|
|
# When
|
|
result = evaluate_sell_conditions(current_price, buy_price, max_price, holding_info)
|
|
|
|
# Then: 부분 매도 재발동 안됨
|
|
assert result["status"] == "hold"
|
|
assert result["sell_ratio"] == 0.0
|
|
assert result["set_partial_sell_done"] is False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"])
|