third version

This commit is contained in:
2026-06-08 07:05:01 +00:00
parent 282c841e11
commit 52a935b8b4
20 changed files with 1371 additions and 151 deletions
+13 -3
View File
@@ -29,6 +29,8 @@ type SizingConfig struct {
type SizingInput struct {
Portfolio domain.Portfolio
SelectedInstruments int
ExistingExposure decimal.Decimal
ReservedCash decimal.Decimal
LimitPrice decimal.Decimal
Lot int64
EntryIntervalVolume decimal.Decimal
@@ -66,11 +68,19 @@ func (s Sizer) Size(input SizingInput) SizingResult {
input.SelectedInstruments = 1
}
capLimit := input.Portfolio.Equity.Mul(s.cfg.MaxPositionPct)
exposureLimit := input.Portfolio.Equity.Mul(s.cfg.MaxTotalExposurePct).
Div(decimal.NewFromInt(int64(input.SelectedInstruments)))
totalExposureLimit := input.Portfolio.Equity.Mul(s.cfg.MaxTotalExposurePct)
remainingExposure := totalExposureLimit.Sub(input.ExistingExposure)
if remainingExposure.IsNegative() {
remainingExposure = decimal.Zero
}
exposureLimit := remainingExposure.Div(decimal.NewFromInt(int64(input.SelectedInstruments)))
liquidityLimit := money.Min(input.EntryIntervalVolume, input.ExitIntervalVolume).
Mul(s.cfg.MaxParticipationRate)
cashLimit := input.Portfolio.Cash.Mul(s.cfg.CashUsageBuffer)
availableCash := input.Portfolio.Cash.Sub(input.ReservedCash)
if availableCash.IsNegative() {
availableCash = decimal.Zero
}
cashLimit := availableCash.Mul(s.cfg.CashUsageBuffer)
riskLimit := capLimit
if input.Q05OvernightAbs.IsPositive() {
riskBudget := input.Portfolio.Equity.Mul(s.cfg.RiskBudgetPerInstrumentPct)
+25
View File
@@ -170,3 +170,28 @@ func TestSizerAppliesSizeReductionFactor(t *testing.T) {
t.Fatalf("unexpected reduced sizing: %+v", got)
}
}
func TestSizerSubtractsExistingExposureAndReservedCash(t *testing.T) {
sizer := NewSizer(SizingConfig{
MaxPositionPct: rd("1"),
MaxTotalExposurePct: rd("0.50"),
MaxParticipationRate: rd("1"),
CashUsageBuffer: rd("1"),
RiskBudgetPerInstrumentPct: rd("1"),
MinOrderNotionalRUB: rd("1"),
})
got := sizer.Size(SizingInput{
Portfolio: domain.Portfolio{Equity: rd("100000"), Cash: rd("50000")},
SelectedInstruments: 2,
ExistingExposure: rd("30000"),
ReservedCash: rd("10000"),
LimitPrice: rd("100"),
Lot: 1,
EntryIntervalVolume: rd("1000000"),
ExitIntervalVolume: rd("1000000"),
Q05OvernightAbs: rd("1"),
})
if got.Lots != 100 || !got.TargetNotional.Equal(rd("10000")) {
t.Fatalf("unexpected sizing with reserved exposure: %+v", got)
}
}