fix: 분할매도 잔량 미갱신 — 스윙·국내 executor·미국 경로 동일 패턴 + 수동매도 ActiveTrade 정리
DT에서 찾은 '분할매도 후 ActiveTrade.quantity 미갱신' 패턴이 3곳 더 있었음: - us_market_scheduler: total_qty = trade.quantity 를 매도량 산정에 직접 사용 → 분할매도 후 다음 사이클이 원래 수량 기준으로 팔아 과다매도(US_TRADING_ENABLED=true 상태) - swing/exit_service, trade_executor._execute_sell: remaining_pct만 갱신 또한 수동 매도(/portfolio/sell)가 ActiveTrade를 전혀 정리하지 않아 청산된 종목이 active로 잔존(삼아알미늄·LG 등) → 재매수 시 옛 remaining_pct가 살아나 1차 익절이 건너뛰어짐. 전량 매도 시 close, 분할 시 잔량 갱신으로 수정. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -98,3 +98,41 @@ async def test_dt_partial_exit_updates_active_trade_quantity():
|
||||
at = [u for u in upserts if u.get("stock_code") == "064400"]
|
||||
assert at and at[-1]["quantity"] == 4, f"ActiveTrade 잔량 갱신 누락: {upserts}"
|
||||
day_trading_state.positions.clear()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_swing_partial_exit_persists_remaining_quantity():
|
||||
"""스윙 분할매도도 ActiveTrade.quantity를 갱신해야 한다(DT와 동일 패턴)."""
|
||||
import inspect
|
||||
from app.services.swing import exit_service as ses
|
||||
src = inspect.getsource(ses)
|
||||
block = src[src.index("분할 매도 후 remaining_pct 갱신"):]
|
||||
block = block[:block.index("await enqueue_active_trade_upsert(_at_data)")]
|
||||
assert '"quantity": quantity - sell_qty' in block, "스윙 분할매도에 잔량 갱신 누락"
|
||||
|
||||
|
||||
def test_us_partial_exit_persists_remaining_quantity():
|
||||
"""미국 스윙도 동일 — total_qty = trade.quantity 를 읽으므로 갱신이 없으면 과다매도."""
|
||||
import inspect
|
||||
from app.services import us_market_scheduler as us
|
||||
src = inspect.getsource(us)
|
||||
i = src.index('"strategy_name": "us_mean_reversion",\n "remaining_pct"')
|
||||
block = src[i:i + 500]
|
||||
assert '"quantity": max(0, total_qty - sell_qty)' in block, "미국 분할매도에 잔량 갱신 누락"
|
||||
|
||||
|
||||
def test_domestic_executor_partial_exit_persists_quantity():
|
||||
import inspect
|
||||
from app.services import trade_executor as te
|
||||
src = inspect.getsource(te)
|
||||
i = src.index('"remaining_pct": new_remaining,\n "quantity"')
|
||||
assert 'max(0, total_qty - quantity)' in src[i:i + 200]
|
||||
|
||||
|
||||
def test_manual_sell_closes_active_trade():
|
||||
"""수동 전량 매도는 ActiveTrade를 closed 로 만들어야 유령 행이 남지 않는다."""
|
||||
import inspect
|
||||
from app.api.endpoints import portfolio as pf
|
||||
src = inspect.getsource(pf.sell_stock)
|
||||
assert "_enq_close_at(stock_code" in src
|
||||
assert '"quantity": original_holding_qty - quantity' in src
|
||||
|
||||
Reference in New Issue
Block a user