Автоматический режим M2M и имитация QUIK МНП

Автоматический режим (Настройка → НРД, выключен по умолчанию): входящие переводы — решение по свежей
сверке с DEPO без оператора (пакет только целиком; бумага для квал. инвесторов при неполной или
непрочитанной квалификации — отказ M2M08), поручение 16/1 — как только пришёл черновик MF010,
поручение 16 по исходящим — по черновику. Нет сверки или ИШ — повтор каждые 3 минуты и оповещение,
без сверки ничего не принимается. Обрабатывается только появившееся не раньше суток до включения
(старые черновики в INBOX не подаются). Решение не отправляется повторно по уже отвеченному переводу.

Имитация QUIK МНП (Настройка → QUIK МНП → цикл): регистрация, подпись, снятие и зачисление проходят
как выполненные с пометкой «имитация», в МНП ничего не пишется; события в DEPO — как обычно.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zuevav
2026-09-16 14:59:23 +03:00
parent 4b62d00ac2
commit d47229c9a5
12 changed files with 486 additions and 30 deletions
+30
View File
@@ -466,6 +466,24 @@ func quikResolveClient(ctx context.Context, rc *RuntimeConfig, ser, num string)
// ---- высокоуровневые операции цикла ----
// quikActive — цикл M2M в МНП работает: записи разрешены или включена имитация.
func quikActive(s QuikMNPSettings) bool { return s.WritesEnabled || s.Emulate }
// quikEmulated — шаг цикла в режиме имитации: связка переходит в состояние state, в МНП ничего не
// пишется (нет пользователя QUIK для блокировок и лимитов); события в DEPO — как при реальной работе.
func quikEmulated(rc *RuntimeConfig, guid, isin, action, state, what string) *QuikLink {
l := globalQuikLinks.update(guid, isin, func(l *QuikLink) {
if l.InstrNo == "" {
l.InstrNo = "ИМИТ-" + shortGUID(guid)
}
l.State, l.Err = state, ""
l.Steps = append(l.Steps, QuikStep{At: time.Now(), Action: action, Reply: "имитация: " + what + " — в МНП не записано", OK: true})
})
log.Printf("quik: %s %s (имитация, в МНП не записано): %s × %v", shortGUID(guid), what, isin, l.Qty)
go depoOnQuik(rc, guid, isin, action, l.InstrNo)
return l
}
func quikStep(action string, aid int64, r QuikActionResult, ok bool) QuikStep {
return QuikStep{At: time.Now(), Action: action, ActionID: aid, Status: r.QueryStatus, Reply: r.ReplyText, OK: ok}
}
@@ -476,6 +494,9 @@ func QuikOutRegister(ctx context.Context, rc *RuntimeConfig, guid, clientID, con
l := globalQuikLinks.update(guid, isin, func(l *QuikLink) {
l.Direction, l.ClientID, l.Contract, l.ISIN, l.Qty = "out", clientID, contract, isin, qty
})
if s.Emulate {
return quikEmulated(rc, guid, isin, "register", "registered", "вывод зарегистрирован, бумаги заблокированы"), nil
}
if err := quikEnsureRecipient(ctx, s, recipientINN, recipientName); err != nil {
return quikFail(rc, guid, isin, "register", err), err
}
@@ -508,6 +529,9 @@ func QuikOutSign(ctx context.Context, rc *RuntimeConfig, guid, isin, comment str
if l.State == "signed" {
return l, nil
}
if s.Emulate {
return quikEmulated(rc, guid, isin, "sign", "signed", "поручение подписано, бумаги списаны"), nil
}
var no float64
fmt.Sscan(l.InstrNo, &no)
aid, err := quikExecSign(ctx, s, no, l.ClientID, l.Qty, comment)
@@ -539,6 +563,9 @@ func QuikOutDeny(ctx context.Context, rc *RuntimeConfig, guid, isin, reason stri
if l.State == "denied" || l.State == "signed" {
return l, nil
}
if s.Emulate {
return quikEmulated(rc, guid, isin, "deny", "denied", "поручение снято ("+reason+")"), nil
}
var no float64
fmt.Sscan(l.InstrNo, &no)
aid, err := quikExecDeny(ctx, s, no, reason)
@@ -569,6 +596,9 @@ func QuikInDeposit(ctx context.Context, rc *RuntimeConfig, guid, clientID, contr
globalQuikLinks.update(guid, isin, func(l *QuikLink) {
l.Direction, l.ClientID, l.Contract, l.ISIN, l.Qty = "in", clientID, contract, isin, qty
})
if s.Emulate {
return quikEmulated(rc, guid, isin, "deposit", "deposited", "ввод зарегистрирован, бумаги зачислены"), nil
}
if strings.TrimSpace(senderINN) != "" {
_ = quikEnsureRecipient(ctx, s, senderINN, senderName)
}