feat: 自动候选筛选与股票研究工作台
This commit is contained in:
@@ -2,6 +2,7 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"git.sundynix.cn/Blizzard/Veyra/internal/apperror"
|
||||
"git.sundynix.cn/Blizzard/Veyra/internal/model"
|
||||
"github.com/google/uuid"
|
||||
@@ -54,6 +55,41 @@ func (r *MarketRepository) Save(ctx context.Context, c model.ProviderConfig, lis
|
||||
return mapError(e)
|
||||
}
|
||||
}
|
||||
if message == "" {
|
||||
// Quote events are produced only for tracked plans and truly recent vendor observations.
|
||||
// Re-reading an unchanged close cannot enqueue another price event.
|
||||
rows, err := tx.Query(ctx, `INSERT INTO veyra_quote_snapshot(id,symbol,exchange,data_mode,price_minor,observed_at,version,source_id,source_version)
|
||||
SELECT gen_random_uuid()::text,i.symbol,i.exchange,'public',i.price_cents,i.observed_at,1,i.source_id,i.source_version FROM veyra_instrument i
|
||||
WHERE i.source_id=$1 AND i.source_version=$2 AND i.observed_at>=now()-interval '1 minute' AND i.observed_at<=now()+interval '1 minute'
|
||||
AND EXISTS(SELECT 1 FROM veyra_trade_plan p JOIN veyra_candidate_revision r ON r.id=p.candidate_revision_id JOIN veyra_candidate c ON c.id=r.candidate_id WHERE `+activePlanPredicate+` AND r.snapshot->>'symbol'=i.symbol AND r.snapshot->>'exchange'=i.exchange)
|
||||
ON CONFLICT(exchange,symbol,data_mode) DO UPDATE SET price_minor=EXCLUDED.price_minor,observed_at=EXCLUDED.observed_at,version=veyra_quote_snapshot.version+1,source_id=EXCLUDED.source_id,source_version=EXCLUDED.source_version,updated_at=now()
|
||||
WHERE EXCLUDED.observed_at>veyra_quote_snapshot.observed_at RETURNING `+quoteColumns, c.ID, c.Version)
|
||||
if err != nil {
|
||||
return mapError(err)
|
||||
}
|
||||
quotes := make([]model.QuoteSnapshot, 0)
|
||||
for rows.Next() {
|
||||
q, err := scanQuote(rows)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
}
|
||||
quotes = append(quotes, q)
|
||||
}
|
||||
rows.Close()
|
||||
if err := rows.Err(); err != nil {
|
||||
return mapError(err)
|
||||
}
|
||||
for _, q := range quotes {
|
||||
payload, err := json.Marshal(q)
|
||||
if err != nil {
|
||||
return apperror.ErrUnavailable
|
||||
}
|
||||
if _, err := tx.Exec(ctx, `INSERT INTO veyra_outbox_event(id,aggregate_type,aggregate_id,aggregate_version,event_type,payload) VALUES($1,'quote_snapshot',$2,$3,'quote.observed',$4)`, uuid.NewString(), q.ID, q.Version, payload); err != nil {
|
||||
return mapError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
_, e = tx.Exec(ctx, `INSERT INTO veyra_market_sync(id,source_id,source_version,instrument_count,status,message,started_at) VALUES($1,$2,$3,$4,$5,$6,$7)`, uuid.NewString(), c.ID, c.Version, len(list), status, message, started)
|
||||
if e != nil {
|
||||
return mapError(e)
|
||||
|
||||
Reference in New Issue
Block a user