Кабинет: архив не старше копии учёта (с пометкой), карточка бумаги без депозитарных реквизитов
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user