import assert from "node:assert/strict"; import test from "node:test"; import { calculateEffectiveAllocationAmount, calculateEffectiveDailyLossLimit, resolveValidationCashBalance, resolveOrderQuantity, } from "../../lib/autotrade/risk"; test("allocationPercent와 allocationAmount를 함께 반영해 실주문 예산 계산", () => { assert.equal(calculateEffectiveAllocationAmount(2_000_000, 10, 500_000), 200_000); assert.equal(calculateEffectiveAllocationAmount(2_000_000, 30, 300_000), 300_000); assert.equal(calculateEffectiveAllocationAmount(2_000_000, 0, 300_000), 0); assert.equal(calculateEffectiveAllocationAmount(0, 30, 300_000), 0); }); test("dailyLossPercent와 dailyLossAmount를 함께 반영해 실손실 한도 계산", () => { assert.equal(calculateEffectiveDailyLossLimit(200_000, 2, 50_000), 4_000); assert.equal(calculateEffectiveDailyLossLimit(200_000, 10, 5_000), 5_000); assert.equal(calculateEffectiveDailyLossLimit(200_000, 0, 5_000), 5_000); }); test("매수 수량은 비용 포함 단가 기준으로 계산", () => { const quantity = resolveOrderQuantity({ side: "buy", price: 10_000, unitCost: 10_015, requestedQuantity: undefined, effectiveAllocationAmount: 100_000, maxOrderAmountRatio: 1, }); assert.equal(quantity, 9); }); test("매수 수량: 비율 상한으로 0주여도 전체 예산 1주 가능하면 최소 1주 허용", () => { const quantity = resolveOrderQuantity({ side: "buy", price: 16_730, unitCost: 16_730, requestedQuantity: undefined, effectiveAllocationAmount: 21_631, maxOrderAmountRatio: 0.25, }); assert.equal(quantity, 1); }); test("매도 수량은 예산과 무관하게 요청값 기준(이후 보유/매도가능 검증)", () => { const quantity = resolveOrderQuantity({ side: "sell", price: 10_000, requestedQuantity: 3, effectiveAllocationAmount: 1_000, maxOrderAmountRatio: 0.1, }); assert.equal(quantity, 3); }); test("검증 기준 자금: 예수금/매수가능금액 중 보수적인 값 사용", () => { const bothAvailable = resolveValidationCashBalance({ cashBalance: 500_000, orderableCash: 430_000, }); assert.equal(bothAvailable.cashBalance, 430_000); assert.equal(bothAvailable.source, "min_of_both"); const onlyOrderable = resolveValidationCashBalance({ cashBalance: 0, orderableCash: 36_664, }); assert.equal(onlyOrderable.cashBalance, 36_664); assert.equal(onlyOrderable.source, "orderable_cash"); const onlyCash = resolveValidationCashBalance({ cashBalance: 120_000, orderableCash: 0, }); assert.equal(onlyCash.cashBalance, 120_000); assert.equal(onlyCash.source, "cash_balance"); });