first commit of restructured project
This commit is contained in:
202
trahn-trade-backend/internal/repository/gridstate.go
Normal file
202
trahn-trade-backend/internal/repository/gridstate.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/kjannette/trahn-backend/internal/models"
|
||||
)
|
||||
|
||||
type GridStateRepo struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewGridStateRepo(pool *pgxpool.Pool) *GridStateRepo {
|
||||
return &GridStateRepo{pool: pool}
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) GetActive(ctx context.Context) (*models.GridState, error) {
|
||||
row := r.pool.QueryRow(ctx,
|
||||
`SELECT * FROM grid_state WHERE is_active = true ORDER BY updated_at DESC LIMIT 1`,
|
||||
)
|
||||
gs, err := scanGridState(row)
|
||||
if err != nil {
|
||||
if err.Error() == "no rows in result set" {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return gs, nil
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) Save(ctx context.Context, data *models.GridState) (*models.GridState, error) {
|
||||
tx, err := r.pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
|
||||
_, err = tx.Exec(ctx, `UPDATE grid_state SET is_active = false WHERE is_active = true`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := tx.QueryRow(ctx,
|
||||
`INSERT INTO grid_state
|
||||
(base_price, grid_levels_json, trades_executed, total_profit,
|
||||
last_sr_refresh, is_active, updated_at)
|
||||
VALUES ($1,$2,$3,$4,$5,true,NOW())
|
||||
RETURNING *`,
|
||||
data.BasePrice,
|
||||
data.GridLevelsJSON,
|
||||
data.TradesExecuted,
|
||||
data.TotalProfit,
|
||||
data.LastSRRefresh,
|
||||
)
|
||||
gs, err := scanGridState(row)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gs, nil
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) UpdateGridLevels(ctx context.Context, levels json.RawMessage) error {
|
||||
_, err := r.pool.Exec(ctx,
|
||||
`UPDATE grid_state SET grid_levels_json = $1, updated_at = NOW() WHERE is_active = true`,
|
||||
levels,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) UpdateTradeStats(ctx context.Context, tradesExecuted int, totalProfit float64) error {
|
||||
_, err := r.pool.Exec(ctx,
|
||||
`UPDATE grid_state SET trades_executed = $1, total_profit = $2, updated_at = NOW() WHERE is_active = true`,
|
||||
tradesExecuted, totalProfit,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) UpdatePaperWallet(ctx context.Context, pw *models.PaperWallet) error {
|
||||
tradesJSON, err := json.Marshal(pw.Trades)
|
||||
if err != nil {
|
||||
tradesJSON = []byte("[]")
|
||||
}
|
||||
_, err = r.pool.Exec(ctx,
|
||||
`UPDATE grid_state
|
||||
SET paper_eth_balance = $1,
|
||||
paper_usdc_balance = $2,
|
||||
paper_total_gas_spent = $3,
|
||||
paper_trades_json = $4,
|
||||
updated_at = NOW()
|
||||
WHERE is_active = true`,
|
||||
pw.ETHBalance, pw.USDCBalance, pw.TotalGasSpent, tradesJSON,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) InitializePaperWallet(ctx context.Context, initialETH, initialUSDC float64) error {
|
||||
state, err := r.GetActive(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if state != nil && state.PaperETHBalance != nil {
|
||||
return nil // already initialized
|
||||
}
|
||||
|
||||
_, err = r.pool.Exec(ctx,
|
||||
`UPDATE grid_state
|
||||
SET paper_eth_balance = $1,
|
||||
paper_usdc_balance = $2,
|
||||
paper_initial_eth = $1,
|
||||
paper_initial_usdc = $2,
|
||||
paper_total_gas_spent = 0,
|
||||
paper_trades_json = '[]'::jsonb,
|
||||
paper_start_time = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE is_active = true`,
|
||||
initialETH, initialUSDC,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) GetPaperWallet(ctx context.Context) (*models.PaperWallet, error) {
|
||||
state, err := r.GetActive(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state == nil || state.PaperETHBalance == nil {
|
||||
return nil, nil
|
||||
}
|
||||
pw := &models.PaperWallet{
|
||||
ETHBalance: valOr(state.PaperETHBalance, 0),
|
||||
USDCBalance: valOr(state.PaperUSDCBalance, 0),
|
||||
TotalGasSpent: valOr(state.PaperTotalGasSpent, 0),
|
||||
Trades: state.PaperTradesJSON,
|
||||
StartTime: state.PaperStartTime,
|
||||
InitialETH: valOr(state.PaperInitialETH, 0),
|
||||
InitialUSDC: valOr(state.PaperInitialUSDC, 0),
|
||||
}
|
||||
return pw, nil
|
||||
}
|
||||
|
||||
func (r *GridStateRepo) GetHistory(ctx context.Context, limit int) ([]models.GridState, error) {
|
||||
rows, err := r.pool.Query(ctx,
|
||||
`SELECT * FROM grid_state ORDER BY updated_at DESC LIMIT $1`,
|
||||
limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return collectGridStates(rows)
|
||||
}
|
||||
|
||||
// --- scan helpers ---
|
||||
|
||||
func scanGridState(row scannable) (*models.GridState, error) {
|
||||
var gs models.GridState
|
||||
err := row.Scan(
|
||||
&gs.ID, &gs.BasePrice, &gs.GridLevelsJSON,
|
||||
&gs.TradesExecuted, &gs.TotalProfit, &gs.LastSRRefresh,
|
||||
&gs.IsActive, &gs.CreatedAt, &gs.UpdatedAt,
|
||||
// paper wallet columns
|
||||
&gs.PaperETHBalance, &gs.PaperUSDCBalance, &gs.PaperTotalGasSpent,
|
||||
&gs.PaperTradesJSON, &gs.PaperStartTime,
|
||||
&gs.PaperInitialETH, &gs.PaperInitialUSDC,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &gs, nil
|
||||
}
|
||||
|
||||
func collectGridStates(rows rowsIter) ([]models.GridState, error) {
|
||||
var out []models.GridState
|
||||
for rows.Next() {
|
||||
var gs models.GridState
|
||||
if err := rows.Scan(
|
||||
&gs.ID, &gs.BasePrice, &gs.GridLevelsJSON,
|
||||
&gs.TradesExecuted, &gs.TotalProfit, &gs.LastSRRefresh,
|
||||
&gs.IsActive, &gs.CreatedAt, &gs.UpdatedAt,
|
||||
&gs.PaperETHBalance, &gs.PaperUSDCBalance, &gs.PaperTotalGasSpent,
|
||||
&gs.PaperTradesJSON, &gs.PaperStartTime,
|
||||
&gs.PaperInitialETH, &gs.PaperInitialUSDC,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, gs)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func valOr(p *float64, fallback float64) float64 {
|
||||
if p != nil {
|
||||
return *p
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
Reference in New Issue
Block a user