add position table and service

This commit is contained in:
c9s 2022-03-10 19:00:02 +08:00
parent f0d500bbaa
commit ac675d0099
5 changed files with 155 additions and 25 deletions

View File

@ -6,7 +6,7 @@ CREATE TABLE `positions`
`strategy` VARCHAR(32) NOT NULL,
`strategy_instance_id` VARCHAR(64) NOT NULL,
`symbol` VARCHAR(20) NOT NULL,
`symbol` VARCHAR(20) NOT NULL,
`quote_currency` VARCHAR(10) NOT NULL,
`base_currency` VARCHAR(10) NOT NULL,
@ -14,6 +14,7 @@ CREATE TABLE `positions`
`average_cost` DECIMAL(16, 8) UNSIGNED NOT NULL,
`base` DECIMAL(16, 8) NOT NULL,
`quote` DECIMAL(16, 8) NOT NULL,
`profit` DECIMAL(16, 8) NULL,
`trade_id` BIGINT UNSIGNED NOT NULL,
`traded_at` DATETIME(3) NOT NULL,

View File

@ -3,20 +3,21 @@ CREATE TABLE `positions`
(
`gid` INTEGER PRIMARY KEY AUTOINCREMENT,
`strategy` VARCHAR(32) NOT NULL,
`strategy_instance_id` VARCHAR(64) NOT NULL,
`strategy` VARCHAR(32) NOT NULL,
`strategy_instance_id` VARCHAR(64) NOT NULL,
`symbol` VARCHAR(20) NOT NULL,
`quote_currency` VARCHAR(10) NOT NULL,
`base_currency` VARCHAR(10) NOT NULL,
`symbol` VARCHAR(20) NOT NULL,
`quote_currency` VARCHAR(10) NOT NULL,
`base_currency` VARCHAR(10) NOT NULL,
-- average_cost is the position average cost
`average_cost` DECIMAL(16, 8) NOT NULL,
`base` DECIMAL(16, 8) NOT NULL,
`quote` DECIMAL(16, 8) NOT NULL,
`average_cost` DECIMAL(16, 8) NOT NULL,
`base` DECIMAL(16, 8) NOT NULL,
`quote` DECIMAL(16, 8) NOT NULL,
`profit` DECIMAL(16, 8) NULL,
`trade_id` BIGINT NOT NULL,
`traded_at` DATETIME(3) NOT NULL
`trade_id` BIGINT NOT NULL,
`traded_at` DATETIME(3) NOT NULL
);
-- +down

92
pkg/service/position.go Normal file
View File

@ -0,0 +1,92 @@
package service
import (
"context"
"github.com/jmoiron/sqlx"
"github.com/pkg/errors"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
type PositionService struct {
DB *sqlx.DB
}
func NewPositionService(db *sqlx.DB) *PositionService {
return &PositionService{db}
}
func (s *PositionService) Load(ctx context.Context, id int64) (*types.Position, error) {
var pos types.Position
rows, err := s.DB.NamedQuery("SELECT * FROM positions WHERE id = :id", map[string]interface{}{
"id": id,
})
if err != nil {
return nil, err
}
defer rows.Close()
if rows.Next() {
err = rows.StructScan(&pos)
return &pos, err
}
return nil, errors.Wrapf(ErrTradeNotFound, "position id:%d not found", id)
}
func (s *PositionService) scanRows(rows *sqlx.Rows) (positions []types.Position, err error) {
for rows.Next() {
var p types.Position
if err := rows.StructScan(&p); err != nil {
return positions, err
}
positions = append(positions, p)
}
return positions, rows.Err()
}
func (s *PositionService) Insert(position *types.Position, trade types.Trade, profit fixedpoint.Value) error {
_, err := s.DB.NamedExec(`
INSERT INTO positions (
strategy,
strategy_instance_id,
symbol,
quote_currency,
base_currency,
average_cost,
base,
quote,
profit,
trade_id,
traded_at
) VALUES (
:strategy,
:strategy_instance_id,
:symbol,
:quote_currency,
:base_currency,
:average_cost,
:base,
:quote,
:profit,
:trade_id,
:traded_at
)`,
map[string]interface{} {
"strategy": "",
"strategy_instance_id": "",
"symbol": position.Symbol,
"quote_currency": position.QuoteCurrency,
"base_currency": position.BaseCurrency,
"average_cost": position.AverageCost,
"base": position.Base,
"quote": position.Quote,
})
return err
}

View File

@ -0,0 +1,34 @@
package service
import (
"testing"
"time"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
)
func TestPositionService(t *testing.T) {
db, err := prepareDB(t)
if err != nil {
t.Fatal(err)
}
defer db.Close()
xdb := sqlx.NewDb(db.DB, "sqlite3")
service := &PositionService{DB: xdb}
err = service.Insert(&types.Position{
Symbol: "BTCUSDT",
BaseCurrency: "BTC",
QuoteCurrency: "USDT",
AverageCost: fixedpoint.NewFromFloat(44000),
ChangedAt: time.Now(),
}, types.Trade{}, fixedpoint.NewFromFloat(10.9))
assert.NoError(t, err)
}

View File

@ -50,6 +50,8 @@ type Position struct {
// TotalFee stores the fee currency -> total fee quantity
TotalFee map[string]fixedpoint.Value `json:"totalFee"`
ChangedAt time.Time `json:"changedAt,omitempty"`
sync.Mutex
}
@ -66,22 +68,22 @@ func (p *Position) NewProfit(trade Trade, profit, netProfit fixedpoint.Value) Pr
ProfitMargin: profit.Div(trade.QuoteQuantity),
NetProfitMargin: netProfit.Div(trade.QuoteQuantity),
// trade related fields
TradeID: trade.ID,
Side: trade.Side,
IsBuyer: trade.IsBuyer,
IsMaker: trade.IsMaker,
Price: trade.Price,
Quantity: trade.Quantity,
QuoteQuantity: trade.QuoteQuantity,
TradeID: trade.ID,
Side: trade.Side,
IsBuyer: trade.IsBuyer,
IsMaker: trade.IsMaker,
Price: trade.Price,
Quantity: trade.Quantity,
QuoteQuantity: trade.QuoteQuantity,
// FeeInUSD: 0,
Fee: trade.Fee,
FeeCurrency: trade.FeeCurrency,
Fee: trade.Fee,
FeeCurrency: trade.FeeCurrency,
Exchange: trade.Exchange,
IsMargin: trade.IsMargin,
IsFutures: trade.IsFutures,
IsIsolated: trade.IsIsolated,
TradedAt: trade.Time.Time(),
Exchange: trade.Exchange,
IsMargin: trade.IsMargin,
IsFutures: trade.IsFutures,
IsIsolated: trade.IsIsolated,
TradedAt: trade.Time.Time(),
}
}