mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-07 23:16:53 +00:00
Backtester: Live trading upgrades (#1023)
* Modifications for a smoother live run * Fixes data appending * Successfully allows multi-currency live trading. Adds multiple currencies to live DCA strategy * Attempting to get cash and carry working * Poor attempts at sorting out data and appending it properly with USD in mind * =designs new live data handler * Updates cash and carry strat to work * adds test coverage. begins closeallpositions function * Updates cash and carry to work live * New kline.Event type. Cancels orders on close. Rn types * =Fixes USD funding issue * =fixes tests * fixes tests AGAIN * adds coverage to close all orders * crummy tests, should override * more tests * more tests * more coverage * removes scourge of currency.Pair maps. More tests * missed currency stuff * Fixes USD data issue & collateral issue. Needs to close ALL orders * Now triggers updates on the very first data entry * All my problems are solved now???? * fixes tests, extends coverage * there is some really funky candle stuff going on * my brain is melting * better shutdown management, fixes freezing bug * fixes data duplication issues, adds retries to requests * reduces logging, adds verbose options * expands coverage over all new functionality * fixes fun bug from curr == curr to curr.Equal(curr) * fixes setup issues and tests * starts adding external wallet amounts for funding * more setup for assets * setup live fund calcs and placing orders * successfully performs automated cash and carry * merge fixes * funding properly set at all times * fixes some bugs, need to address currencystatistics still * adds 'appeneded' trait, attempts to fix some stats * fixes stat bugs, adds cool new fetchfees feature * fixes terrible processing bugs * tightens realorder stats, sadly loses some live stats * this actually sets everything correctly for bothcd ..cd ..cd ..cd ..cd ..! * fix tests * coverage * beautiful new test coverage * docs * adds new fee getter delayer * commits from the correct directory * Lint * adds verbose to fund manager * Fix bug in t2b2 strat. Update dca live config. Docs * go mod tidy * update buf * buf + test improvement * Post merge fixes * fixes surprise offset bug * fix sizing restrictions for cash and carry * fix server lints * merge fixes * test fixesss * lintle fixles * slowloris * rn run to task, bug fixes, close all on close * rpc lint and fixes * bugfix: order manager not processing orders properly * somewhat addresses nits * absolutely broken end of day commit * absolutely massive knockon effects from nits * massive knockon effects continue * fixes things * address remaining nits * jk now fixes things * addresses the easier nits * more nit fixers * more niterinos addressederinos * refactors holdings and does some nits * so buf * addresses some nits, fixes holdings bugs * cleanup * attempts to fix alert chans to prevent many chans waiting? * terrible code, will revert * to be reviewed in detail tomorrow * Fixes up channel system * smashes those nits * fixes extra candles, fixes collateral bug, tests * fixes data races, introduces reflection * more checks n tests * Fixes cash and carry issues. Fixes more cool bugs * fixes ~typer~ typo * replace spot strats from ftx to binance * fixes all the tests I just destroyed * removes example path, rm verbose * 1) what 2) removes FTX references from the Backtester * renamed, non-working strategies * Removes FTX references almost as fast as sbf removes funds * regen docs, add contrib names,sort contrib names * fixes merge renamings * Addresses nits. Fixes setting API credentials. Fixes Binance limit retrieval * Fixes live order bugs with real orders and without * Apply suggestions from code review Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update backtester/engine/live.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update backtester/engine/live.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * Update backtester/config/strategyconfigbuilder/main.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * updates docs * even better docs Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
@@ -764,7 +764,11 @@ func (f *FTX) Order(
|
||||
req := make(map[string]interface{})
|
||||
req["market"] = marketName
|
||||
req["side"] = side
|
||||
req["price"] = price
|
||||
if orderType == "market" {
|
||||
req["price"] = nil
|
||||
} else {
|
||||
req["price"] = price
|
||||
}
|
||||
req["type"] = orderType
|
||||
req["size"] = size
|
||||
if reduceOnly {
|
||||
@@ -922,7 +926,7 @@ func (f *FTX) DeleteTriggerOrder(ctx context.Context, orderID string) (string, e
|
||||
|
||||
// GetFills gets order fills data and ensures that all
|
||||
// fills are retrieved from the supplied timeframe
|
||||
func (f *FTX) GetFills(ctx context.Context, market currency.Pair, item asset.Item, startTime, endTime time.Time) ([]FillsData, error) {
|
||||
func (f *FTX) GetFills(ctx context.Context, market currency.Pair, item asset.Item, startTime, endTime time.Time, orderID string) ([]FillsData, error) {
|
||||
var resp []FillsData
|
||||
var nextEnd = endTime
|
||||
limit := 200
|
||||
@@ -946,6 +950,9 @@ func (f *FTX) GetFills(ctx context.Context, market currency.Pair, item asset.Ite
|
||||
params.Set("start_time", strconv.FormatInt(startTime.Unix(), 10))
|
||||
params.Set("end_time", strconv.FormatInt(nextEnd.Unix(), 10))
|
||||
}
|
||||
if orderID != "" {
|
||||
params.Set("orderId", orderID)
|
||||
}
|
||||
endpoint := common.EncodeURLValues(getFills, params)
|
||||
err := f.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, endpoint, nil, &data)
|
||||
if err != nil {
|
||||
|
||||
@@ -678,6 +678,7 @@ func TestSubmitOrder(t *testing.T) {
|
||||
Amount: 1,
|
||||
AssetType: asset.Spot,
|
||||
ClientOrderID: "order12345679$$$$$",
|
||||
RetrieveFees: true,
|
||||
}
|
||||
_, err = f.SubmitOrder(context.Background(), orderSubmission)
|
||||
if err != nil {
|
||||
@@ -766,25 +767,30 @@ func TestGetFills(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
_, err := f.GetFills(context.Background(),
|
||||
currency.Pair{}, asset.Futures, time.Now().Add(time.Hour*24*365), time.Now())
|
||||
currency.Pair{}, asset.Futures, time.Now().Add(time.Hour*24*365), time.Now(), "")
|
||||
if !errors.Is(err, errStartTimeCannotBeAfterEndTime) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errStartTimeCannotBeAfterEndTime)
|
||||
}
|
||||
|
||||
_, err = f.GetFills(context.Background(),
|
||||
currency.Pair{}, asset.Futures, time.Time{}, time.Time{})
|
||||
currency.Pair{}, asset.Futures, time.Time{}, time.Time{}, "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = f.GetFills(context.Background(),
|
||||
currency.Pair{}, asset.Futures, time.Now().Add(-time.Hour*24*365), time.Now())
|
||||
currency.Pair{}, asset.Futures, time.Now().Add(-time.Hour*24*365), time.Now(), "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = f.GetFills(context.Background(),
|
||||
spotPair, asset.Spot, time.Now().Add(-time.Hour*24*365), time.Now())
|
||||
spotPair, asset.Spot, time.Now().Add(-time.Hour*24*365), time.Now(), "")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = f.GetFills(context.Background(),
|
||||
currency.EMPTYPAIR, asset.Futures, time.Time{}, time.Time{}, "177453606715")
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
@@ -2819,3 +2825,36 @@ func TestGetReferralRebateRate(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCollateralCurrencyForContract(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, a, err := f.GetCollateralCurrencyForContract(asset.Futures, currency.NewPair(currency.XRP, currency.BABYDOGE))
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
if a != asset.Futures {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", a, asset.Futures)
|
||||
}
|
||||
if !c.Equal(currency.USD) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", c, currency.USD)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencyForRealisedPNL(t *testing.T) {
|
||||
t.Parallel()
|
||||
c, a, err := f.GetCurrencyForRealisedPNL(asset.Futures, currency.NewPair(currency.XRP, currency.BABYDOGE))
|
||||
if !errors.Is(err, nil) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
||||
}
|
||||
if a != asset.Spot {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", a, asset.Spot)
|
||||
}
|
||||
if !c.Equal(currency.USD) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", c, currency.USD)
|
||||
}
|
||||
|
||||
_, _, err = f.GetCurrencyForRealisedPNL(asset.Spot, currency.NewPair(currency.SHIB, currency.DOGE))
|
||||
if !errors.Is(err, order.ErrNotFuturesAsset) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, order.ErrNotFuturesAsset)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ type OrderData struct {
|
||||
ClientID string `json:"clientId"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
FilledSize float64 `json:"filledSize"`
|
||||
Future currency.Pair `json:"future"`
|
||||
Future string `json:"future"`
|
||||
ID int64 `json:"id"`
|
||||
IOC bool `json:"ioc"`
|
||||
Market currency.Pair `json:"market"`
|
||||
|
||||
@@ -168,6 +168,14 @@ func (f *FTX) SetDefaults() {
|
||||
f.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
f.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
f.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
|
||||
err = f.LoadCollateralWeightings(context.TODO())
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to store collateral weightings. Err: %s",
|
||||
f.Name,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup takes in the supplied exchange configuration details and sets params
|
||||
@@ -206,15 +214,6 @@ func (f *FTX) Setup(exch *config.Exchange) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = f.CurrencyPairs.IsAssetEnabled(asset.Futures); err == nil {
|
||||
err = f.LoadCollateralWeightings(context.TODO())
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys,
|
||||
"%s failed to store collateral weightings. Err: %s",
|
||||
f.Name,
|
||||
err)
|
||||
}
|
||||
}
|
||||
return f.Websocket.SetupNewConnection(stream.ConnectionSetup{
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
@@ -490,7 +489,7 @@ func (f *FTX) UpdateAccountInfo(ctx context.Context, a asset.Item) (account.Hold
|
||||
hold := balances[x].Total - balances[x].AvailableWithoutBorrow
|
||||
acc.Currencies = append(acc.Currencies,
|
||||
account.Balance{
|
||||
CurrencyName: balances[x].Coin,
|
||||
Currency: balances[x].Coin,
|
||||
Total: balances[x].Total,
|
||||
Hold: hold,
|
||||
AvailableWithoutBorrow: balances[x].AvailableWithoutBorrow,
|
||||
@@ -648,10 +647,10 @@ func (f *FTX) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.Side == order.Ask {
|
||||
if s.Side.IsShort() {
|
||||
s.Side = order.Sell
|
||||
}
|
||||
if s.Side == order.Bid {
|
||||
if s.Side.IsLong() {
|
||||
s.Side = order.Buy
|
||||
}
|
||||
|
||||
@@ -674,7 +673,43 @@ func (f *FTX) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.DeriveSubmitResponse(strconv.FormatInt(tempResp.ID, 10))
|
||||
resp, err := s.DeriveSubmitResponse(strconv.FormatInt(tempResp.ID, 10))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.RetrieveFees {
|
||||
return resp, nil
|
||||
}
|
||||
time.Sleep(s.RetrieveFeeDelay)
|
||||
fills, err := f.GetFills(ctx, s.Pair, s.AssetType, time.Time{}, time.Time{}, strconv.FormatInt(tempResp.ID, 10))
|
||||
if err != nil {
|
||||
// choosing to return with no error so that a valid order is still returned to caller
|
||||
log.Errorf(log.ExchangeSys, "could not retrieve fees for order %v: %v", tempResp.ID, err)
|
||||
return resp, nil
|
||||
}
|
||||
for i := range fills {
|
||||
resp.Fee += fills[i].Fee
|
||||
var side order.Side
|
||||
side, err = order.StringToOrderSide(fills[i].Side)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.FeeAsset.IsEmpty() {
|
||||
resp.FeeAsset = fills[i].FeeCurrency
|
||||
}
|
||||
resp.Trades = append(resp.Trades, order.TradeHistory{
|
||||
Price: fills[i].Price,
|
||||
Amount: fills[i].Size,
|
||||
Fee: fills[i].Fee,
|
||||
Exchange: f.Name,
|
||||
TID: strconv.FormatInt(fills[i].TradeID, 10),
|
||||
Side: side,
|
||||
Timestamp: fills[i].Time,
|
||||
IsMaker: fills[i].Liquidity == "maker",
|
||||
FeeAsset: fills[i].FeeCurrency.String(),
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
@@ -1270,7 +1305,7 @@ func (f *FTX) GetHistoricCandlesExtended(ctx context.Context, p currency.Pair, a
|
||||
if len(summary) > 0 {
|
||||
log.Warnf(log.ExchangeSys, "%v - %v", f.Name, summary)
|
||||
}
|
||||
ret.RemoveDuplicates()
|
||||
ret.RemoveDuplicateCandlesByTime()
|
||||
ret.RemoveOutsideRange(start, end)
|
||||
ret.SortCandlesByTimestamp(false)
|
||||
return ret, nil
|
||||
@@ -1696,7 +1731,7 @@ func (f *FTX) GetFuturesPositions(ctx context.Context, request *order.PositionsR
|
||||
allPositions:
|
||||
for {
|
||||
var fills []FillsData
|
||||
fills, err = f.GetFills(ctx, request.Pairs[x], request.Asset, request.StartDate, endTime)
|
||||
fills, err = f.GetFills(ctx, request.Pairs[x], request.Asset, request.StartDate, endTime, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1760,12 +1795,15 @@ func (f *FTX) GetFuturesPositions(ctx context.Context, request *order.PositionsR
|
||||
}
|
||||
|
||||
// GetCollateralCurrencyForContract returns the collateral currency for an asset and contract pair
|
||||
func (f *FTX) GetCollateralCurrencyForContract(_ asset.Item, _ currency.Pair) (currency.Code, asset.Item, error) {
|
||||
func (f *FTX) GetCollateralCurrencyForContract(a asset.Item, _ currency.Pair) (currency.Code, asset.Item, error) {
|
||||
return currency.USD, asset.Futures, nil
|
||||
}
|
||||
|
||||
// GetCurrencyForRealisedPNL returns where to put realised PNL
|
||||
func (f *FTX) GetCurrencyForRealisedPNL(_ asset.Item, _ currency.Pair) (currency.Code, asset.Item, error) {
|
||||
func (f *FTX) GetCurrencyForRealisedPNL(a asset.Item, _ currency.Pair) (currency.Code, asset.Item, error) {
|
||||
if !a.IsFutures() {
|
||||
return currency.EMPTYCODE, asset.Empty, fmt.Errorf("%v %w", a, order.ErrNotFuturesAsset)
|
||||
}
|
||||
return currency.USD, asset.Spot, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user