mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-15 23:16:48 +00:00
* 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>
201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
package report
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/statistics"
|
|
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
)
|
|
|
|
// createUSDTotalsChart used for creating a chart in the HTML report
|
|
// to show how much the overall assets are worth over time
|
|
func createUSDTotalsChart(items []statistics.ValueAtTime, stats []statistics.FundingItemStatistics) (*Chart, error) {
|
|
if items == nil {
|
|
return nil, fmt.Errorf("%w missing values at time", gctcommon.ErrNilPointer)
|
|
}
|
|
if stats == nil {
|
|
return nil, fmt.Errorf("%w missing funding item statistics", gctcommon.ErrNilPointer)
|
|
}
|
|
response := &Chart{
|
|
AxisType: "logarithmic",
|
|
}
|
|
usdTotalChartPlot := make([]LinePlot, len(items))
|
|
for i := range items {
|
|
usdTotalChartPlot[i] = LinePlot{
|
|
Value: items[i].Value.InexactFloat64(),
|
|
UnixMilli: items[i].Time.UTC().UnixMilli(),
|
|
}
|
|
}
|
|
response.Data = append(response.Data, ChartLine{
|
|
Name: "Total USD value",
|
|
LinePlots: usdTotalChartPlot,
|
|
})
|
|
|
|
for i := range stats {
|
|
var plots []LinePlot
|
|
if stats[i].ReportItem.AppendedViaAPI {
|
|
continue
|
|
}
|
|
for j := range stats[i].ReportItem.Snapshots {
|
|
if stats[i].ReportItem.Snapshots[j].Available.IsZero() {
|
|
response.ShowZeroDisclaimer = true
|
|
}
|
|
plots = append(plots, LinePlot{
|
|
Value: stats[i].ReportItem.Snapshots[j].USDValue.InexactFloat64(),
|
|
UnixMilli: stats[i].ReportItem.Snapshots[j].Time.UTC().UnixMilli(),
|
|
})
|
|
}
|
|
response.Data = append(response.Data, ChartLine{
|
|
Name: fmt.Sprintf("%v %v %v USD value", stats[i].ReportItem.Exchange, stats[i].ReportItem.Asset, stats[i].ReportItem.Currency),
|
|
LinePlots: plots,
|
|
})
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// createHoldingsOverTimeChart used for creating a chart in the HTML report
|
|
// to show how many holdings of each type was held over the time of backtesting
|
|
func createHoldingsOverTimeChart(stats []statistics.FundingItemStatistics) (*Chart, error) {
|
|
if stats == nil {
|
|
return nil, fmt.Errorf("%w missing funding item statistics", gctcommon.ErrNilPointer)
|
|
}
|
|
response := &Chart{
|
|
AxisType: "logarithmic",
|
|
}
|
|
for i := range stats {
|
|
var plots []LinePlot
|
|
if stats[i].ReportItem.AppendedViaAPI {
|
|
continue
|
|
}
|
|
for j := range stats[i].ReportItem.Snapshots {
|
|
if stats[i].ReportItem.Snapshots[j].Available.IsZero() {
|
|
response.ShowZeroDisclaimer = true
|
|
}
|
|
plots = append(plots, LinePlot{
|
|
UnixMilli: stats[i].ReportItem.Snapshots[j].Time.UTC().UnixMilli(),
|
|
Value: stats[i].ReportItem.Snapshots[j].Available.InexactFloat64(),
|
|
})
|
|
}
|
|
response.Data = append(response.Data, ChartLine{
|
|
Name: fmt.Sprintf("%v %v %v holdings", stats[i].ReportItem.Exchange, stats[i].ReportItem.Asset, stats[i].ReportItem.Currency),
|
|
LinePlots: plots,
|
|
})
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// createPNLCharts shows a running history of all realised and unrealised PNL values
|
|
// over time
|
|
func createPNLCharts(items map[string]map[asset.Item]map[*currency.Item]map[*currency.Item]*statistics.CurrencyPairStatistic) (*Chart, error) {
|
|
if items == nil {
|
|
return nil, fmt.Errorf("%w missing currency pair statistics", gctcommon.ErrNilPointer)
|
|
}
|
|
response := &Chart{
|
|
AxisType: "linear",
|
|
}
|
|
for exch, assetMap := range items {
|
|
for item, baseMap := range assetMap {
|
|
for b, quoteMap := range baseMap {
|
|
for q, result := range quoteMap {
|
|
id := fmt.Sprintf("%v %v %v%v",
|
|
exch,
|
|
item,
|
|
b,
|
|
q)
|
|
uPNLName := fmt.Sprintf("%v Unrealised PNL", id)
|
|
rPNLName := fmt.Sprintf("%v Realised PNL", id)
|
|
|
|
unrealisedPNL := ChartLine{Name: uPNLName}
|
|
realisedPNL := ChartLine{Name: rPNLName}
|
|
for i := range result.Events {
|
|
if result.Events[i].PNL != nil {
|
|
realisedPNL.LinePlots = append(realisedPNL.LinePlots, LinePlot{
|
|
Value: result.Events[i].PNL.GetRealisedPNL().PNL.InexactFloat64(),
|
|
UnixMilli: result.Events[i].Time.UnixMilli(),
|
|
})
|
|
unrealisedPNL.LinePlots = append(unrealisedPNL.LinePlots, LinePlot{
|
|
Value: result.Events[i].PNL.GetUnrealisedPNL().PNL.InexactFloat64(),
|
|
UnixMilli: result.Events[i].Time.UnixMilli(),
|
|
})
|
|
}
|
|
}
|
|
if len(unrealisedPNL.LinePlots) == 0 || len(realisedPNL.LinePlots) == 0 {
|
|
continue
|
|
}
|
|
response.Data = append(response.Data, unrealisedPNL, realisedPNL)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
// createFuturesSpotDiffChart highlights the difference in futures and spot prices
|
|
// over time
|
|
func createFuturesSpotDiffChart(items map[string]map[asset.Item]map[*currency.Item]map[*currency.Item]*statistics.CurrencyPairStatistic) (*Chart, error) {
|
|
if items == nil {
|
|
return nil, fmt.Errorf("%w missing currency pair statistics", gctcommon.ErrNilPointer)
|
|
}
|
|
currs := make(map[currency.Pair]linkCurrencyDiff)
|
|
response := &Chart{
|
|
AxisType: "linear",
|
|
}
|
|
|
|
for _, assetMap := range items {
|
|
for item, baseMap := range assetMap {
|
|
for b, quoteMap := range baseMap {
|
|
for q, result := range quoteMap {
|
|
cp := currency.NewPair(b.Currency(), q.Currency())
|
|
if item.IsFutures() {
|
|
p := result.UnderlyingPair.Format(currency.EMPTYFORMAT)
|
|
diff, ok := currs[p]
|
|
if !ok {
|
|
diff = linkCurrencyDiff{}
|
|
}
|
|
diff.FuturesPair = cp
|
|
diff.SpotPair = p
|
|
diff.FuturesEvents = result.Events
|
|
currs[p] = diff
|
|
} else {
|
|
p := cp.Format(currency.EMPTYFORMAT)
|
|
diff, ok := currs[p]
|
|
if !ok {
|
|
diff = linkCurrencyDiff{}
|
|
}
|
|
diff.SpotEvents = result.Events
|
|
currs[p] = diff
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for i := range currs {
|
|
if currs[i].FuturesEvents == nil || currs[i].SpotEvents == nil {
|
|
continue
|
|
}
|
|
if len(currs[i].SpotEvents) != len(currs[i].FuturesEvents) {
|
|
continue
|
|
}
|
|
line := ChartLine{
|
|
Name: fmt.Sprintf("%v %v diff %%", currs[i].FuturesPair, currs[i].SpotPair),
|
|
}
|
|
for j := range currs[i].SpotEvents {
|
|
spotPrice := currs[i].SpotEvents[j].DataEvent.GetClosePrice()
|
|
futuresPrice := currs[i].FuturesEvents[j].DataEvent.GetClosePrice()
|
|
diff := futuresPrice.Sub(spotPrice).Div(spotPrice).Mul(decimal.NewFromInt(100))
|
|
line.LinePlots = append(line.LinePlots, LinePlot{
|
|
Value: diff.InexactFloat64(),
|
|
UnixMilli: currs[i].SpotEvents[j].Time.UnixMilli(),
|
|
})
|
|
}
|
|
response.Data = append(response.Data, line)
|
|
}
|
|
return response, nil
|
|
}
|