59 lines
1.7 KiB
Go
59 lines
1.7 KiB
Go
package execution
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
|
|
"overnight-trading-bot/internal/domain"
|
|
"overnight-trading-bot/internal/money"
|
|
)
|
|
|
|
var nonIDChar = regexp.MustCompile(`[^A-Za-z0-9_-]+`)
|
|
|
|
func LimitBuyPrice(bestBid, bestAsk, tick decimal.Decimal, improveTicks int) (decimal.Decimal, error) {
|
|
if improveTicks < 0 {
|
|
improveTicks = 0
|
|
}
|
|
if !tick.IsPositive() {
|
|
return decimal.Zero, money.ErrInvalidTick
|
|
}
|
|
candidate := bestBid.Add(tick.Mul(decimal.NewFromInt(int64(improveTicks))))
|
|
upper := bestAsk.Sub(tick)
|
|
if candidate.LessThanOrEqual(upper) {
|
|
return money.RoundToTick(candidate, tick, money.RoundFloor)
|
|
}
|
|
return money.RoundToTick(bestBid, tick, money.RoundFloor)
|
|
}
|
|
|
|
func LimitSellPrice(bestBid, bestAsk, tick decimal.Decimal, improveTicks int) (decimal.Decimal, error) {
|
|
if improveTicks < 0 {
|
|
improveTicks = 0
|
|
}
|
|
if !tick.IsPositive() {
|
|
return decimal.Zero, money.ErrInvalidTick
|
|
}
|
|
candidate := bestAsk.Sub(tick.Mul(decimal.NewFromInt(int64(improveTicks))))
|
|
lower := bestBid.Add(tick)
|
|
if candidate.GreaterThanOrEqual(lower) {
|
|
return money.RoundToTick(candidate, tick, money.RoundCeil)
|
|
}
|
|
return money.RoundToTick(bestAsk, tick, money.RoundCeil)
|
|
}
|
|
|
|
func ClientOrderID(tradeDate time.Time, instrumentUID string, side domain.Side, attempt int) string {
|
|
base := fmt.Sprintf("%s|%s|%s|%d", tradeDate.Format("20060102"), instrumentUID, side, attempt)
|
|
sum := sha256.Sum256([]byte(base))
|
|
suffix := hex.EncodeToString(sum[:])[:8]
|
|
cleanUID := nonIDChar.ReplaceAllString(instrumentUID, "_")
|
|
if len(cleanUID) > 24 {
|
|
cleanUID = cleanUID[:24]
|
|
}
|
|
return strings.ToLower(fmt.Sprintf("otb-%s-%s-%s-%02d-%s", tradeDate.Format("20060102"), cleanUID, side, attempt, suffix))
|
|
}
|