package db
import (
"encoding/json"
"fmt"
"time"
"github.com/go-redis/redis"
"github.com/shopspring/decimal"
)
type PortfolioStep string
const SELL_BEGIN PortfolioStep = "process_sell_all__1_all_sell_begin"
const SELL_END PortfolioStep = "process_sell_all__1_all_sell_end"
const BUY_BEGIN PortfolioStep = "process_sell_all__3_all_buy_begin"
const BUY_END PortfolioStep = "process_sell_all__3_all_buy_end"
const INTERMADIATE_STATE PortfolioStep = "process_print_balances__1_print_balances_begin"
type ViewBalances struct {
Id int64
Date time.Time
ReportId int64
MarketId int64
Payload struct {
Report
}
}
type Report struct {
Tag PortfolioStep
Date time.Time
Balances ReportBalances
Tickers ReportTickers
}
type ReportTickers struct {
Currency string
Balances map[string]decimal.Decimal
Rates BTCRates
Total decimal.Decimal
}
func (r ReportTickers) GetBTCRate(currency string) decimal.Decimal {
if currency == "BTC" {
return decimal.NewFromFloat(1.0)
}
return r.Rates[currency]
}
type BTCRates map[string]decimal.Decimal
func (b BTCRates) Rate(currency string) decimal.Decimal {
if currency == "BTC" {
return decimal.NewFromFloat(1.0)
}
return b[currency]
}
type ReportBalances map[string]struct {
Total decimal.Decimal
MarginTotal decimal.Decimal `json:"margin_total"`
MarginInPosition decimal.Decimal `json:"margin_in_position"`
MarginAvailable decimal.Decimal `json:"margin_available"`
}
func RedisReportKey(marketConfigId int64, timestamp, entity string) string {
return fmt.Sprintf("/cryptoportfolio/%v/%v/%v", marketConfigId, timestamp, entity)
}
func GetLatestReport(marketConfig MarketConfig) (Report, error) {
var reportPayload Report
var err error
var key string
// Get balance.
key = RedisReportKey(marketConfig.Id, "latest", "balance")
payload, err := Redis.Get(key).Bytes()
if err == redis.Nil {
return Report{}, fmt.Errorf("cannot find '%s' redis key", key)
} else if err != nil {
return Report{}, err
}
// Get date.
key = RedisReportKey(marketConfig.Id, "latest", "date")
dateString, err := Redis.Get(key).Result()
if err == redis.Nil {
return Report{}, fmt.Errorf("cannot find '%s' redis key", key)
} else if err != nil {
return Report{}, err
}
reportPayload.Date, err = time.Parse("2006-01-02T15:04:05", dateString)
if err != nil {
return Report{}, err
}
err = json.Unmarshal(payload, &reportPayload)
return reportPayload, err
}
func GetPortfolioMilestones(marketConfig MarketConfig, step PortfolioStep, limit int) ([]Report, error) {
viewBalances := make([]ViewBalances, 0)
reports := make([]Report, 0)
err := DB.
Model(&viewBalances).
Where("market_id = ?", marketConfig.Id).
Where("payload @> ?", fmt.Sprintf(`{"tag": "%s", "checkpoint": "%s"}`, step, "begin")).
OrderExpr("date DESC").Limit(limit).Select()
if err != nil {
return nil, err
}
for _, reportLine := range viewBalances {
reportLine.Payload.Report.Date = reportLine.Date
reports = append(reports, reportLine.Payload.Report)
}
return reports, nil
}
func GetLastPortfolioBegin(marketConfig MarketConfig) (*Report, error) {
reports, err := GetPortfolioMilestones(marketConfig, BUY_END, 1)
if err != nil {
return nil, nil
}
if len(reports) == 0 {
return nil, nil
}
return &reports[0], nil
}