backtester: Futures handling & FTX Cash and Carry example strategy (#930)

* implements futures functions and GRPC functions on new branch

* lint and test fixes

* Fix uneven split pnl. Adds collateral weight test. docs. New clear func

* Test protection if someone has zero collateral

* Uses string instead of double for accuracy

* Fixes old code panic

* context, match, docs

* Addresses Shazniterinos, var names, expanded tests

* Returns subaccount name, provides USD values when offlinecalc

* Fixes oopsie

* Fixes cool bug which allowed made up subaccount results

* Subaccount override on FTX, subaccount results for collateral

* Strenghten collateral account info checks. Improve FTX test

* English is my first language

* Fixes oopsies

* Adds some conceptual futures order details to track PNL

* Initial design of future order processing in the backtester

* Introduces futures concept for collateral and spot/futures config diffs

* Fixes most tests

* Simple designs for collateral funding pair concept

* Expands interface use so much it hurts

* Implements more collateral interfaces

* Adds liquidation, adds strategy, struggles with Binance

* Attempts at getting FTX to work

* Adds calculatePNL as a wrapper function and adds an `IsFutures` asset check

* Successfully loads backtester with collateral currency

* Fails to really get much going for supporting futures

* Merges master changes

* Fleshes out how FTX processes collateral

* Further FTX collateral workings

* hooks up more ftx collateral and pnl calculations

* more funcs to flesh out handling

* Adds more links, just can't fit the pieces together :(

* Greatly expands futures order processing

* Fleshes out position tracker to also handle asset and exchange +testing

* RM linkedOrderID. rn positioncontroller, unexport

* Successfully tracks futures order positions

* Fails to calculate PNL

* Calculates pnl from orders accurately with exception to flipping orders

* Calculates PNL from orders

* Adds another controller layer to make it ez from orderstore

* Backtester now compiles. Adds test coverage

* labels things add scaling collateral test

* Calculates pnl in line with fees

* Mostly accurate PNL, with exception to appending with diff prices

* Adds locks, adds rpc function

* grpc implementations

* Gracefully handles rpc function

* beautiful tests!

* rejiggles tests to polish

* Finishes FTX testing, adds comments

* Exposes collateral calculations to rpc

* Adds commands and testing for rpcserver.go functions

* Increase testing and fix up backtester code

* Returns cool changes to original branch

* end of day fixes

* Fixing some tests

* Fixing tests 🎉

* Fixes all the tests

* Splits the backtester setup and running into different files

* Merge, minor fixes

* Messing with some strategy updates

* Failed understanding at collateral usage

* Begins the creation of cash and carry strategy

* Adds underlying pair, adds filldependentevent for futures

* Completes fill prerequsite event implementation. Can't short though

* Some bug fixes

* investigating funds

* CAN NOW CREATE A SHORT ORDER

* Minor change in short size

* Fixes for unrealised PNL & collateral rendering

* Fixes lint and tests

* Adds some verbosity

* Updates to pnl calc

* Tracks pnl for short orders, minor update to strategy

* Close and open event based on conditions

* Adds pnl data for currency statistics

* Working through PNL calculation automatically. Now panics

* Adds tracking, is blocked from design

* Work to flesh out closing a position

* vain attempts at tracking zeroing out bugs

* woww, super fun new subloggers 🎉

* Begins attempt at automatically handling contracts and collateral based on direction

* Merge master + fixes

* Investigating issues with pnl and holdings

* Minor pnl fixes

* Fixes future position sizing, needs contract sizing

* Can render pnl results, focussing on funding statistics

* tracking candles for futures, but why not btc

* Improves funding statistics

* Colours and stats

* Fixes collateral and snapshot bugs

* Completes test

* Fixes totals bug

* Fix double buy, expand stats, fixes usd totals, introduce interface

* Begins report formatting and calculations

* Appends pnl to receiving curr. Fixes map[time]. accurate USD

* Improves report output rendering

* PNL stats in report. New tests for futures

* Fixes existing tests before adding new coverage

* Test coverage

* Completes portfolio coverage

* Increase coverage exchange, portfolio. fix size bug. NEW CHART

* WHAT IS GOING ON WITH PNL

* Fixes PNL calculation. Adds ability to skip om futures tracking

* minor commit before merge

* Adds basic liquidation to backtester

* Changes liquidation to order based

* Liquidationnnnnn

* Further fleshes out liquidations

* Completes liquidations in a honorable manner. Adds AppendReasonf

* Beginnings of spot futures gap chart. Needs to link currencies to render difference

* Removes fake liquidation. Adds cool new chart

* Fixes somet tests,allows for zero fee value v nil distinction,New tests

* Some annoying test fixes that took too long

* portfolio coverage

* holding coverage, privatisation funding

* Testwork

* boring tests

* engine coverage

* More backtesting coverage

* Funding, strategy, report test coverage

* Completes coverage of report package

* Documentation, fixes some assumptions on asset errors

* Changes before master merge

* Lint and Tests

* defaults to non-coloured rendering

* Chart rendering

* Fixes surprise non-local-lints

* Niterinos to the extremeos

* Fixes merge problems

* The linter splintered across the glinting plinths

* Many nits addressed. Now sells spot position on final candle

* Adds forgotten coverage

* Adds ability to size futures contracts to match spot positions.

* fixes order sell sizing

* Adds tests to sizing. Fixes charting issue

* clint splintered the linters with flint

* Improves stats, stat rendering

* minifix

* Fixes tests and fee bug

* Merge fixeroos

* Microfixes

* Updates orderPNL on first Correctly utilises fees. Adds committed funds

* New base funcs. New order summary

* Fun test updates

* Fix logo colouring

* Fixes niteroonies

* Fix report

* BAD COMMIT

* Fixes funding issues.Updates default fee rates.Combines cashcarry case

* doc regen

* Now returns err

* Fixes sizing bug issue introduced in PR

* Fixes fun fee/total US value bug

* Fix chart bug. Show log charts with disclaimer

* sellside fee

* fixes fee and slippage view

* Fixed slippage price issue

* Fixes calculation and removes rendering

* Fixes stats and some rendering

* Merge fix

* Fixes merge issues

* go mod tidy, lint updates

* New linter attempt

* Version bump in appveyor and makefile

* Regex filename, config fixes, template h2 fixes

* Removes bad stats.

* neatens config builder. Moves filename generator

* Fixes issue where linter wants to fix my spelling

* Fixes pointers and starts
This commit is contained in:
Scott
2022-06-30 15:43:41 +10:00
committed by GitHub
parent d3339ad0b8
commit f929b4d51e
161 changed files with 15137 additions and 7292 deletions

View File

@@ -192,7 +192,7 @@ func (m *DataHistoryManager) compareJobsToData(jobs ...*DataHistoryJob) error {
jobs[i].rangeHolder.SetHasDataFromCandles(candles.Candles)
case dataHistoryTradeDataType:
for x := range jobs[i].rangeHolder.Ranges {
results, ok := jobs[i].Results[jobs[i].rangeHolder.Ranges[x].Start.Time]
results, ok := jobs[i].Results[jobs[i].rangeHolder.Ranges[x].Start.Time.Unix()]
if !ok {
continue
}
@@ -358,7 +358,7 @@ ranges:
}
}
if skipProcessing {
_, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time]
_, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time.Unix()]
if !ok && !job.OverwriteExistingData {
// we have determined that data is there, however it is not reflected in
// this specific job's results, which is required for a job to be complete
@@ -367,7 +367,7 @@ ranges:
if err != nil {
return err
}
job.Results[job.rangeHolder.Ranges[i].Start.Time] = []DataHistoryJobResult{
job.Results[job.rangeHolder.Ranges[i].Start.Time.Unix()] = []DataHistoryJobResult{
{
ID: id,
JobID: job.ID,
@@ -397,7 +397,7 @@ ranges:
var failures int64
hasDataInRange := false
resultLookup, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time]
resultLookup, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time.Unix()]
if ok {
for x := range resultLookup {
switch resultLookup[x].Status {
@@ -419,7 +419,7 @@ ranges:
for x := range resultLookup {
resultLookup[x].Status = dataHistoryIntervalIssuesFound
}
job.Results[job.rangeHolder.Ranges[i].Start.Time] = resultLookup
job.Results[job.rangeHolder.Ranges[i].Start.Time.Unix()] = resultLookup
continue
}
}
@@ -451,16 +451,16 @@ ranges:
return errNilResult
}
lookup := job.Results[result.IntervalStartDate]
lookup := job.Results[result.IntervalStartDate.Unix()]
lookup = append(lookup, *result)
job.Results[result.IntervalStartDate] = lookup
job.Results[result.IntervalStartDate.Unix()] = lookup
}
completed := true // nolint:ifshort,nolintlint // false positive and triggers only on Windows
allResultsSuccessful := true
allResultsFailed := true
completionCheck:
for i := range job.rangeHolder.Ranges {
result, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time]
result, ok := job.Results[job.rangeHolder.Ranges[i].Start.Time.Unix()]
if !ok {
completed = false
}
@@ -503,21 +503,22 @@ func (m *DataHistoryManager) runValidationJob(job *DataHistoryJob, exch exchange
nextIntervalToProcess := job.StartDate
timesToFetch:
for t, results := range job.Results {
tt := time.Unix(t, 0)
if len(results) < int(job.MaxRetryAttempts) {
for x := range results {
if results[x].Status == dataHistoryStatusComplete {
continue timesToFetch
}
}
intervalsToCheck = append(intervalsToCheck, t)
intervalsToCheck = append(intervalsToCheck, tt)
} else {
for x := range results {
results[x].Status = dataHistoryIntervalIssuesFound
}
job.Results[t] = results
}
if t.After(nextIntervalToProcess) {
nextIntervalToProcess = t.Add(intervalLength)
if tt.After(nextIntervalToProcess) {
nextIntervalToProcess = tt.Add(intervalLength)
}
}
for i := nextIntervalToProcess; i.Before(job.EndDate); i = i.Add(intervalLength) {
@@ -548,9 +549,9 @@ timesToFetch:
if err != nil {
return err
}
lookup := job.Results[result.IntervalStartDate]
lookup := job.Results[result.IntervalStartDate.Unix()]
lookup = append(lookup, *result)
job.Results[result.IntervalStartDate] = lookup
job.Results[result.IntervalStartDate.Unix()] = lookup
}
completed := true // nolint:ifshort,nolintlint // false positive and triggers only on Windows
@@ -558,7 +559,7 @@ timesToFetch:
allResultsFailed := true
completionCheck:
for i := range jobIntervals {
results, ok := job.Results[jobIntervals[i]]
results, ok := job.Results[jobIntervals[i].Unix()]
if !ok {
completed = false
break
@@ -1198,7 +1199,7 @@ func (m *DataHistoryManager) validateJob(job *DataHistoryJob) error {
return fmt.Errorf("job %s exchange %s asset %s currency %s %w", job.Nickname, job.Exchange, job.Asset, job.Pair, errCurrencyNotEnabled)
}
if job.Results == nil {
job.Results = make(map[time.Time][]DataHistoryJobResult)
job.Results = make(map[int64][]DataHistoryJobResult)
}
if job.RunBatchLimit <= 0 {
log.Warnf(log.DataHistory, "job %s has unset batch limit, defaulting to %v", job.Nickname, defaultDataHistoryBatchLimit)
@@ -1520,11 +1521,11 @@ func (m *DataHistoryManager) convertDBModelToJob(dbModel *datahistoryjob.DataHis
return resp, nil
}
func (m *DataHistoryManager) convertDBResultToJobResult(dbModels []*datahistoryjobresult.DataHistoryJobResult) (map[time.Time][]DataHistoryJobResult, error) {
func (m *DataHistoryManager) convertDBResultToJobResult(dbModels []*datahistoryjobresult.DataHistoryJobResult) (map[int64][]DataHistoryJobResult, error) {
if !m.IsRunning() {
return nil, ErrSubSystemNotStarted
}
result := make(map[time.Time][]DataHistoryJobResult)
result := make(map[int64][]DataHistoryJobResult)
for i := range dbModels {
id, err := uuid.FromString(dbModels[i].ID)
if err != nil {
@@ -1535,7 +1536,7 @@ func (m *DataHistoryManager) convertDBResultToJobResult(dbModels []*datahistoryj
if err != nil {
return nil, err
}
lookup := result[dbModels[i].IntervalStartDate]
lookup := result[dbModels[i].IntervalStartDate.Unix()]
lookup = append(lookup, DataHistoryJobResult{
ID: id,
JobID: jobID,
@@ -1545,13 +1546,13 @@ func (m *DataHistoryManager) convertDBResultToJobResult(dbModels []*datahistoryj
Result: dbModels[i].Result,
Date: dbModels[i].Date,
})
result[dbModels[i].IntervalStartDate] = lookup
result[dbModels[i].IntervalStartDate.Unix()] = lookup
}
return result, nil
}
func (m *DataHistoryManager) convertJobResultToDBResult(results map[time.Time][]DataHistoryJobResult) []*datahistoryjobresult.DataHistoryJobResult {
func (m *DataHistoryManager) convertJobResultToDBResult(results map[int64][]DataHistoryJobResult) []*datahistoryjobresult.DataHistoryJobResult {
var response []*datahistoryjobresult.DataHistoryJobResult
for _, v := range results {
for i := range v {

View File

@@ -893,8 +893,8 @@ func TestConverters(t *testing.T) {
Result: "test123",
Date: time.Now(),
}
mapperino := make(map[time.Time][]DataHistoryJobResult)
mapperino[dhj.StartDate] = append(mapperino[dhj.StartDate], jr)
mapperino := make(map[int64][]DataHistoryJobResult)
mapperino[dhj.StartDate.Unix()] = append(mapperino[dhj.StartDate.Unix()], jr)
result := m.convertJobResultToDBResult(mapperino)
if jr.ID.String() != result[0].ID ||
jr.JobID.String() != result[0].JobID ||
@@ -910,13 +910,13 @@ func TestConverters(t *testing.T) {
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
if jr.ID != andBackAgain[dhj.StartDate][0].ID ||
jr.JobID != andBackAgain[dhj.StartDate][0].JobID ||
jr.Result != andBackAgain[dhj.StartDate][0].Result ||
!jr.Date.Equal(andBackAgain[dhj.StartDate][0].Date) ||
!jr.IntervalStartDate.Equal(andBackAgain[dhj.StartDate][0].IntervalStartDate) ||
!jr.IntervalEndDate.Equal(andBackAgain[dhj.StartDate][0].IntervalEndDate) ||
jr.Status != andBackAgain[dhj.StartDate][0].Status {
if jr.ID != andBackAgain[dhj.StartDate.Unix()][0].ID ||
jr.JobID != andBackAgain[dhj.StartDate.Unix()][0].JobID ||
jr.Result != andBackAgain[dhj.StartDate.Unix()][0].Result ||
!jr.Date.Equal(andBackAgain[dhj.StartDate.Unix()][0].Date) ||
!jr.IntervalStartDate.Equal(andBackAgain[dhj.StartDate.Unix()][0].IntervalStartDate) ||
!jr.IntervalEndDate.Equal(andBackAgain[dhj.StartDate.Unix()][0].IntervalEndDate) ||
jr.Status != andBackAgain[dhj.StartDate.Unix()][0].Status {
t.Error("expected matching job")
}
}

View File

@@ -155,7 +155,7 @@ type DataHistoryJob struct {
MaxRetryAttempts int64
Status dataHistoryStatus
CreatedDate time.Time
Results map[time.Time][]DataHistoryJobResult
Results map[int64][]DataHistoryJobResult
rangeHolder *kline.IntervalRangeHolder
OverwriteExistingData bool
ConversionInterval kline.Interval

View File

@@ -283,6 +283,7 @@ func PrintSettings(s *Settings) {
gctlog.Debugf(gctlog.Global, "\t Enable dispatcher: %v", s.EnableDispatcher)
gctlog.Debugf(gctlog.Global, "\t Dispatch package max worker amount: %d", s.DispatchMaxWorkerAmount)
gctlog.Debugf(gctlog.Global, "\t Dispatch package jobs limit: %d", s.DispatchJobsLimit)
gctlog.Debugf(gctlog.Global, "\t Futures PNL tracking: %v", s.EnableFuturesTracking)
gctlog.Debugf(gctlog.Global, "- EXCHANGE SYNCER SETTINGS:\n")
gctlog.Debugf(gctlog.Global, "\t Exchange sync continuously: %v\n", s.SyncContinuously)
gctlog.Debugf(gctlog.Global, "\t Exchange sync workers count: %v\n", s.SyncWorkersCount)
@@ -513,6 +514,7 @@ func (bot *Engine) Start() error {
bot.ExchangeManager,
bot.CommunicationsManager,
&bot.ServicesWG,
bot.Settings.EnableFuturesTracking,
bot.Settings.Verbose)
if err != nil {
gctlog.Errorf(gctlog.Global, "Order manager unable to setup: %s", err)

View File

@@ -39,6 +39,7 @@ type Settings struct {
EnableWebsocketRoutine bool
EnableCurrencyStateManager bool
EventManagerDelay time.Duration
EnableFuturesTracking bool
Verbose bool
// Exchange syncer settings

View File

@@ -137,6 +137,7 @@ func (bot *Engine) SetSubsystem(subSystemName string, enable bool) error {
bot.ExchangeManager,
bot.CommunicationsManager,
&bot.ServicesWG,
bot.Settings.EnableFuturesTracking,
bot.Settings.Verbose)
if err != nil {
return err

View File

@@ -21,7 +21,7 @@ import (
)
// SetupOrderManager will boot up the OrderManager
func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager iCommsManager, wg *sync.WaitGroup, verbose bool) (*OrderManager, error) {
func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager iCommsManager, wg *sync.WaitGroup, enabledFuturesTracking, verbose bool) (*OrderManager, error) {
if exchangeManager == nil {
return nil, errNilExchangeManager
}
@@ -40,6 +40,7 @@ func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager i
commsManager: communicationsManager,
wg: wg,
futuresPositionController: order.SetupPositionController(),
trackFuturesPositions: enabledFuturesTracking,
},
verbose: verbose,
}, nil
@@ -889,7 +890,7 @@ func (s *store) upsert(od *order.Detail) (*OrderUpsertResponse, error) {
}
s.m.Lock()
defer s.m.Unlock()
if od.AssetType.IsFutures() {
if s.trackFuturesPositions && od.AssetType.IsFutures() {
err = s.futuresPositionController.TrackNewOrder(od)
if err != nil && !errors.Is(err, order.ErrPositionClosed) {
return nil, err

View File

@@ -93,21 +93,21 @@ func (f omfExchange) ModifyOrder(ctx context.Context, action *order.Modify) (*or
}
func TestSetupOrderManager(t *testing.T) {
_, err := SetupOrderManager(nil, nil, nil, false)
_, err := SetupOrderManager(nil, nil, nil, false, false)
if !errors.Is(err, errNilExchangeManager) {
t.Errorf("error '%v', expected '%v'", err, errNilExchangeManager)
}
_, err = SetupOrderManager(SetupExchangeManager(), nil, nil, false)
_, err = SetupOrderManager(SetupExchangeManager(), nil, nil, false, false)
if !errors.Is(err, errNilCommunicationsManager) {
t.Errorf("error '%v', expected '%v'", err, errNilCommunicationsManager)
}
_, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, nil, false)
_, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, nil, false, false)
if !errors.Is(err, errNilWaitGroup) {
t.Errorf("error '%v', expected '%v'", err, errNilWaitGroup)
}
var wg sync.WaitGroup
_, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false)
_, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -120,7 +120,7 @@ func TestOrderManagerStart(t *testing.T) {
t.Errorf("error '%v', expected '%v'", err, ErrNilSubsystem)
}
var wg sync.WaitGroup
m, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false)
m, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -141,7 +141,7 @@ func TestOrderManagerIsRunning(t *testing.T) {
}
var wg sync.WaitGroup
m, err := SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false)
m, err := SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -166,7 +166,7 @@ func TestOrderManagerStop(t *testing.T) {
}
var wg sync.WaitGroup
m, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false)
m, err = SetupOrderManager(SetupExchangeManager(), &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -209,7 +209,7 @@ func OrdersSetup(t *testing.T) *OrderManager {
IBotExchange: exch,
}
em.Add(fakeExchange)
m, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false)
m, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -674,7 +674,7 @@ func TestProcessOrders(t *testing.T) {
IBotExchange: exch,
}
em.Add(fakeExchange)
m, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false)
m, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
@@ -782,7 +782,7 @@ func TestProcessOrders(t *testing.T) {
t.Error(err)
}
if len(res) != 1 {
t.Errorf("Expected 3 result, got: %d", len(res))
t.Errorf("Expected 1 result, got: %d", len(res))
}
if res[0].Status != order.Active {
t.Errorf("Order 1 should be active, but status is %s", res[0].Status)
@@ -1285,6 +1285,7 @@ func TestUpdateExisting(t *testing.T) {
if !errors.Is(err, ErrOrderNotFound) {
t.Errorf("received '%v', expected '%v'", err, ErrOrderNotFound)
}
od.Exchange = testExchange
od.AssetType = asset.Futures
od.OrderID = "123"
od.Pair = currency.NewPair(currency.BTC, currency.USDT)
@@ -1296,6 +1297,10 @@ func TestUpdateExisting(t *testing.T) {
od,
}
s.futuresPositionController = order.SetupPositionController()
err = s.futuresPositionController.TrackNewOrder(od)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)
}
err = s.updateExisting(od)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)

View File

@@ -46,6 +46,7 @@ type store struct {
exchangeManager iExchangeManager
wg *sync.WaitGroup
futuresPositionController *order.PositionController
trackFuturesPositions bool
}
// OrderManager processes and stores orders across enabled exchanges

View File

@@ -868,7 +868,7 @@ func (s *RPCServer) GetForexRates(_ context.Context, _ *gctrpc.GetForexRatesRequ
continue
}
// TODO
// TODO add inverse rate
// inverseRate, err := rates[x].GetInversionRate()
// if err != nil {
// continue
@@ -3375,10 +3375,10 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
start = start.Truncate(time.Hour)
end = end.Truncate(time.Hour)
intervalMap := make(map[time.Time]bool)
intervalMap := make(map[int64]bool)
iterationTime := start
for iterationTime.Before(end) {
intervalMap[iterationTime] = false
intervalMap[iterationTime.Unix()] = false
iterationTime = iterationTime.Add(time.Hour)
}

View File

@@ -141,7 +141,6 @@ func (f fExchange) GetFuturesPositions(_ context.Context, a asset.Item, cp curre
Price: 1337,
Amount: 1337,
Fee: 1.337,
FeeAsset: currency.Code{},
Exchange: f.GetName(),
OrderID: "test",
Side: order.Long,
@@ -1139,7 +1138,7 @@ func TestGetOrders(t *testing.T) {
RequestFormat: &currency.PairFormat{Uppercase: true}}
em.Add(exch)
var wg sync.WaitGroup
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false)
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)
}
@@ -1246,7 +1245,7 @@ func TestGetOrder(t *testing.T) {
RequestFormat: &currency.PairFormat{Uppercase: true}}
em.Add(exch)
var wg sync.WaitGroup
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false)
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)
}
@@ -1775,7 +1774,7 @@ func TestGetManagedOrders(t *testing.T) {
RequestFormat: &currency.PairFormat{Uppercase: true}}
em.Add(exch)
var wg sync.WaitGroup
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false)
om, err := SetupOrderManager(em, engerino.CommunicationsManager, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)
}
@@ -2108,6 +2107,7 @@ func TestGetFuturesPositions(t *testing.T) {
if err != nil {
t.Fatal(err)
}
cp.Delimiter = ""
b.CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
b.CurrencyPairs.Pairs[asset.Futures] = &currency.PairStore{
@@ -2129,7 +2129,7 @@ func TestGetFuturesPositions(t *testing.T) {
}
em.Add(fakeExchange)
var wg sync.WaitGroup
om, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false)
om, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v', expected '%v'", err, nil)
}
@@ -2164,7 +2164,37 @@ func TestGetFuturesPositions(t *testing.T) {
Secret: "super wow",
})
r, err := s.GetFuturesPositions(ctx, &gctrpc.GetFuturesPositionsRequest{
_, err = s.GetFuturesPositions(ctx, &gctrpc.GetFuturesPositionsRequest{
Exchange: fakeExchangeName,
Asset: asset.Futures.String(),
Pair: &gctrpc.CurrencyPair{
Delimiter: currency.DashDelimiter,
Base: cp.Base.String(),
Quote: cp.Quote.String(),
},
Verbose: true,
})
if !errors.Is(err, order.ErrPositionsNotLoadedForExchange) {
t.Fatalf("received '%v', expected '%v'", err, order.ErrPositionsNotLoadedForExchange)
}
od := &order.Detail{
Price: 1337,
Amount: 1337,
Fee: 1.337,
Exchange: fakeExchangeName,
OrderID: "test",
Side: order.Long,
Status: order.Open,
AssetType: asset.Futures,
Date: time.Now(),
Pair: cp,
}
err = s.OrderManager.orderStore.futuresPositionController.TrackNewOrder(od)
if !errors.Is(err, nil) {
t.Fatalf("received '%v', expected '%v'", err, nil)
}
_, err = s.GetFuturesPositions(ctx, &gctrpc.GetFuturesPositionsRequest{
Exchange: fakeExchangeName,
Asset: asset.Futures.String(),
Pair: &gctrpc.CurrencyPair{
@@ -2177,15 +2207,6 @@ func TestGetFuturesPositions(t *testing.T) {
if !errors.Is(err, nil) {
t.Fatalf("received '%v', expected '%v'", err, nil)
}
if r == nil { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
t.Fatal("expected not nil response")
}
if len(r.Positions) != 1 { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
t.Fatal("expected 1 position")
}
if r.TotalOrders != 1 { //nolint:staticcheck,nolintlint // SA5011 Ignore the nil warnings
t.Fatal("expected 1 order")
}
_, err = s.GetFuturesPositions(ctx, &gctrpc.GetFuturesPositionsRequest{
Exchange: fakeExchangeName,

View File

@@ -131,7 +131,7 @@ func TestWebsocketRoutineManagerHandleData(t *testing.T) {
exch.SetDefaults()
em.Add(exch)
om, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false)
om, err := SetupOrderManager(em, &CommunicationManager{}, &wg, false, false)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}