Кабинет: архив не старше копии учёта (с пометкой), карточка бумаги без депозитарных реквизитов

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-18 15:56:48 +03:00
parent e7344d8121
commit 68e1153cb2
4 changed files with 39 additions and 10 deletions
+2 -1
View File
@@ -299,7 +299,8 @@ func registerLKAPI(mux *http.ServeMux, rc *RuntimeConfig, svc *Service) {
if err == nil && len(pf.Positions) == 0 && len(pf.Cash) == 0 {
// В торговой системе клиента нет (не торгует через QUIK) — текущий портфель из учёта.
if ar, e := lkArchivePortfolio(r.Context(), fancy, u.Contract, time.Now()); e == nil {
ar.Note = "по данным брокерского учёта на сегодня"
ar.Note = strings.TrimSpace(strings.TrimPrefix("в торговой системе позиций нет; портфель по брокерскому учёту на "+ar.AsOf+"; "+ar.Note, "; "))
ar.Note = strings.TrimSuffix(ar.Note, "; ")
pf = ar
}
}
+33 -2
View File
@@ -21,6 +21,7 @@ import (
"fmt"
"sort"
"strings"
"sync"
"time"
)
@@ -52,6 +53,13 @@ func lkArchivePortfolio(ctx context.Context, s FancyMSSQLSettings, contract stri
cctx, cancel := context.WithTimeout(ctx, 40*time.Second)
defer cancel()
day := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, time.UTC)
// Мы читаем копию учёта; она может отставать. Позже её последнего дня данных нет —
// показываем портфель на последний день копии и говорим об этом.
note := ""
if last := spectreAsOf(cctx, conn); !last.IsZero() && day.After(last) {
day = last
note = "данные брокерского учёта доступны по " + last.Format("02.01.2006")
}
today := time.Now()
isPast := day.Before(time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC))
@@ -110,7 +118,7 @@ func lkArchivePortfolio(ctx context.Context, s FancyMSSQLSettings, contract stri
}
}
out := &LKPortfolio{Source: "spectre", AsOf: day.Format("02.01.2006")}
out := &LKPortfolio{Source: "spectre", AsOf: day.Format("02.01.2006"), Note: note}
fx := spectreFx(cctx, conn, day)
byISIN := map[string]*LKPosition{}
cash := map[string]float64{}
@@ -182,11 +190,34 @@ func lkArchivePortfolio(ctx context.Context, s FancyMSSQLSettings, contract stri
}
lkPortfolioTotals(out)
if c.Closed {
out.Note = "договор закрыт"
out.Note = strings.TrimSpace(strings.TrimPrefix(out.Note+"; договор закрыт", "; "))
}
return out, nil
}
// spectreAsOf — последний день, за который в копии учёта есть документы (кэш 10 минут).
var spectreAsOfCache struct {
mu sync.Mutex
at time.Time
v time.Time
}
func spectreAsOf(ctx context.Context, conn *sql.DB) time.Time {
spectreAsOfCache.mu.Lock()
defer spectreAsOfCache.mu.Unlock()
if time.Since(spectreAsOfCache.at) < 10*time.Minute {
return spectreAsOfCache.v
}
var d sql.NullTime
_ = conn.QueryRowContext(ctx, `SELECT MAX(R_DATE) FROM OD_DOCS WHERE YEAR(R_DATE) < 9000`).Scan(&d)
v := time.Time{}
if d.Valid {
v = time.Date(d.Time.Year(), d.Time.Month(), d.Time.Day(), 0, 0, 0, 0, time.UTC)
}
spectreAsOfCache.at, spectreAsOfCache.v = time.Now(), v
return v
}
func abs(v float64) float64 {
if v < 0 {
return -v