mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-30 07:26:46 +00:00
* 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
1375 lines
35 KiB
Go
1375 lines
35 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/base"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/top2bottom2"
|
|
"github.com/thrasher-corp/gocryptotrader/common/file"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/database"
|
|
"github.com/thrasher-corp/gocryptotrader/database/drivers"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
|
)
|
|
|
|
const (
|
|
testExchange = "ftx"
|
|
dca = "dollarcostaverage"
|
|
// change this if you modify a config and want it to save to the example folder
|
|
saveConfig = false
|
|
)
|
|
|
|
var (
|
|
startDate = time.Date(time.Now().Year()-1, 8, 1, 0, 0, 0, 0, time.Local)
|
|
endDate = time.Date(time.Now().Year()-1, 12, 1, 0, 0, 0, 0, time.Local)
|
|
tradeEndDate = startDate.Add(time.Hour * 72)
|
|
makerFee = decimal.NewFromFloat(0.0002)
|
|
takerFee = decimal.NewFromFloat(0.0007)
|
|
minMax = MinMax{
|
|
MinimumSize: decimal.NewFromFloat(0.005),
|
|
MaximumSize: decimal.NewFromInt(2),
|
|
MaximumTotal: decimal.NewFromInt(40000),
|
|
}
|
|
initialFunds1000000 *decimal.Decimal
|
|
initialFunds100000 *decimal.Decimal
|
|
initialFunds10 *decimal.Decimal
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
iF1 := decimal.NewFromInt(1000000)
|
|
iF2 := decimal.NewFromInt(100000)
|
|
iBF := decimal.NewFromInt(10)
|
|
initialFunds1000000 = &iF1
|
|
initialFunds100000 = &iF2
|
|
initialFunds10 = &iBF
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestLoadConfig(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := LoadConfig([]byte(`{}`))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestValidateDate(t *testing.T) {
|
|
t.Parallel()
|
|
c := Config{}
|
|
err := c.validateDate()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
c.DataSettings = DataSettings{
|
|
DatabaseData: &DatabaseData{},
|
|
}
|
|
err = c.validateDate()
|
|
if !errors.Is(err, errStartEndUnset) {
|
|
t.Errorf("received: %v, expected: %v", err, errStartEndUnset)
|
|
}
|
|
c.DataSettings.DatabaseData.StartDate = time.Now()
|
|
c.DataSettings.DatabaseData.EndDate = c.DataSettings.DatabaseData.StartDate
|
|
err = c.validateDate()
|
|
if !errors.Is(err, errBadDate) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadDate)
|
|
}
|
|
c.DataSettings.DatabaseData.EndDate = c.DataSettings.DatabaseData.StartDate.Add(time.Minute)
|
|
err = c.validateDate()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
c.DataSettings.APIData = &APIData{}
|
|
err = c.validateDate()
|
|
if !errors.Is(err, errStartEndUnset) {
|
|
t.Errorf("received: %v, expected: %v", err, errStartEndUnset)
|
|
}
|
|
c.DataSettings.APIData.StartDate = time.Now()
|
|
c.DataSettings.APIData.EndDate = c.DataSettings.APIData.StartDate
|
|
err = c.validateDate()
|
|
if !errors.Is(err, errBadDate) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadDate)
|
|
}
|
|
c.DataSettings.APIData.EndDate = c.DataSettings.APIData.StartDate.Add(time.Minute)
|
|
err = c.validateDate()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestValidateCurrencySettings(t *testing.T) {
|
|
t.Parallel()
|
|
c := Config{}
|
|
err := c.validateCurrencySettings()
|
|
if !errors.Is(err, errNoCurrencySettings) {
|
|
t.Errorf("received: %v, expected: %v", err, errNoCurrencySettings)
|
|
}
|
|
c.CurrencySettings = append(c.CurrencySettings, CurrencySettings{})
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errUnsetCurrency) {
|
|
t.Errorf("received: %v, expected: %v", err, errUnsetCurrency)
|
|
}
|
|
leet := decimal.NewFromInt(1337)
|
|
c.CurrencySettings[0].SpotDetails = &SpotDetails{InitialQuoteFunds: &leet}
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errUnsetCurrency) {
|
|
t.Errorf("received: %v, expected: %v", err, errUnsetCurrency)
|
|
}
|
|
c.CurrencySettings[0].Base = currency.NewCode("lol")
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, asset.ErrNotSupported) {
|
|
t.Errorf("received: %v, expected: %v", err, asset.ErrNotSupported)
|
|
}
|
|
c.CurrencySettings[0].Asset = asset.Spot
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errUnsetExchange) {
|
|
t.Errorf("received: %v, expected: %v", err, errUnsetExchange)
|
|
}
|
|
c.CurrencySettings[0].ExchangeName = "lol"
|
|
err = c.validateCurrencySettings()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
c.CurrencySettings[0].Asset = asset.PerpetualSwap
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errPerpetualsUnsupported) {
|
|
t.Errorf("received: %v, expected: %v", err, errPerpetualsUnsupported)
|
|
}
|
|
|
|
c.CurrencySettings[0].Asset = asset.Futures
|
|
c.CurrencySettings[0].Quote = currency.NewCode("PERP")
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errPerpetualsUnsupported) {
|
|
t.Errorf("received: %v, expected: %v", err, errPerpetualsUnsupported)
|
|
}
|
|
|
|
c.CurrencySettings[0].MinimumSlippagePercent = decimal.NewFromInt(2)
|
|
c.CurrencySettings[0].MaximumSlippagePercent = decimal.NewFromInt(3)
|
|
c.CurrencySettings[0].Quote = currency.NewCode("USD")
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errFeatureIncompatible) {
|
|
t.Errorf("received: %v, expected: %v", err, errFeatureIncompatible)
|
|
}
|
|
|
|
c.CurrencySettings[0].Asset = asset.Spot
|
|
c.CurrencySettings[0].MinimumSlippagePercent = decimal.NewFromInt(-1)
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadSlippageRates) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadSlippageRates)
|
|
}
|
|
c.CurrencySettings[0].MinimumSlippagePercent = decimal.NewFromInt(2)
|
|
c.CurrencySettings[0].MaximumSlippagePercent = decimal.NewFromInt(-1)
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadSlippageRates) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadSlippageRates)
|
|
}
|
|
c.CurrencySettings[0].MinimumSlippagePercent = decimal.NewFromInt(2)
|
|
c.CurrencySettings[0].MaximumSlippagePercent = decimal.NewFromInt(1)
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadSlippageRates) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadSlippageRates)
|
|
}
|
|
|
|
c.CurrencySettings[0].SpotDetails = &SpotDetails{}
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadInitialFunds) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadInitialFunds)
|
|
}
|
|
|
|
z := decimal.Zero
|
|
c.CurrencySettings[0].SpotDetails.InitialQuoteFunds = &z
|
|
c.CurrencySettings[0].SpotDetails.InitialBaseFunds = &z
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadInitialFunds) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadInitialFunds)
|
|
}
|
|
|
|
c.CurrencySettings[0].SpotDetails.InitialQuoteFunds = &leet
|
|
c.FundingSettings.UseExchangeLevelFunding = true
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadInitialFunds) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadInitialFunds)
|
|
}
|
|
|
|
c.CurrencySettings[0].SpotDetails.InitialQuoteFunds = &z
|
|
c.CurrencySettings[0].SpotDetails.InitialBaseFunds = &leet
|
|
c.FundingSettings.UseExchangeLevelFunding = true
|
|
err = c.validateCurrencySettings()
|
|
if !errors.Is(err, errBadInitialFunds) {
|
|
t.Errorf("received: %v, expected: %v", err, errBadInitialFunds)
|
|
}
|
|
}
|
|
|
|
func TestValidateMinMaxes(t *testing.T) {
|
|
t.Parallel()
|
|
c := &Config{}
|
|
err := c.validateMinMaxes()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
SellSide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(-1),
|
|
},
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errSizeLessThanZero) {
|
|
t.Errorf("received %v expected %v", err, errSizeLessThanZero)
|
|
}
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
SellSide: MinMax{
|
|
MaximumTotal: decimal.NewFromInt(-1),
|
|
},
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errSizeLessThanZero) {
|
|
t.Errorf("received %v expected %v", err, errSizeLessThanZero)
|
|
}
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
SellSide: MinMax{
|
|
MaximumSize: decimal.NewFromInt(-1),
|
|
},
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errSizeLessThanZero) {
|
|
t.Errorf("received %v expected %v", err, errSizeLessThanZero)
|
|
}
|
|
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(2),
|
|
MaximumTotal: decimal.NewFromInt(10),
|
|
MaximumSize: decimal.NewFromInt(1),
|
|
},
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errMaxSizeMinSizeMismatch) {
|
|
t.Errorf("received %v expected %v", err, errMaxSizeMinSizeMismatch)
|
|
}
|
|
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(2),
|
|
MaximumSize: decimal.NewFromInt(2),
|
|
},
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errMinMaxEqual) {
|
|
t.Errorf("received %v expected %v", err, errMinMaxEqual)
|
|
}
|
|
|
|
c.CurrencySettings = []CurrencySettings{
|
|
{
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(1),
|
|
MaximumTotal: decimal.NewFromInt(10),
|
|
MaximumSize: decimal.NewFromInt(2),
|
|
},
|
|
},
|
|
}
|
|
c.PortfolioSettings = PortfolioSettings{
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(-1),
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errSizeLessThanZero) {
|
|
t.Errorf("received %v expected %v", err, errSizeLessThanZero)
|
|
}
|
|
c.PortfolioSettings = PortfolioSettings{
|
|
SellSide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(-1),
|
|
},
|
|
}
|
|
err = c.validateMinMaxes()
|
|
if !errors.Is(err, errSizeLessThanZero) {
|
|
t.Errorf("received %v expected %v", err, errSizeLessThanZero)
|
|
}
|
|
}
|
|
|
|
func TestValidateStrategySettings(t *testing.T) {
|
|
t.Parallel()
|
|
c := &Config{}
|
|
err := c.validateStrategySettings()
|
|
if !errors.Is(err, base.ErrStrategyNotFound) {
|
|
t.Errorf("received %v expected %v", err, base.ErrStrategyNotFound)
|
|
}
|
|
c.StrategySettings = StrategySettings{Name: dca}
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
|
|
c.StrategySettings.SimultaneousSignalProcessing = true
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
c.FundingSettings = FundingSettings{}
|
|
c.FundingSettings.UseExchangeLevelFunding = true
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, errExchangeLevelFundingDataRequired) {
|
|
t.Errorf("received %v expected %v", err, errExchangeLevelFundingDataRequired)
|
|
}
|
|
c.FundingSettings.ExchangeLevelFunding = []ExchangeLevelFunding{
|
|
{
|
|
InitialFunds: decimal.NewFromInt(-1),
|
|
},
|
|
}
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, errBadInitialFunds) {
|
|
t.Errorf("received %v expected %v", err, errBadInitialFunds)
|
|
}
|
|
|
|
c.StrategySettings.SimultaneousSignalProcessing = false
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, errSimultaneousProcessingRequired) {
|
|
t.Errorf("received %v expected %v", err, errSimultaneousProcessingRequired)
|
|
}
|
|
|
|
c.FundingSettings.UseExchangeLevelFunding = false
|
|
err = c.validateStrategySettings()
|
|
if !errors.Is(err, errExchangeLevelFundingRequired) {
|
|
t.Errorf("received %v expected %v", err, errExchangeLevelFundingRequired)
|
|
}
|
|
}
|
|
|
|
func TestPrintSettings(t *testing.T) {
|
|
t.Parallel()
|
|
cfg := Config{
|
|
Nickname: "super fun run",
|
|
Goal: "To demonstrate rendering of settings",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
CustomSettings: map[string]interface{}{
|
|
"dca-dummy1": 30.0,
|
|
"dca-dummy2": 30.0,
|
|
"dca-dummy3": 30.0,
|
|
},
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds1000000,
|
|
InitialBaseFunds: initialFunds1000000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
FuturesDetails: &FuturesDetails{},
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneMin,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: true,
|
|
},
|
|
CSVData: &CSVData{
|
|
FullPath: "fake",
|
|
},
|
|
LiveData: &LiveData{
|
|
APIKeyOverride: "",
|
|
APISecretOverride: "",
|
|
APIClientIDOverride: "",
|
|
API2FAOverride: "",
|
|
APISubAccountOverride: "",
|
|
RealOrders: false,
|
|
},
|
|
DatabaseData: &DatabaseData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
Config: database.Config{},
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
cfg.PrintSetting()
|
|
cfg.FundingSettings = FundingSettings{
|
|
UseExchangeLevelFunding: true,
|
|
ExchangeLevelFunding: []ExchangeLevelFunding{{}},
|
|
}
|
|
cfg.PrintSetting()
|
|
}
|
|
|
|
func TestValidate(t *testing.T) {
|
|
t.Parallel()
|
|
c := &Config{
|
|
StrategySettings: StrategySettings{Name: dca},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialBaseFunds: initialFunds10,
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromInt(1),
|
|
MaximumSize: decimal.NewFromInt(10),
|
|
MaximumTotal: decimal.NewFromInt(10),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if err := c.Validate(); !errors.Is(err, nil) {
|
|
t.Errorf("received %v expected %v", err, nil)
|
|
}
|
|
}
|
|
|
|
func TestReadConfigFromFile(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
passFile, err := ioutil.TempFile(tempDir, "*.start")
|
|
if err != nil {
|
|
t.Fatalf("Problem creating temp file at %v: %s\n", passFile, err)
|
|
}
|
|
_, err = passFile.WriteString("{}")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = passFile.Close()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = ReadConfigFromFile(passFile.Name())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCAAPICandles(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCAAPICandles",
|
|
Goal: "To demonstrate DCA strategy using API candles",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCAAPICandlesExchangeLevelFunding(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCAAPICandlesExchangeLevelFunding",
|
|
Goal: "To demonstrate DCA strategy using API candles using a shared pool of funds",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
SimultaneousSignalProcessing: true,
|
|
DisableUSDTracking: true,
|
|
},
|
|
FundingSettings: FundingSettings{
|
|
UseExchangeLevelFunding: true,
|
|
ExchangeLevelFunding: []ExchangeLevelFunding{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Currency: currency.USDT,
|
|
InitialFunds: decimal.NewFromInt(100000),
|
|
},
|
|
},
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.ETH,
|
|
Quote: currency.USDT,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-exchange-level-funding.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCAAPITrades(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCAAPITrades",
|
|
Goal: "To demonstrate running the DCA strategy using API trade data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: "ftx",
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
SkipCandleVolumeFitting: true,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneHour,
|
|
DataType: common.TradeStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: tradeEndDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: MinMax{
|
|
MinimumSize: decimal.NewFromFloat(0.1),
|
|
MaximumSize: decimal.NewFromInt(1),
|
|
MaximumTotal: decimal.NewFromInt(10000),
|
|
},
|
|
SellSide: MinMax{
|
|
MinimumSize: decimal.NewFromFloat(0.1),
|
|
MaximumSize: decimal.NewFromInt(1),
|
|
MaximumTotal: decimal.NewFromInt(10000),
|
|
},
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-trades.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCAAPICandlesMultipleCurrencies(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCAAPICandlesMultipleCurrencies",
|
|
Goal: "To demonstrate running the DCA strategy using the API against multiple currencies candle data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.ETH,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-multiple-currencies.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCAAPICandlesSimultaneousProcessing(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCAAPICandlesSimultaneousProcessing",
|
|
Goal: "To demonstrate how simultaneous processing can work",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
SimultaneousSignalProcessing: true,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds1000000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.ETH,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-api-candles-simultaneous-processing.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCALiveCandles(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCALiveCandles",
|
|
Goal: "To demonstrate live trading proof of concept against candle data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
DisableUSDTracking: true,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneMin,
|
|
DataType: common.CandleStr,
|
|
LiveData: &LiveData{
|
|
APIKeyOverride: "",
|
|
APISecretOverride: "",
|
|
APIClientIDOverride: "",
|
|
API2FAOverride: "",
|
|
APISubAccountOverride: "",
|
|
RealOrders: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-candles-live.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForRSIAPICustomSettings(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "TestGenerateRSICandleAPICustomSettingsStrat",
|
|
Goal: "To demonstrate the RSI strategy using API candle data and custom settings",
|
|
StrategySettings: StrategySettings{
|
|
Name: "rsi",
|
|
CustomSettings: map[string]interface{}{
|
|
"rsi-low": 30.0,
|
|
"rsi-high": 70.0,
|
|
"rsi-period": 14,
|
|
},
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.ETH,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialBaseFunds: initialFunds10,
|
|
InitialQuoteFunds: initialFunds1000000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "rsi-api-candles.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCACSVCandles(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
fp := filepath.Join("..", "testdata", "binance_BTCUSDT_24h_2019_01_01_2020_01_01.csv")
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCACSVCandles",
|
|
Goal: "To demonstrate the DCA strategy using CSV candle data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
DisableUSDTracking: true,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
CSVData: &CSVData{
|
|
FullPath: fp,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-csv-candles.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCACSVTrades(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
fp := filepath.Join("..", "testdata", "binance_BTCUSDT_24h-trades_2020_11_16.csv")
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCACSVTrades",
|
|
Goal: "To demonstrate the DCA strategy using CSV trade data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
DisableUSDTracking: true,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneMin,
|
|
DataType: common.TradeStr,
|
|
CSVData: &CSVData{
|
|
FullPath: fp,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-csv-trades.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForDCADatabaseCandles(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyDCADatabaseCandles",
|
|
Goal: "To demonstrate the DCA strategy using database candle data",
|
|
StrategySettings: StrategySettings{
|
|
Name: dca,
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
SpotDetails: &SpotDetails{
|
|
InitialQuoteFunds: initialFunds100000,
|
|
},
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
DatabaseData: &DatabaseData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
Config: database.Config{
|
|
Enabled: true,
|
|
Verbose: false,
|
|
Driver: "sqlite",
|
|
ConnectionDetails: drivers.ConnectionDetails{
|
|
Host: "localhost",
|
|
Database: "testsqlite.db",
|
|
},
|
|
},
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{
|
|
CanUseLeverage: false,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "dca-database-candles.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateConfigForTop2Bottom2(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleStrategyTop2Bottom2",
|
|
Goal: "To demonstrate a complex strategy using exchange level funding and simultaneous processing of data signals",
|
|
StrategySettings: StrategySettings{
|
|
Name: top2bottom2.Name,
|
|
SimultaneousSignalProcessing: true,
|
|
|
|
CustomSettings: map[string]interface{}{
|
|
"mfi-low": 32,
|
|
"mfi-high": 68,
|
|
"mfi-period": 14,
|
|
},
|
|
},
|
|
FundingSettings: FundingSettings{
|
|
UseExchangeLevelFunding: true,
|
|
ExchangeLevelFunding: []ExchangeLevelFunding{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Currency: currency.BTC,
|
|
InitialFunds: decimal.NewFromFloat(3),
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Currency: currency.USDT,
|
|
InitialFunds: decimal.NewFromInt(10000),
|
|
},
|
|
},
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USDT,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.DOGE,
|
|
Quote: currency.USDT,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.ETH,
|
|
Quote: currency.BTC,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.LTC,
|
|
Quote: currency.BTC,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.XRP,
|
|
Quote: currency.USDT,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: testExchange,
|
|
Asset: asset.Spot,
|
|
Base: currency.BNB,
|
|
Quote: currency.BTC,
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: startDate,
|
|
EndDate: endDate,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
BuySide: minMax,
|
|
SellSide: minMax,
|
|
Leverage: Leverage{},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "t2b2-api-candles-exchange-funding.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateFTXCashAndCarryStrategy(t *testing.T) {
|
|
if !saveConfig {
|
|
t.Skip()
|
|
}
|
|
cfg := Config{
|
|
Nickname: "ExampleCashAndCarry",
|
|
Goal: "To demonstrate a cash and carry strategy",
|
|
StrategySettings: StrategySettings{
|
|
Name: "ftx-cash-carry",
|
|
SimultaneousSignalProcessing: true,
|
|
},
|
|
FundingSettings: FundingSettings{
|
|
UseExchangeLevelFunding: true,
|
|
ExchangeLevelFunding: []ExchangeLevelFunding{
|
|
{
|
|
ExchangeName: "ftx",
|
|
Asset: asset.Spot,
|
|
Currency: currency.USD,
|
|
InitialFunds: *initialFunds100000,
|
|
},
|
|
},
|
|
},
|
|
CurrencySettings: []CurrencySettings{
|
|
{
|
|
ExchangeName: "ftx",
|
|
Asset: asset.Futures,
|
|
Base: currency.BTC,
|
|
Quote: currency.NewCode("20210924"),
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
{
|
|
ExchangeName: "ftx",
|
|
Asset: asset.Spot,
|
|
Base: currency.BTC,
|
|
Quote: currency.USD,
|
|
MakerFee: &makerFee,
|
|
TakerFee: &takerFee,
|
|
},
|
|
},
|
|
DataSettings: DataSettings{
|
|
Interval: kline.OneDay,
|
|
DataType: common.CandleStr,
|
|
APIData: &APIData{
|
|
StartDate: time.Date(2021, 1, 14, 0, 0, 0, 0, time.UTC),
|
|
EndDate: time.Date(2021, 9, 24, 0, 0, 0, 0, time.UTC),
|
|
InclusiveEndDate: false,
|
|
},
|
|
},
|
|
PortfolioSettings: PortfolioSettings{
|
|
Leverage: Leverage{
|
|
CanUseLeverage: true,
|
|
},
|
|
},
|
|
StatisticSettings: StatisticSettings{
|
|
RiskFreeRate: decimal.NewFromFloat(0.03),
|
|
},
|
|
}
|
|
if saveConfig {
|
|
result, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
p, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.WriteFile(filepath.Join(p, "examples", "ftx-cash-carry.strat"), result, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|