aboutsummaryrefslogblamecommitdiff
path: root/db/report_lines.go
blob: 274be577e3d2e0c5d6ab666dd7e8cf5d1d7bc8c5 (plain) (tree)











































































































































                                                                                                         
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
}