feat: add Citations and WatchlistChat components, integrate with API
- Implemented Citations component to display citation data. - Created WatchlistDrawer and ChatSidebar components for managing watchlists and AI chat functionality. - Integrated API calls for watchlist management and chat interactions. - Updated index.tsx to include new components in the main application layout. - Added API client in lib/api.ts for structured API interactions. - Developed Alerts, Dashboard, Portfolio, Routines, Screener, and Report pages with relevant data fetching and UI components. - Introduced styles in tokens.css for consistent theming across the application. - Configured TypeScript and Vite for project setup and development.
This commit is contained in:
1 parent
0db2cf28b3
commit
8c184ccae1
111 files changed
+12349
-62
No files matched your search
@@ -0,0 +1,89 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// ResolveDue resolves predictions older than 30d against actual return:
|
||||
// first stored close on/after predict_date vs latest stored close.
|
||||
// BUY hits above +5%, AVOID hits below -5%, HOLD hits within ±10%.
|
||||
// Returns the number of newly resolved rows.
|
||||
func (db *DB) ResolveDue() (int, error) {
|
||||
due, err := db.DueForResolution()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
resolved := 0
|
||||
for _, p := range due {
|
||||
id, _ := p["id"].(int64)
|
||||
ticker, _ := p["ticker"].(string)
|
||||
pred, _ := p["prediction"].(string)
|
||||
since, _ := p["predict_date"].(string)
|
||||
series, err := db.dailyCloses(ticker)
|
||||
if err != nil || len(series) < 2 {
|
||||
continue
|
||||
}
|
||||
base, ok := firstOnOrAfter(series, since)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
last := series[len(series)-1]
|
||||
if base.close <= 0 {
|
||||
continue
|
||||
}
|
||||
ret := (last.close - base.close) / base.close
|
||||
hit := false
|
||||
switch pred {
|
||||
case "BUY":
|
||||
hit = ret > 0.05
|
||||
case "AVOID":
|
||||
hit = ret < -0.05
|
||||
default: // HOLD
|
||||
hit = ret >= -0.10 && ret <= 0.10
|
||||
}
|
||||
if err := db.ResolvePrediction(id, hit, ret); err == nil {
|
||||
resolved++
|
||||
}
|
||||
}
|
||||
return resolved, nil
|
||||
}
|
||||
|
||||
type closePoint struct {
|
||||
date string
|
||||
close float64
|
||||
}
|
||||
|
||||
// dailyCloses parses every stored daily payload into a date-sorted series.
|
||||
func (db *DB) dailyCloses(ticker string) ([]closePoint, error) {
|
||||
rows, err := db.Query(`SELECT payload_json FROM snapshots WHERE ticker=? AND source='daily'`, ticker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []closePoint
|
||||
for rows.Next() {
|
||||
var raw string
|
||||
if err := rows.Scan(&raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, b := range parseDailyBars(raw, "") {
|
||||
if b.Date != "" && b.Close > 0 {
|
||||
out = append(out, closePoint{b.Date, b.Close})
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].date < out[j].date })
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func firstOnOrAfter(series []closePoint, date string) (closePoint, bool) {
|
||||
for _, p := range series {
|
||||
if p.date >= date {
|
||||
return p, true
|
||||
}
|
||||
}
|
||||
return closePoint{}, false
|
||||
}
|
||||
Reference in new issue
Block a user