Skip to content

Commit

Permalink
Merge pull request #163 from vegaprotocol/141-refactor-liqbot-iterati…
Browse files Browse the repository at this point in the history
…on-3

141 refactor liqbot iteration 3
  • Loading branch information
zale144 authored Oct 10, 2022
2 parents be761ce + b44702f commit 4bec3c9
Show file tree
Hide file tree
Showing 52 changed files with 3,574 additions and 2,875 deletions.
16 changes: 7 additions & 9 deletions .github/workflows/continous-delivery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ jobs:
uses: docker/login-action@v2
if: ${{ !github.event.repository.private }}
with:
# registry: registry.hub.docker.com
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

Expand All @@ -48,13 +47,13 @@ jobs:
tags: ghcr.io/${{ github.repository }}:latest,ghcr.io/${{ github.repository }}:${{ github.sha }},ghcr.io/${{ github.repository }}:${{ github.ref_name }}

# public registry builds
- name: Build and push
uses: docker/build-push-action@v3
if: ${{!github.event.repository.private}}
with:
context: .
push: true
tags: ${{ github.repository }}:latest,${{ github.repository }}:${{ github.sha }},${{ github.repository }}:${{ github.ref_name }}
#- name: Build and push
# uses: docker/build-push-action@v3
# if: ${{!github.event.repository.private}}
# with:
# context: .
# push: true
# tags: ${{ github.repository }}:latest,${{ github.repository }}:${{ github.sha }},${{ github.repository }}:${{ github.ref_name }}


release-binary:
Expand Down Expand Up @@ -93,4 +92,3 @@ jobs:
files: build/*.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6 changes: 3 additions & 3 deletions .github/workflows/continous-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ name: "Continous Deployment Workflow"
- v*

jobs:
integration:
uses: ./.github/workflows/continous-integration.yml
#integration:
# uses: ./.github/workflows/continous-integration.yml
delivery:
needs: integration
#needs: integration
uses: ./.github/workflows/continous-delivery.yml
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/continous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: "Continous Integration Workflow"
"on":
workflow_call:
pull_request:

push:
branches:

Expand All @@ -19,7 +19,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '1.19.0'
go-version: 1.19

- name: build
run: make build
Expand All @@ -33,6 +33,5 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.45
version: v1.49.0
args: --config .golangci.toml

4 changes: 4 additions & 0 deletions .golangci.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ linters = ["forbidigo"]
path = "cmd/"
linters = ["forbidigo"]

[[issues.exclude-rules]]
path = "./"
linters = ["nosnakecase","exhaustruct"]

[[issues.exclude-rules]]
path = "flags.go"
linters = ["forbidigo"]
Expand Down
18 changes: 18 additions & 0 deletions account/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package account

import (
"context"
"time"

"code.vegaprotocol.io/liqbot/data"
"code.vegaprotocol.io/liqbot/types"
"code.vegaprotocol.io/liqbot/types/num"
v1 "code.vegaprotocol.io/vega/protos/vega/events/v1"
)

type accountStream interface {
Init(pubKey string, pauseCh chan types.PauseSignal)
GetBalances(assetID string) (data.BalanceStore, error)
WaitForStakeLinking(pubKey string) error
WaitForTopUpToFinalise(ctx context.Context, evtType v1.BusEventType, walletPubKey, assetID string, amount *num.Uint, timeout time.Duration) error
}
163 changes: 163 additions & 0 deletions account/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package account

import (
"context"
"fmt"

log "github.com/sirupsen/logrus"

"code.vegaprotocol.io/liqbot/data"
"code.vegaprotocol.io/liqbot/types"
"code.vegaprotocol.io/liqbot/types/num"
)

type Service struct {
name string
pubKey string
assetID string
stores map[string]data.BalanceStore
accountStream accountStream
coinProvider types.CoinProvider
log *log.Entry
}

func NewAccountService(name, assetID string, accountStream accountStream, coinProvider types.CoinProvider) *Service {
return &Service{
name: name,
assetID: assetID,
accountStream: accountStream,
coinProvider: coinProvider,
log: log.WithField("component", "AccountService"),
}
}

func (a *Service) Init(pubKey string, pauseCh chan types.PauseSignal) {
a.stores = make(map[string]data.BalanceStore)
a.pubKey = pubKey
a.accountStream.Init(pubKey, pauseCh)
}

func (a *Service) EnsureBalance(ctx context.Context, assetID string, targetAmount *num.Uint, from string) error {
store, err := a.getStore(assetID)
if err != nil {
return err
}

balanceTotal := store.Balance().Total() // TODO: should it be total balance?

a.log.WithFields(
log.Fields{
"name": a.name,
"partyId": a.pubKey,
"balanceTotal": balanceTotal.String(),
}).Debugf("%s: Total account balance", from)

if balanceTotal.GTE(targetAmount) {
return nil
}

a.log.WithFields(
log.Fields{
"name": a.name,
"partyId": a.pubKey,
"balanceTotal": balanceTotal.String(),
"targetAmount": targetAmount.String(),
}).Debugf("%s: Account balance is less than target amount, depositing...", from)

evtType, err := a.coinProvider.TopUpAsync(ctx, a.name, a.pubKey, assetID, targetAmount)
if err != nil {
return fmt.Errorf("failed to top up: %w", err)
}

a.log.WithFields(log.Fields{"name": a.name}).Debugf("%s: Waiting for top-up...", from)

if err = a.accountStream.WaitForTopUpToFinalise(ctx, evtType, a.pubKey, assetID, targetAmount, 0); err != nil {
return fmt.Errorf("failed to finalise deposit: %w", err)
}

a.log.WithFields(log.Fields{"name": a.name}).Debugf("%s: Top-up complete", from)

return nil
}

func (a *Service) EnsureStake(ctx context.Context, receiverName, receiverPubKey, assetID string, targetAmount *num.Uint, from string) error {
if receiverPubKey == "" {
return fmt.Errorf("receiver public key is empty")
}

store, err := a.getStore(assetID)
if err != nil {
return err
}

// TODO: how the hell do we check for stake balance??
balanceTotal := store.Balance().Total()

a.log.WithFields(
log.Fields{
"name": a.name,
"partyId": a.pubKey,
"balanceTotal": balanceTotal.String(),
}).Debugf("%s: Total account stake balance", from)

if balanceTotal.GT(targetAmount) {
return nil
}

a.log.WithFields(
log.Fields{
"name": a.name,
"receiverName": receiverName,
"receiverPubKey": receiverPubKey,
"partyId": a.pubKey,
"balanceTotal": balanceTotal.String(),
"targetAmount": targetAmount.String(),
}).Debugf("%s: Account Stake balance is less than target amount, staking...", from)

if err = a.coinProvider.StakeAsync(ctx, receiverPubKey, assetID, targetAmount); err != nil {
return fmt.Errorf("failed to stake: %w", err)
}

a.log.WithFields(log.Fields{
"name": a.name,
"receiverName": receiverName,
"receiverPubKey": receiverPubKey,
"partyId": a.pubKey,
"targetAmount": targetAmount.String(),
}).Debugf("%s: Waiting for staking...", from)

if err = a.accountStream.WaitForStakeLinking(receiverPubKey); err != nil {
return fmt.Errorf("failed to finalise stake: %w", err)
}

return nil
}

func (a *Service) StakeAsync(ctx context.Context, receiverPubKey, assetID string, amount *num.Uint) error {
return a.coinProvider.StakeAsync(ctx, receiverPubKey, assetID, amount)
}

func (a *Service) Balance() types.Balance {
store, err := a.getStore(a.assetID)
if err != nil {
a.log.WithError(err).Error("failed to get balance store")
return types.Balance{}
}
return store.Balance()
}

func (a *Service) getStore(assetID string) (data.BalanceStore, error) {
var err error

store, ok := a.stores[assetID]
if !ok {
store, err = a.accountStream.GetBalances(assetID)
if err != nil {
return nil, fmt.Errorf("failed to initialise balances for '%s': %w", assetID, err)
}

a.stores[assetID] = store
}

return store, nil
}
70 changes: 50 additions & 20 deletions bot/bot.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,67 @@
package bot

import (
"context"
"errors"
"fmt"

ppconfig "code.vegaprotocol.io/priceproxy/config"
ppservice "code.vegaprotocol.io/priceproxy/service"
log "github.com/sirupsen/logrus"

"code.vegaprotocol.io/liqbot/account"
"code.vegaprotocol.io/liqbot/bot/normal"
"code.vegaprotocol.io/liqbot/config"
"code.vegaprotocol.io/liqbot/data"
"code.vegaprotocol.io/liqbot/market"
"code.vegaprotocol.io/liqbot/node"
"code.vegaprotocol.io/liqbot/types"
"code.vegaprotocol.io/liqbot/wallet"
)

// Bot is the generic bot interface.
//
//go:generate go run github.com/golang/mock/mockgen -destination mocks/bot_mock.go -package mocks code.vegaprotocol.io/liqbot/bot Bot
type Bot interface {
Start() error
Stop()
GetTraderDetails() string
}

// PricingEngine is the source of price information from the price proxy.
//
//go:generate go run github.com/golang/mock/mockgen -destination mocks/pricingengine_mock.go -package mocks code.vegaprotocol.io/liqbot/bot PricingEngine
type PricingEngine interface {
GetPrice(pricecfg ppconfig.PriceConfig) (pi ppservice.PriceResponse, err error)
}

// New returns a new Bot instance.
func New(botConf config.BotConfig, locations []string, seedConf *config.TokenConfig, pe PricingEngine, wc normal.WalletClient) (Bot, error) {
func New(
botConf config.BotConfig,
conf config.Config,
pricing types.PricingEngine,
whale types.CoinProvider,
) (types.Bot, error) {
switch botConf.Strategy {
case config.BotStrategyNormal:
return normal.New(botConf, locations, seedConf, pe, wc), nil
bot, err := newNormalBot(botConf, conf, pricing, whale)
if err != nil {
return nil, fmt.Errorf("failed to create normal bot '%s': %w", botConf.Name, err)
}
return bot, nil
default:
return nil, errors.New("unrecognised bot strategy")
}
}

func newNormalBot(
botConf config.BotConfig,
conf config.Config,
pricing types.PricingEngine,
whale types.CoinProvider,
) (types.Bot, error) {
dataNode := node.NewDataNode(
conf.Locations,
conf.CallTimeoutMills,
)

log.Debug("Attempting to connect to Vega gRPC node...")
dataNode.MustDialConnection(context.Background()) // blocking

botWallet := wallet.NewClient(conf.Wallet.URL)
accountStream := data.NewAccountStream(botConf.Name, dataNode)
accountService := account.NewAccountService(botConf.Name, botConf.SettlementAssetID, accountStream, whale)

marketStream := data.NewMarketStream(botConf.Name, dataNode)
marketService := market.NewService(botConf.Name, marketStream, dataNode, botWallet, pricing, accountService, botConf, conf.VegaAssetID)

return normal.New(
botConf,
conf.VegaAssetID,
botWallet,
accountService,
marketService,
), nil
}
6 changes: 3 additions & 3 deletions bot/normal/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func discreteThreeLevelProbabilities(V []float64, muHat float64, sigmaHat float6
// generatePriceUsingDiscreteThreeLevel is a method for calculating price levels
// input is a float price (so divide uint64 price by 10^{num of decimals})
// it returns a float price which you want to multiply by 10^{num of decimals} and then round.
func generatePriceUsingDiscreteThreeLevel(m0, delta, sigma, tgtTimeHorizonYrFrac, n float64) (price float64, err error) {
func generatePriceUsingDiscreteThreeLevel(m0, delta, sigma, tgtTimeHorizonYrFrac, n float64) (float64, error) {
muHat := -0.5 * sigma * sigma * tgtTimeHorizonYrFrac
sigmaHat := math.Sqrt(n*tgtTimeHorizonYrFrac) * sigma
v := make([]float64, 3)
Expand All @@ -117,9 +117,9 @@ func generatePriceUsingDiscreteThreeLevel(m0, delta, sigma, tgtTimeHorizonYrFrac
shockX := v[randomChoice(probabilities)]
y := math.Exp(shockX / n)

price = m0 * y
price := m0 * y

return price, err
return price, nil
}

func randomChoice(probabilities []float64) uint64 {
Expand Down
Loading

0 comments on commit 4bec3c9

Please sign in to comment.