Files
overnight-trading-bot/internal/tinvest/paper.go
T
2026-06-09 21:04:01 +00:00

110 lines
3.4 KiB
Go

package tinvest
import (
"context"
"time"
"github.com/shopspring/decimal"
"overnight-trading-bot/internal/domain"
)
type PaperGateway struct {
market Gateway
fake *FakeGateway
}
func NewPaperGateway(market Gateway) *PaperGateway {
return &PaperGateway{market: market, fake: NewFakeGateway()}
}
func (g *PaperGateway) Fake() *FakeGateway {
if g.fake == nil {
g.fake = NewFakeGateway()
}
return g.fake
}
func (g *PaperGateway) GetInstrument(ctx context.Context, ticker, classCode string) (domain.Instrument, error) {
if g.market != nil {
return g.market.GetInstrument(ctx, ticker, classCode)
}
return g.Fake().GetInstrument(ctx, ticker, classCode)
}
func (g *PaperGateway) GetCandles(ctx context.Context, instrumentUID string, interval string, from, to time.Time) ([]domain.Candle, error) {
if g.market != nil {
return g.market.GetCandles(ctx, instrumentUID, interval, from, to)
}
return g.Fake().GetCandles(ctx, instrumentUID, interval, from, to)
}
func (g *PaperGateway) GetTradingDays(ctx context.Context, exchange string, from, to time.Time) ([]time.Time, error) {
if g.market != nil {
return g.market.GetTradingDays(ctx, exchange, from, to)
}
return g.Fake().GetTradingDays(ctx, exchange, from, to)
}
func (g *PaperGateway) GetOrderBook(ctx context.Context, instrumentUID string, depth int32) (domain.OrderBook, error) {
if g.market != nil {
return g.market.GetOrderBook(ctx, instrumentUID, depth)
}
return g.Fake().GetOrderBook(ctx, instrumentUID, depth)
}
func (g *PaperGateway) GetTradingStatus(ctx context.Context, instrumentUID string) (domain.TradingStatus, error) {
if g.market != nil {
return g.market.GetTradingStatus(ctx, instrumentUID)
}
return g.Fake().GetTradingStatus(ctx, instrumentUID)
}
func (g *PaperGateway) PostLimitOrder(ctx context.Context, accountID, instrumentUID string, side domain.Side, lots int64, price decimal.Decimal, clientOrderID string) (domain.Order, error) {
return g.Fake().PostLimitOrder(ctx, accountID, instrumentUID, side, lots, price, clientOrderID)
}
func (g *PaperGateway) CancelOrder(ctx context.Context, accountID, orderID string) error {
return g.Fake().CancelOrder(ctx, accountID, orderID)
}
func (g *PaperGateway) GetOrderState(ctx context.Context, accountID, orderID string) (domain.Order, error) {
order, err := g.Fake().GetOrderState(ctx, accountID, orderID)
if err != nil {
return domain.Order{}, err
}
if !paperOrderCanFill(order) {
return order, nil
}
book, err := g.GetOrderBook(ctx, order.InstrumentUID, 20)
if err != nil {
return domain.Order{}, err
}
return g.Fake().SimulateOrderBookFill(orderID, book)
}
func (g *PaperGateway) GetActiveOrders(ctx context.Context, accountID string) ([]domain.Order, error) {
return g.Fake().GetActiveOrders(ctx, accountID)
}
func (g *PaperGateway) GetPortfolio(ctx context.Context, accountID string) (domain.Portfolio, error) {
return g.Fake().GetPortfolio(ctx, accountID)
}
func (g *PaperGateway) GetOperations(ctx context.Context, accountID string, from, to time.Time) ([]domain.Operation, error) {
return g.Fake().GetOperations(ctx, accountID, from, to)
}
func (g *PaperGateway) GetServerTime(ctx context.Context) (time.Time, error) {
if g.market != nil {
return g.market.GetServerTime(ctx)
}
return g.Fake().GetServerTime(ctx)
}
func paperOrderCanFill(order domain.Order) bool {
return order.Status == domain.OrderStatusSent ||
order.Status == domain.OrderStatusPartiallyFilled ||
order.Status == domain.OrderStatusNew
}