instrument usecases & repository methods
This commit is contained in:
parent
39b89fc404
commit
16d38bb3cf
7 changed files with 100 additions and 13 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
package entities
|
package entities
|
||||||
|
|
||||||
type Pair struct {
|
type InstrumentID string
|
||||||
|
|
||||||
|
type Instrument struct {
|
||||||
|
ID InstrumentID
|
||||||
BaseCurrency string // base currency of the pair. e.g. BTC.
|
BaseCurrency string // base currency of the pair. e.g. BTC.
|
||||||
QuoteCurrency string // quote currency of the pair. e.g. USDT.
|
QuoteCurrency string // quote currency of the pair. e.g. USDT.
|
||||||
}
|
}
|
||||||
|
|
@ -3,8 +3,8 @@ package entities
|
||||||
import "github.com/shopspring/decimal"
|
import "github.com/shopspring/decimal"
|
||||||
|
|
||||||
type Price struct {
|
type Price struct {
|
||||||
Ask decimal.Decimal // limit seller / market buyer. ask > bid.
|
Ask decimal.Decimal // limit seller / market buyer. ask > bid.
|
||||||
Bid decimal.Decimal // limit buyer / market seller. bid < ask.
|
Bid decimal.Decimal // limit buyer / market seller. bid < ask.
|
||||||
Spread decimal.Decimal // delta between ask and bid.
|
Spread decimal.Decimal // delta between ask and bid.
|
||||||
Pair Pair // trading pair
|
Instrument Instrument // trading pair
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,17 +36,17 @@ func New(log *slog.Logger, cfg *config.Bybit) provider.Provider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bybit) symbol(pair *entities.Pair) string {
|
func (b *Bybit) symbol(pair *entities.Instrument) string {
|
||||||
return fmt.Sprintf("%s%s", pair.BaseCurrency, pair.QuoteCurrency)
|
return fmt.Sprintf("%s%s", pair.BaseCurrency, pair.QuoteCurrency)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Price returns the current price of the pair (base currency / quote currency).
|
// Price returns the current price of the pair (base currency / quote currency).
|
||||||
// e.g. BTC/USDT.
|
// e.g. BTC/USDT.
|
||||||
func (b *Bybit) Price(ctx context.Context, pair entities.Pair) (*entities.Price, error) {
|
func (b *Bybit) Price(ctx context.Context, instrument entities.Instrument) (*entities.Price, error) {
|
||||||
// build request
|
// build request
|
||||||
req := marketOrderbookReq{
|
req := marketOrderbookReq{
|
||||||
Category: categorySpot,
|
Category: categorySpot,
|
||||||
Symbol: b.symbol(&pair),
|
Symbol: b.symbol(&instrument),
|
||||||
}
|
}
|
||||||
var resp marketOrderbookResp
|
var resp marketOrderbookResp
|
||||||
// make request
|
// make request
|
||||||
|
|
@ -67,9 +67,9 @@ func (b *Bybit) Price(ctx context.Context, pair entities.Pair) (*entities.Price,
|
||||||
spread := askPrice.Sub(bidPrice)
|
spread := askPrice.Sub(bidPrice)
|
||||||
|
|
||||||
return &entities.Price{
|
return &entities.Price{
|
||||||
Ask: askPrice,
|
Ask: askPrice,
|
||||||
Bid: bidPrice,
|
Bid: bidPrice,
|
||||||
Spread: spread,
|
Spread: spread,
|
||||||
Pair: pair,
|
Instrument: instrument,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ import (
|
||||||
type Provider interface {
|
type Provider interface {
|
||||||
// Price returns the current price of the pair (base currency / quote currency).
|
// Price returns the current price of the pair (base currency / quote currency).
|
||||||
// e.g. BTC/USDT.
|
// e.g. BTC/USDT.
|
||||||
Price(ctx context.Context, pair entities.Pair) (*entities.Price, error)
|
Price(ctx context.Context, instrument entities.Instrument) (*entities.Price, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,54 @@
|
||||||
package postgresql
|
package postgresql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities"
|
||||||
|
)
|
||||||
|
|
||||||
|
const instrumentListQuery = `
|
||||||
|
select i.id, c_base.symbol, c_quote.symbol
|
||||||
|
from instrument i
|
||||||
|
join currency c_base on c_base.id = i.base_currency_id
|
||||||
|
join currency c_quote on c_quote.id = i.quoted_currency_id
|
||||||
|
order by i.id
|
||||||
|
offset $1 limit $2`
|
||||||
|
|
||||||
|
func (p *Postgresql) InstrumentList(ctx context.Context, offset, limit int) ([]entities.Instrument, error) {
|
||||||
|
rows, err := p.db.Query(ctx, instrumentListQuery, offset, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to exec instrumentListQuery: %w", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var instruments []entities.Instrument
|
||||||
|
for rows.Next() {
|
||||||
|
var inst entities.Instrument
|
||||||
|
if err := rows.Scan(&inst.ID, &inst.BaseCurrency, &inst.QuoteCurrency); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan instrument row: %w", err)
|
||||||
|
}
|
||||||
|
instruments = append(instruments, inst)
|
||||||
|
}
|
||||||
|
|
||||||
|
return instruments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const createInstrumentQuery = `
|
||||||
|
insert into instrument(base_currency_id, quoted_currency_id)
|
||||||
|
values (
|
||||||
|
(select id from currency where symbol = $1),
|
||||||
|
(select id from currency where symbol = $2)
|
||||||
|
)
|
||||||
|
returning id`
|
||||||
|
|
||||||
|
func (p *Postgresql) CreateInstrument(ctx context.Context, instrument *entities.Instrument) (entities.InstrumentID, error) {
|
||||||
|
var id entities.InstrumentID
|
||||||
|
|
||||||
|
err := p.db.QueryRow(ctx, createInstrumentQuery, instrument.BaseCurrency, instrument.QuoteCurrency).Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to exec createInstrumentQuery: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,7 @@ type Storage interface {
|
||||||
SaveUser(ctx context.Context, user *entities.User) (entities.UserID, error)
|
SaveUser(ctx context.Context, user *entities.User) (entities.UserID, error)
|
||||||
UserByID(ctx context.Context, id entities.UserID) (*entities.User, error)
|
UserByID(ctx context.Context, id entities.UserID) (*entities.User, error)
|
||||||
UserByTelegramID(ctx context.Context, tgID entities.TelegramID) (*entities.User, error)
|
UserByTelegramID(ctx context.Context, tgID entities.TelegramID) (*entities.User, error)
|
||||||
|
|
||||||
|
InstrumentList(ctx context.Context, offset, limit int) ([]entities.Instrument, error)
|
||||||
|
CreateInstrument(ctx context.Context, instrument *entities.Instrument) (entities.InstrumentID, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
internal/usecase/instrument.go
Normal file
28
internal/usecase/instrument.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (uc *Usecase) InstrumentList(ctx context.Context, offset, limit int) ([]entities.Instrument, error) {
|
||||||
|
instruments, err := uc.storage.InstrumentList(ctx, offset, limit)
|
||||||
|
if err != nil {
|
||||||
|
uc.log.Error("failed to list instruments", "offset", offset, "limit", limit, "err", err)
|
||||||
|
return nil, fmt.Errorf("failed to list instruments: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return instruments, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uc *Usecase) CreateInstrument(ctx context.Context, instrument *entities.Instrument) (entities.InstrumentID, error) {
|
||||||
|
id, err := uc.storage.CreateInstrument(ctx, instrument)
|
||||||
|
if err != nil {
|
||||||
|
uc.log.Error("failed to create instrument", "instrument", instrument, "err", err)
|
||||||
|
return "", fmt.Errorf("failed to create instrument: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue