투자관리 화면 수정
This commit is contained in:
@@ -290,41 +290,85 @@ public class PaperTradingService {
|
||||
.filter(m -> m != null && !m.isBlank())
|
||||
.findFirst()
|
||||
.orElse("LONG_ONLY");
|
||||
if ("LONG_ONLY".equals(positionMode)) {
|
||||
GcPaperPosition posNow = positionRepo.findByAccountIdAndSymbol(account.getId(), market)
|
||||
.orElse(null);
|
||||
double held = posNow != null ? posNow.getQuantity().doubleValue() : 0;
|
||||
BigDecimal defaultMax = account.getInitialCapitalSnapshot() != null
|
||||
? account.getInitialCapitalSnapshot()
|
||||
: (app.getPaperInitialCapital() != null
|
||||
? app.getPaperInitialCapital() : BigDecimal.valueOf(10_000_000));
|
||||
GcPaperSymbolAllocation alloc = allocationService.getOrDefaultEntity(
|
||||
account.getId(), market, defaultMax);
|
||||
boolean staged = PaperTradeStageService.usesStagedTrading(alloc);
|
||||
|
||||
GcPaperPosition posNow = positionRepo.findByAccountIdAndSymbol(account.getId(), market)
|
||||
.orElse(null);
|
||||
double held = posNow != null ? posNow.getQuantity().doubleValue() : 0;
|
||||
|
||||
if ("LONG_ONLY".equals(positionMode) && !staged) {
|
||||
if ("BUY".equals(signalType) && held > 0) return;
|
||||
if ("SELL".equals(signalType) && held <= 0) return;
|
||||
}
|
||||
|
||||
double feeRate = pct(app.getPaperFeeRatePct(), 0.05);
|
||||
double slip = pct(app.getPaperSlippagePct(), 0);
|
||||
double minOrder = app.getPaperMinOrderKrw() != null
|
||||
? app.getPaperMinOrderKrw().doubleValue() : 5000;
|
||||
|
||||
if ("BUY".equals(signalType)) {
|
||||
double budgetPct = pct(app.getPaperAutoTradeBudgetPct(), 95);
|
||||
double cash = account.getCashBalance().doubleValue();
|
||||
double reserved = account.getReservedCash() != null
|
||||
? account.getReservedCash().doubleValue() : 0;
|
||||
double budget = (cash - reserved) * budgetPct / 100.0;
|
||||
double execPrice = price * (1 + slip / 100.0);
|
||||
double denom = execPrice * (1 + feeRate / 100.0);
|
||||
if (denom <= 0 || budget < minOrder) return;
|
||||
double qty = budget / denom;
|
||||
if (qty * execPrice < minOrder) return;
|
||||
executeTrade(uid, app, market, "BUY", "market", "STRATEGY",
|
||||
strategyId, price, qty, null, true);
|
||||
log.info("[Paper] STRATEGY BUY {} qty≈{} @ {}", market, qty, price);
|
||||
if (staged) {
|
||||
if (held <= 0) {
|
||||
allocationService.resetTradeStages(account.getId(), market);
|
||||
alloc = allocationService.getOrDefaultEntity(account.getId(), market, defaultMax);
|
||||
} else if ("LONG_ONLY".equals(positionMode)
|
||||
&& alloc.getBuyStageDone() != null && alloc.getBuyStageDone() >= 3) {
|
||||
return;
|
||||
}
|
||||
double stageKrw = PaperTradeStageService.nextBuyStageKrw(alloc);
|
||||
if (stageKrw <= 0) return;
|
||||
if (stageKrw < minOrder) return;
|
||||
double execPrice = price * (1 + slip / 100.0);
|
||||
double denom = execPrice * (1 + feeRate / 100.0);
|
||||
if (denom <= 0) return;
|
||||
double qty = stageKrw / denom;
|
||||
if (qty * execPrice < minOrder) return;
|
||||
executeTrade(uid, app, market, "BUY", "market", "STRATEGY",
|
||||
strategyId, price, qty, null, true);
|
||||
allocationService.advanceBuyStageAfterTrade(account.getId(), market);
|
||||
log.info("[Paper] STRATEGY BUY (staged) {} qty≈{} @ {}", market, qty, price);
|
||||
} else {
|
||||
double budgetPct = pct(app.getPaperAutoTradeBudgetPct(), 95);
|
||||
double cash = account.getCashBalance().doubleValue();
|
||||
double reserved = account.getReservedCash() != null
|
||||
? account.getReservedCash().doubleValue() : 0;
|
||||
double budget = (cash - reserved) * budgetPct / 100.0;
|
||||
double execPrice = price * (1 + slip / 100.0);
|
||||
double denom = execPrice * (1 + feeRate / 100.0);
|
||||
if (denom <= 0 || budget < minOrder) return;
|
||||
double qty = budget / denom;
|
||||
if (qty * execPrice < minOrder) return;
|
||||
executeTrade(uid, app, market, "BUY", "market", "STRATEGY",
|
||||
strategyId, price, qty, null, true);
|
||||
log.info("[Paper] STRATEGY BUY {} qty≈{} @ {}", market, qty, price);
|
||||
}
|
||||
} else {
|
||||
GcPaperPosition pos = positionRepo.findByAccountIdAndSymbol(account.getId(), market)
|
||||
.orElse(null);
|
||||
if (pos == null || pos.getQuantity().doubleValue() <= 0) return;
|
||||
double avail = availableSellQty(account.getId(), market, pos.getQuantity().doubleValue());
|
||||
if (held <= 0) return;
|
||||
double avail = availableSellQty(account.getId(), market, held);
|
||||
if (avail <= 0) return;
|
||||
executeTrade(uid, app, market, "SELL", "market", "STRATEGY",
|
||||
strategyId, price, avail, null, true);
|
||||
log.info("[Paper] STRATEGY SELL {} qty={} @ {}", market, avail, price);
|
||||
|
||||
if (staged) {
|
||||
double stageKrw = PaperTradeStageService.nextSellStageKrw(alloc);
|
||||
if (stageKrw <= 0) return;
|
||||
if (stageKrw < minOrder) return;
|
||||
double execPrice = price * (1 - slip / 100.0);
|
||||
double qty = PaperTradeStageService.sellQtyForStageKrw(stageKrw, avail, execPrice);
|
||||
if (qty * execPrice < minOrder) return;
|
||||
executeTrade(uid, app, market, "SELL", "market", "STRATEGY",
|
||||
strategyId, price, qty, null, true);
|
||||
allocationService.advanceSellStageAfterTrade(account.getId(), market);
|
||||
log.info("[Paper] STRATEGY SELL (staged) {} qty={} @ {}", market, qty, price);
|
||||
} else {
|
||||
executeTrade(uid, app, market, "SELL", "market", "STRATEGY",
|
||||
strategyId, price, avail, null, true);
|
||||
log.info("[Paper] STRATEGY SELL {} qty={} @ {}", market, avail, price);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("[Paper] auto trade failed {} {}: {}", market, signalType, e.getMessage());
|
||||
@@ -591,6 +635,9 @@ public class PaperTradingService {
|
||||
.positionQtyAfter(qtyAfter)
|
||||
.build());
|
||||
ledgerService.recordSellSettle(account, trade, netProceeds);
|
||||
if ("STRATEGY".equals(source) && qtyAfter.compareTo(BigDecimal.valueOf(0.00000001)) <= 0) {
|
||||
allocationService.resetTradeStages(account.getId(), market);
|
||||
}
|
||||
return toTradeDto(trade);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user