--- /dev/null
+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
+}