-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* skeleton * Add Redis repository for storing order book (#5) Redis repo, first CRUD operations * after merge * fix proto * before merge * Co-authored-by: Luke Rogerson <[email protected]> * amountOut both sides redis * gitignore * store orders * lh side * amountOut re-factor Co-authored-by: Luke Rogerson <[email protected]> * tests for amount out * fix iter state * lint * remove cmd lh * rename * rename lh * add ctx * ctx in tests * add logs better error --------- Co-authored-by: Luke Rogerson <[email protected]>
- Loading branch information
1 parent
9976946
commit 79f2376
Showing
16 changed files
with
451 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package redisrepo | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/google/uuid" | ||
"github.com/orbs-network/order-book/models" | ||
"github.com/orbs-network/order-book/utils/logger" | ||
"github.com/orbs-network/order-book/utils/logger/logctx" | ||
) | ||
|
||
// //////////////////////////////////////////////// | ||
type OrderIter struct { | ||
index int | ||
ids []string | ||
redis *redisRepository | ||
} | ||
|
||
func (i *OrderIter) Next(ctx context.Context) *models.Order { | ||
if i.index >= len(i.ids) { | ||
logctx.Error(ctx, "Error iterator reached last element") | ||
return nil | ||
} | ||
|
||
// increment index | ||
i.index = i.index + 1 | ||
// get order | ||
orderId, err := uuid.Parse(i.ids[i.index]) | ||
if err != nil { | ||
logctx.Error(ctx, "Error parsing bid order id", logger.Error(err)) | ||
return nil | ||
} | ||
order, err := i.redis.FindOrderById(ctx, orderId) | ||
if err != nil { | ||
logctx.Error(ctx, "Error fetching order", logger.Error(err)) | ||
return nil | ||
} | ||
|
||
return order | ||
} | ||
|
||
func (i *OrderIter) HasNext() bool { | ||
return i.index < (len(i.ids) - 1) | ||
} | ||
|
||
// //////////////////////////////////////////////// | ||
func (r *redisRepository) GetMinAsk(ctx context.Context, symbol models.Symbol) models.OrderIter { | ||
key := CreateSellSidePricesKey(symbol) | ||
|
||
// Min ask price for selling | ||
orderIDs, err := r.client.ZRange(ctx, key, 0, -1).Result() | ||
if err != nil { | ||
logctx.Error(ctx, "Error fetching asks", logger.Error(err)) | ||
} | ||
// create order iter | ||
return &OrderIter{ | ||
index: -1, | ||
ids: orderIDs, | ||
redis: r, | ||
} | ||
|
||
} | ||
|
||
// //////////////////////////////////////////////// | ||
func (r *redisRepository) GetMaxBid(ctx context.Context, symbol models.Symbol) models.OrderIter { | ||
key := CreateBuySidePricesKey(symbol) | ||
|
||
// Min ask price for selling | ||
orderIDs, err := r.client.ZRevRange(ctx, key, 0, -1).Result() | ||
|
||
if err != nil { | ||
logctx.Error(ctx, "Error fetching bids", logger.Error(err)) | ||
} | ||
// create order iter | ||
return &OrderIter{ | ||
index: -1, | ||
ids: orderIDs, | ||
redis: r, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package redisrepo | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/orbs-network/order-book/models" | ||
) | ||
|
||
func (r *redisRepository) StoreAuction(ctx context.Context, auctionID string, fillOrders []models.FilledOrder) error { | ||
// auctionId:<ID>: [{orderID: <ID>, filledAmount: <amount>}, ...}] | ||
panic("not implemented") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package mocks | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/orbs-network/order-book/models" | ||
) | ||
|
||
type OrderIter struct { | ||
Error error | ||
Order *models.Order | ||
ShouldHaveNext bool | ||
} | ||
|
||
func (o *OrderIter) HasNext() bool { | ||
return o.ShouldHaveNext | ||
} | ||
|
||
func (o *OrderIter) Next(ctx context.Context) *models.Order { | ||
return o.Order | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package models | ||
|
||
import ( | ||
"github.com/google/uuid" | ||
"github.com/shopspring/decimal" | ||
) | ||
|
||
type AmountOut struct { | ||
AmountOut decimal.Decimal | ||
FillOrders []FilledOrder | ||
} | ||
|
||
type FilledOrder struct { | ||
OrderId uuid.UUID | ||
Amount decimal.Decimal | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package models | ||
|
||
import "context" | ||
|
||
type OrderIter interface { | ||
HasNext() bool | ||
Next(ctx context.Context) *Order | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package service | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/orbs-network/order-book/models" | ||
"github.com/orbs-network/order-book/utils/logger" | ||
"github.com/orbs-network/order-book/utils/logger/logctx" | ||
"github.com/shopspring/decimal" | ||
) | ||
|
||
// orderID->amount bought or sold in A token always | ||
|
||
func (s *Service) GetAmountOut(ctx context.Context, auctionId string, symbol models.Symbol, side models.Side, amountIn decimal.Decimal) (models.AmountOut, error) { | ||
|
||
var it models.OrderIter | ||
var res models.AmountOut | ||
var err error | ||
if side == models.BUY { | ||
it = s.orderBookStore.GetMinAsk(ctx, symbol) | ||
res, err = getAmountOutInAToken(ctx, it, amountIn) | ||
|
||
} else { // SELL | ||
it = s.orderBookStore.GetMaxBid(ctx, symbol) | ||
res, err = getAmountOutInBToken(ctx, it, amountIn) | ||
} | ||
if err != nil { | ||
logctx.Error(ctx, "getAmountOutIn failed", logger.Error(err)) | ||
return models.AmountOut{}, err | ||
} | ||
err = s.orderBookStore.StoreAuction(ctx, auctionId, res.FillOrders) | ||
if err != nil { | ||
logctx.Error(ctx, "StoreAuction failed", logger.Error(err)) | ||
return models.AmountOut{}, err | ||
} | ||
return res, nil | ||
} | ||
|
||
// PAIR/SYMBOL A-B (ETH-USDC) | ||
// amount in B token (USD) | ||
// amount out A token (ETH) | ||
func getAmountOutInAToken(ctx context.Context, it models.OrderIter, amountInB decimal.Decimal) (models.AmountOut, error) { | ||
amountOutA := decimal.NewFromInt(0) | ||
var fillOrders []models.FilledOrder | ||
var order *models.Order | ||
for it.HasNext() && amountInB.IsPositive() { | ||
order = it.Next(ctx) | ||
// max Spend in B token for this order | ||
orderSizeB := order.Price.Mul(order.Size) | ||
// spend the min of orderSizeB/amountInB | ||
spendB := decimal.Min(orderSizeB, amountInB) | ||
|
||
// Gain | ||
gainA := spendB.Div(order.Price) | ||
|
||
// sub-add | ||
amountInB = amountInB.Sub(spendB) | ||
logctx.Info(ctx, "StoreAuction failed") | ||
amountOutA = amountOutA.Add(gainA) | ||
|
||
// res | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder gainA: %s", gainA.String())) | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder spendB: %s", spendB.String())) | ||
fillOrders = append(fillOrders, models.FilledOrder{OrderId: order.Id, Amount: gainA}) | ||
} | ||
// not all is Spent - error | ||
if amountInB.IsPositive() { | ||
logctx.Warn(ctx, models.ErrInsufficientLiquity.Error()) | ||
return models.AmountOut{}, models.ErrInsufficientLiquity | ||
} | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder amountOutA: %s", amountOutA.String())) | ||
return models.AmountOut{AmountOut: amountOutA, FillOrders: fillOrders}, nil | ||
} | ||
|
||
// PAIR/SYMBOL A-B (ETH-USDC) | ||
// amount in A token (ETH) | ||
// amount out B token (USD) | ||
func getAmountOutInBToken(ctx context.Context, it models.OrderIter, amountInA decimal.Decimal) (models.AmountOut, error) { | ||
amountOutB := decimal.NewFromInt(0) | ||
var order *models.Order | ||
var fillOrders []models.FilledOrder | ||
for it.HasNext() && amountInA.IsPositive() { | ||
order = it.Next(ctx) | ||
|
||
// Spend | ||
spendA := decimal.Min(order.Size, amountInA) | ||
fmt.Println("sizeA ", spendA.String()) | ||
|
||
// Gain | ||
gainB := order.Price.Mul(spendA) | ||
fmt.Println("gainB ", gainB.String()) | ||
|
||
// sub-add | ||
amountInA = amountInA.Sub(spendA) | ||
amountOutB = amountOutB.Add(gainB) | ||
|
||
// res | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder spendA: %s", spendA.String())) | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder gainB: %s", gainB.String())) | ||
fillOrders = append(fillOrders, models.FilledOrder{OrderId: order.Id, Amount: spendA}) | ||
} | ||
if amountInA.IsPositive() { | ||
logctx.Warn(ctx, models.ErrInsufficientLiquity.Error()) | ||
return models.AmountOut{}, models.ErrInsufficientLiquity | ||
} | ||
logctx.Info(ctx, fmt.Sprintf("append FilledOrder amountOutB: %s", amountOutB.String())) | ||
return models.AmountOut{AmountOut: amountOutB, FillOrders: fillOrders}, nil | ||
} |
Oops, something went wrong.