mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 06:53:52 +00:00
fix unmarshal behavior to gain more precision
This commit is contained in:
parent
abc1d535d8
commit
9978a3cf90
|
@ -1,7 +1,6 @@
|
||||||
package accounting
|
package accounting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -16,19 +15,15 @@ func zero(a float64) bool {
|
||||||
return int(math.Round(a*1e8)) == 0
|
return int(math.Round(a*1e8)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func round(a float64) float64 {
|
|
||||||
return math.Round(a*1e8) / 1e8
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stock types.Trade
|
type Stock types.Trade
|
||||||
|
|
||||||
func (stock *Stock) String() string {
|
func (stock *Stock) String() string {
|
||||||
return fmt.Sprintf("%f (%f)", stock.Price, stock.Quantity)
|
return stock.Price.String() + " (" + stock.Quantity.String() + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (stock *Stock) Consume(quantity fixedpoint.Value) fixedpoint.Value {
|
func (stock *Stock) Consume(quantity fixedpoint.Value) fixedpoint.Value {
|
||||||
q := fixedpoint.Min(stock.Quantity, quantity)
|
q := fixedpoint.Min(stock.Quantity, quantity)
|
||||||
stock.Quantity = stock.Quantity.Sub(q).Round(0, fixedpoint.Down)
|
stock.Quantity = stock.Quantity.Sub(q)
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +36,7 @@ func (slice StockSlice) QuantityBelowPrice(price fixedpoint.Value) (quantity fix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return quantity.Round(0, fixedpoint.Down)
|
return quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slice StockSlice) Quantity() (total fixedpoint.Value) {
|
func (slice StockSlice) Quantity() (total fixedpoint.Value) {
|
||||||
|
@ -49,7 +44,7 @@ func (slice StockSlice) Quantity() (total fixedpoint.Value) {
|
||||||
total = total.Add(stock.Quantity)
|
total = total.Add(stock.Quantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
return total.Round(0, fixedpoint.Down)
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
type StockDistribution struct {
|
type StockDistribution struct {
|
||||||
|
@ -77,10 +72,7 @@ func (m *StockDistribution) DistributionStats(level int) *DistributionStats {
|
||||||
for _, stock := range m.Stocks {
|
for _, stock := range m.Stocks {
|
||||||
n := math.Ceil(math.Log10(stock.Price.Float64()))
|
n := math.Ceil(math.Log10(stock.Price.Float64()))
|
||||||
digits := int(n - math.Max(float64(level), 1.0))
|
digits := int(n - math.Max(float64(level), 1.0))
|
||||||
// TODO: use Round function in fixedpoint
|
key := stock.Price.Round(-digits, fixedpoint.Down).FormatString(2)
|
||||||
div := math.Pow10(digits)
|
|
||||||
priceLevel := math.Floor(stock.Price.Float64()/div) * div
|
|
||||||
key := strconv.FormatFloat(priceLevel, 'f', 2, 64)
|
|
||||||
|
|
||||||
d.TotalQuantity = d.TotalQuantity.Add(stock.Quantity)
|
d.TotalQuantity = d.TotalQuantity.Add(stock.Quantity)
|
||||||
d.Stocks[key] = append(d.Stocks[key], stock)
|
d.Stocks[key] = append(d.Stocks[key], stock)
|
||||||
|
@ -98,8 +90,6 @@ func (m *StockDistribution) DistributionStats(level int) *DistributionStats {
|
||||||
d.PriceLevels = append(d.PriceLevels, strconv.FormatFloat(price, 'f', 2, 64))
|
d.PriceLevels = append(d.PriceLevels, strconv.FormatFloat(price, 'f', 2, 64))
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Float64s(priceLevels)
|
|
||||||
|
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStockManager(t *testing.T) {
|
func TestStockManager(t *testing.T) {
|
||||||
|
@ -28,7 +29,7 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
_, err = stockManager.AddTrades(trades)
|
_, err = stockManager.AddTrades(trades)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0.72970242, stockManager.Stocks.Quantity())
|
assert.Equal(t, "0.72970242", stockManager.Stocks.Quantity().String())
|
||||||
assert.NotEmpty(t, stockManager.Stocks)
|
assert.NotEmpty(t, stockManager.Stocks)
|
||||||
assert.Equal(t, 20, len(stockManager.Stocks))
|
assert.Equal(t, 20, len(stockManager.Stocks))
|
||||||
assert.Equal(t, 0, len(stockManager.PendingSells))
|
assert.Equal(t, 0, len(stockManager.PendingSells))
|
||||||
|
@ -37,9 +38,9 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("stock", func(t *testing.T) {
|
t.Run("stock", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.01, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.01"), IsBuyer: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -53,14 +54,14 @@ func TestStockManager(t *testing.T) {
|
||||||
assert.Equal(t, StockSlice{
|
assert.Equal(t, StockSlice{
|
||||||
{
|
{
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Price: 9100.0,
|
Price: fixedpoint.MustNewFromString("9100.0"),
|
||||||
Quantity: 0.05,
|
Quantity: fixedpoint.MustNewFromString("0.05"),
|
||||||
IsBuyer: true,
|
IsBuyer: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Price: 9100.0,
|
Price: fixedpoint.MustNewFromString("9100.0"),
|
||||||
Quantity: 0.04,
|
Quantity: fixedpoint.MustNewFromString("0.04"),
|
||||||
IsBuyer: true,
|
IsBuyer: true,
|
||||||
},
|
},
|
||||||
}, stockManager.Stocks)
|
}, stockManager.Stocks)
|
||||||
|
@ -69,10 +70,10 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("sold out", func(t *testing.T) {
|
t.Run("sold out", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.05, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.05, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -88,9 +89,9 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("oversell", func(t *testing.T) {
|
t.Run("oversell", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.05, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.05, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -106,9 +107,9 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("loss sell", func(t *testing.T) {
|
t.Run("loss sell", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.02, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.02"), IsBuyer: false},
|
||||||
{Symbol: "BTCUSDT", Price: 8000.0, Quantity: 0.01, IsBuyer: false},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("8000.0"), Quantity: fixedpoint.MustNewFromString("0.01"), IsBuyer: false},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -122,8 +123,8 @@ func TestStockManager(t *testing.T) {
|
||||||
assert.Equal(t, StockSlice{
|
assert.Equal(t, StockSlice{
|
||||||
{
|
{
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Price: 9100.0,
|
Price: fixedpoint.MustNewFromString("9100.0"),
|
||||||
Quantity: 0.02,
|
Quantity: fixedpoint.MustNewFromString("0.02"),
|
||||||
IsBuyer: true,
|
IsBuyer: true,
|
||||||
},
|
},
|
||||||
}, stockManager.Stocks)
|
}, stockManager.Stocks)
|
||||||
|
@ -132,8 +133,8 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("pending sell 1", func(t *testing.T) {
|
t.Run("pending sell 1", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.02},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.02")},
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -147,8 +148,8 @@ func TestStockManager(t *testing.T) {
|
||||||
assert.Equal(t, StockSlice{
|
assert.Equal(t, StockSlice{
|
||||||
{
|
{
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Price: 9100.0,
|
Price: fixedpoint.MustNewFromString("9100.0"),
|
||||||
Quantity: 0.03,
|
Quantity: fixedpoint.MustNewFromString("0.03"),
|
||||||
IsBuyer: true,
|
IsBuyer: true,
|
||||||
},
|
},
|
||||||
}, stockManager.Stocks)
|
}, stockManager.Stocks)
|
||||||
|
@ -157,8 +158,8 @@ func TestStockManager(t *testing.T) {
|
||||||
|
|
||||||
t.Run("pending sell 2", func(t *testing.T) {
|
t.Run("pending sell 2", func(t *testing.T) {
|
||||||
var trades = []types.Trade{
|
var trades = []types.Trade{
|
||||||
{Symbol: "BTCUSDT", Price: 9200.0, Quantity: 0.1},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9200.0"), Quantity: fixedpoint.MustNewFromString("0.1")},
|
||||||
{Symbol: "BTCUSDT", Price: 9100.0, Quantity: 0.05, IsBuyer: true},
|
{Symbol: "BTCUSDT", Price: fixedpoint.MustNewFromString("9100.0"), Quantity: fixedpoint.MustNewFromString("0.05"), IsBuyer: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
var stockManager = &StockDistribution{
|
var stockManager = &StockDistribution{
|
||||||
|
@ -173,8 +174,8 @@ func TestStockManager(t *testing.T) {
|
||||||
assert.Equal(t, StockSlice{
|
assert.Equal(t, StockSlice{
|
||||||
{
|
{
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Price: 9200.0,
|
Price: fixedpoint.MustNewFromString("9200.0"),
|
||||||
Quantity: 0.05,
|
Quantity: fixedpoint.MustNewFromString("0.05"),
|
||||||
IsBuyer: false,
|
IsBuyer: false,
|
||||||
},
|
},
|
||||||
}, stockManager.PendingSells)
|
}, stockManager.PendingSells)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
@ -1001,29 +1000,10 @@ func (v Value) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Value) UnmarshalJSON(data []byte) error {
|
func (v *Value) UnmarshalJSON(data []byte) error {
|
||||||
var a interface{}
|
var err error
|
||||||
err := json.Unmarshal(data, &a)
|
if *v, err = NewFromBytes(data); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch d := a.(type) {
|
|
||||||
case float64:
|
|
||||||
*v = NewFromFloat(d)
|
|
||||||
case float32:
|
|
||||||
*v = NewFromFloat(float64(d))
|
|
||||||
case int:
|
|
||||||
*v = NewFromInt(int64(d))
|
|
||||||
case int64:
|
|
||||||
*v = NewFromInt(d)
|
|
||||||
case string:
|
|
||||||
v2, err := NewFromString(d)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*v = v2;
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported type :%T %v", d, d)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,22 @@ func TestNew(t *testing.T) {
|
||||||
assert.Equal(t, "0.10%", f.FormatPercentage(2))
|
assert.Equal(t, "0.10%", f.FormatPercentage(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRound(t *testing.T) {
|
||||||
|
f := NewFromFloat(1.2345)
|
||||||
|
f = f.Round(0, Down)
|
||||||
|
assert.Equal(t, "1", f.String())
|
||||||
|
w := NewFromFloat(1.2345)
|
||||||
|
w = w.Trunc()
|
||||||
|
assert.Equal(t, "1", w.String())
|
||||||
|
s := NewFromFloat(1.2345)
|
||||||
|
assert.Equal(t, "1.23", s.Round(2, Down).String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromString(t *testing.T) {
|
||||||
|
f := MustNewFromString("0.004075")
|
||||||
|
assert.Equal(t, "0.004075", f.String())
|
||||||
|
}
|
||||||
|
|
||||||
// Not used
|
// Not used
|
||||||
/*func TestParse(t *testing.T) {
|
/*func TestParse(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
|
|
|
@ -3,15 +3,17 @@ package indicator
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
// generated from:
|
// generated from:
|
||||||
// 2020/12/05 10:25
|
// 2020/12/05 10:25
|
||||||
// curl -s 'https://www.binance.com/api/v3/klines?symbol=ETHUSDT&interval=5m&endTime=1607135400000&limit=1000' | jq '. | map({ closePrice: (.[4] | tonumber), openTime: .[0] })'
|
// curl -s 'https://www.binance.com/api/v3/klines?symbol=ETHUSDT&interval=5m&endTime=1607135400000&limit=1000' | jq '. | map({ closePrice: (.[4] | tonumber), openTime: .[0] })'
|
||||||
// curl -s 'https://www.binance.com/api/v3/klines?symbol=ETHUSDT&interval=5m&endTime=1607135400000&limit=1000' | jq '. | map(.[4] | tonumber)'
|
// curl -s 'https://www.binance.com/api/v3/klines?symbol=ETHUSDT&interval=5m&endTime=1607135400000&limit=1000' | jq '. | map(.[4] | tonumber)'
|
||||||
var ethusdt5m = []float64{
|
var ethusdt5m = []byte(`[
|
||||||
614.36,
|
614.36,
|
||||||
613.62,
|
613.62,
|
||||||
611.68,
|
611.68,
|
||||||
|
@ -1011,10 +1013,10 @@ var ethusdt5m = []float64{
|
||||||
572.85,
|
572.85,
|
||||||
572.21,
|
572.21,
|
||||||
572.63,
|
572.63,
|
||||||
572.74,
|
572.74
|
||||||
}
|
]`)
|
||||||
|
|
||||||
func buildKLines(prices []float64) (klines []types.KLine) {
|
func buildKLines(prices []fixedpoint.Value) (klines []types.KLine) {
|
||||||
for _, p := range prices {
|
for _, p := range prices {
|
||||||
klines = append(klines, types.KLine{Close: p})
|
klines = append(klines, types.KLine{Close: p})
|
||||||
}
|
}
|
||||||
|
@ -1028,6 +1030,10 @@ func Test_calculateEWMA(t *testing.T) {
|
||||||
priceF KLinePriceMapper
|
priceF KLinePriceMapper
|
||||||
window int
|
window int
|
||||||
}
|
}
|
||||||
|
var input []fixedpoint.Value;
|
||||||
|
if err := json.Unmarshal(ethusdt5m, &input); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
|
@ -1036,7 +1042,7 @@ func Test_calculateEWMA(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "ETHUSDT EMA 7",
|
name: "ETHUSDT EMA 7",
|
||||||
args: args{
|
args: args{
|
||||||
allKLines: buildKLines(ethusdt5m),
|
allKLines: buildKLines(input),
|
||||||
priceF: KLineClosePriceMapper,
|
priceF: KLineClosePriceMapper,
|
||||||
window: 7,
|
window: 7,
|
||||||
},
|
},
|
||||||
|
@ -1045,7 +1051,7 @@ func Test_calculateEWMA(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "ETHUSDT EMA 25",
|
name: "ETHUSDT EMA 25",
|
||||||
args: args{
|
args: args{
|
||||||
allKLines: buildKLines(ethusdt5m),
|
allKLines: buildKLines(input),
|
||||||
priceF: KLineClosePriceMapper,
|
priceF: KLineClosePriceMapper,
|
||||||
window: 25,
|
window: 25,
|
||||||
},
|
},
|
||||||
|
@ -1054,7 +1060,7 @@ func Test_calculateEWMA(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "ETHUSDT EMA 99",
|
name: "ETHUSDT EMA 99",
|
||||||
args: args{
|
args: args{
|
||||||
allKLines: buildKLines(ethusdt5m),
|
allKLines: buildKLines(input),
|
||||||
priceF: KLineClosePriceMapper,
|
priceF: KLineClosePriceMapper,
|
||||||
window: 99,
|
window: 99,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,8 +3,10 @@ package indicator
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -18,7 +20,11 @@ print(fast - slow)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func Test_calculateMACD(t *testing.T) {
|
func Test_calculateMACD(t *testing.T) {
|
||||||
var randomPrices = []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
var randomPrices = []byte(`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`)
|
||||||
|
var input []fixedpoint.Value
|
||||||
|
if err := json.Unmarshal(randomPrices, &input); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
kLines []types.KLine
|
kLines []types.KLine
|
||||||
|
@ -26,7 +32,7 @@ func Test_calculateMACD(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "random_case",
|
name: "random_case",
|
||||||
kLines: buildKLines(randomPrices),
|
kLines: buildKLines(input),
|
||||||
want: 0.7967670223776384,
|
want: 0.7967670223776384,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,11 @@ func (inc *OBV) update(kLine types.KLine, priceF KLinePriceMapper) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var sign float64 = 0.0
|
if volume < inc.PrePrice {
|
||||||
if volume > inc.PrePrice {
|
inc.Values.Push(inc.Last() - volume)
|
||||||
sign = 1.0
|
} else {
|
||||||
} else if volume < inc.PrePrice {
|
inc.Values.Push(inc.Last() + volume)
|
||||||
sign = -1.0
|
|
||||||
}
|
}
|
||||||
obv := inc.Last() + sign*volume
|
|
||||||
inc.Values.Push(obv)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (inc *OBV) Last() float64 {
|
func (inc *OBV) Last() float64 {
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
package indicator
|
package indicator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Delta = 1e-9
|
||||||
|
|
||||||
func Test_calculateOBV(t *testing.T) {
|
func Test_calculateOBV(t *testing.T) {
|
||||||
buildKLines := func(prices, volumes []float64) (kLines []types.KLine) {
|
buildKLines := func(prices, volumes []fixedpoint.Value) (kLines []types.KLine) {
|
||||||
for i, p := range prices {
|
for i, p := range prices {
|
||||||
kLines = append(kLines, types.KLine{High: p, Low: p, Close: p, Volume: volumes[i]})
|
kLines = append(kLines, types.KLine{High: p, Low: p, Close: p, Volume: volumes[i]})
|
||||||
}
|
}
|
||||||
return kLines
|
return kLines
|
||||||
}
|
}
|
||||||
|
var easy1 = []byte(`[3, 2, 1, 4]`)
|
||||||
|
var easy2 = []byte(`[3, 2, 2, 6]`)
|
||||||
|
var input1 []fixedpoint.Value
|
||||||
|
var input2 []fixedpoint.Value
|
||||||
|
_ = json.Unmarshal(easy1, &input1)
|
||||||
|
_ = json.Unmarshal(easy2, &input2)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -23,13 +34,15 @@ func Test_calculateOBV(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "trivial_case",
|
name: "trivial_case",
|
||||||
kLines: buildKLines([]float64{0}, []float64{1}),
|
kLines: buildKLines(
|
||||||
|
[]fixedpoint.Value{fixedpoint.Zero}, []fixedpoint.Value{fixedpoint.One},
|
||||||
|
),
|
||||||
window: 0,
|
window: 0,
|
||||||
want: types.Float64Slice{1.0},
|
want: types.Float64Slice{1.0},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "easy_case",
|
name: "easy_case",
|
||||||
kLines: buildKLines([]float64{3, 2, 1, 4}, []float64{3, 2, 2, 6}),
|
kLines: buildKLines(input1, input2),
|
||||||
window: 0,
|
window: 0,
|
||||||
want: types.Float64Slice{3, 1, -1, 5},
|
want: types.Float64Slice{3, 1, -1, 5},
|
||||||
},
|
},
|
||||||
|
@ -39,8 +52,9 @@ func Test_calculateOBV(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
obv := OBV{IntervalWindow: types.IntervalWindow{Window: tt.window}}
|
obv := OBV{IntervalWindow: types.IntervalWindow{Window: tt.window}}
|
||||||
obv.calculateAndUpdate(tt.kLines)
|
obv.calculateAndUpdate(tt.kLines)
|
||||||
if !reflect.DeepEqual(obv.Values, tt.want) {
|
assert.Equal(t, len(obv.Values), len(tt.want))
|
||||||
t.Errorf("calculateAndUpdate() = %v, want %v", obv.Values, tt.want)
|
for i, v := range(obv.Values) {
|
||||||
|
assert.InDelta(t, v, tt.want[i], Delta)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -18,17 +20,22 @@ df = pd.DataFrame(klines, columns=['open', 'high', 'low', 'close', 'volume'])
|
||||||
print(df.ta.stoch(df['high'], df['low'], df['close'], k=14, d=3, smooth_k=1))
|
print(df.ta.stoch(df['high'], df['low'], df['close'], k=14, d=3, smooth_k=1))
|
||||||
*/
|
*/
|
||||||
func TestSTOCH_update(t *testing.T) {
|
func TestSTOCH_update(t *testing.T) {
|
||||||
open := []float64{8273.0, 8280.0, 8280.0, 8275.0, 8281.0, 8277.0, 8279.0, 8280.0, 8284.0, 8286.0, 8283.0, 8283.0, 8284.0, 8286.0, 8285.0, 8287.0, 8289.0, 8282.0, 8286.0, 8279.0, 8275.0, 8276.0, 8276.0, 8281.0, 8269.0, 8256.0, 8258.0, 8252.0, 8241.0, 8232.0, 8218.0, 8221.0, 8216.0, 8210.0, 8212.0, 8201.0, 8197.0, 8200.0, 8193.0, 8181.0, 8185.0, 8190.0, 8184.0, 8185.0, 8163.0, 8153.0, 8162.0, 8165.0, 8162.0, 8157.0, 8159.0, 8141.0, 8140.0, 8141.0, 8130.0, 8144.0, 8141.0, 8148.0, 8145.0, 8134.0, 8123.0, 8127.0, 8130.0, 8125.0, 8122.0, 8105.0, 8096.0, 8103.0, 8102.0, 8110.0, 8104.0, 8109.0, 8103.0, 8111.0, 8112.0, 8109.0, 8092.0, 8100.0, 8101.0, 8100.0, 8096.0, 8095.0, 8094.0, 8101.0, 8095.0, 8069.0, 8067.0, 8070.0, 8069.0, 8066.0, 8047.0, 8046.0, 8042.0, 8039.0, 8049.0, 8055.0, 8063.0, 8061.0, 8056.0, 8057.0, 8056.0, 8057.0, 8057.0, 8054.0, 8056.0, 8056.0, 8065.0, 8065.0, 8070.0, 8065.0, 8064.0, 8063.0, 8060.0, 8065.0, 8068.0, 8068.0, 8069.0, 8073.0, 8073.0, 8084.0, 8084.0, 8076.0, 8074.0, 8074.0, 8074.0, 8078.0, 8080.0, 8082.0, 8085.0, 8083.0, 8087.0, 8087.0, 8083.0, 8083.0, 8082.0, 8074.0, 8074.0, 8071.0, 8071.0, 8072.0, 8075.0, 8075.0, 8076.0, 8073.0, 8071.0, 8070.0, 8075.0, 8078.0, 8077.0, 8075.0, 8073.0, 8079.0, 8084.0, 8082.0, 8085.0, 8085.0, 8085.0, 8101.0, 8106.0, 8113.0, 8109.0, 8104.0, 8105.0, 8105.0, 8107.0, 8106.0, 8104.0, 8106.0, 8106.0, 8110.0, 8107.0, 8110.0, 8111.0, 8104.0, 8098.0, 8098.0, 8098.0, 8098.0, 8094.0, 8097.0, 8096.0, 8099.0, 8098.0, 8099.0, 8098.0, 8095.0, 8096.0, 8086.0, 8088.0, 8093.0, 8092.0, 8096.0, 8100.0, 8104.0, 8104.0, 8108.0, 8107.0, 8103.0, 8104.0, 8110.0, 8105.0, 8102.0, 8104.0, 8096.0, 8099.0, 8103.0, 8102.0, 8108.0, 8107.0, 8107.0, 8104.0, 8095.0, 8091.0, 8092.0, 8090.0, 8093.0, 8093.0, 8094.0, 8095.0, 8096.0, 8088.0, 8090.0, 8079.0, 8077.0, 8079.0, 8081.0, 8083.0, 8084.0, 8084.0, 8087.0, 8091.0, 8089.0, 8089.0, 8091.0, 8087.0, 8093.0, 8090.0, 8090.0, 8095.0, 8093.0, 8088.0, 8087.0, 8090.0, 8089.0, 8087.0, 8084.0, 8087.0, 8084.0, 8080.0, 8078.0, 8077.0, 8077.0, 8076.0, 8072.0, 8072.0, 8075.0, 8076.0, 8074.0, 8077.0, 8081.0, 8080.0, 8076.0, 8075.0, 8077.0, 8080.0, 8077.0, 8076.0, 8076.0, 8070.0, 8071.0, 8070.0, 8073.0, 8069.0, 8069.0, 8068.0, 8072.0, 8078.0, 8077.0, 8079.0, 8081.0, 8076.0, 8076.0, 8077.0, 8077.0, 8078.0, 8075.0, 8066.0, 8064.0, 8064.0, 8062.0, 8062.0, 8065.0, 8062.0, 8063.0, 8074.0, 8070.0, 8069.0, 8068.0, 8074.0, 8075.0}
|
open := []byte(`[8273.0, 8280.0, 8280.0, 8275.0, 8281.0, 8277.0, 8279.0, 8280.0, 8284.0, 8286.0, 8283.0, 8283.0, 8284.0, 8286.0, 8285.0, 8287.0, 8289.0, 8282.0, 8286.0, 8279.0, 8275.0, 8276.0, 8276.0, 8281.0, 8269.0, 8256.0, 8258.0, 8252.0, 8241.0, 8232.0, 8218.0, 8221.0, 8216.0, 8210.0, 8212.0, 8201.0, 8197.0, 8200.0, 8193.0, 8181.0, 8185.0, 8190.0, 8184.0, 8185.0, 8163.0, 8153.0, 8162.0, 8165.0, 8162.0, 8157.0, 8159.0, 8141.0, 8140.0, 8141.0, 8130.0, 8144.0, 8141.0, 8148.0, 8145.0, 8134.0, 8123.0, 8127.0, 8130.0, 8125.0, 8122.0, 8105.0, 8096.0, 8103.0, 8102.0, 8110.0, 8104.0, 8109.0, 8103.0, 8111.0, 8112.0, 8109.0, 8092.0, 8100.0, 8101.0, 8100.0, 8096.0, 8095.0, 8094.0, 8101.0, 8095.0, 8069.0, 8067.0, 8070.0, 8069.0, 8066.0, 8047.0, 8046.0, 8042.0, 8039.0, 8049.0, 8055.0, 8063.0, 8061.0, 8056.0, 8057.0, 8056.0, 8057.0, 8057.0, 8054.0, 8056.0, 8056.0, 8065.0, 8065.0, 8070.0, 8065.0, 8064.0, 8063.0, 8060.0, 8065.0, 8068.0, 8068.0, 8069.0, 8073.0, 8073.0, 8084.0, 8084.0, 8076.0, 8074.0, 8074.0, 8074.0, 8078.0, 8080.0, 8082.0, 8085.0, 8083.0, 8087.0, 8087.0, 8083.0, 8083.0, 8082.0, 8074.0, 8074.0, 8071.0, 8071.0, 8072.0, 8075.0, 8075.0, 8076.0, 8073.0, 8071.0, 8070.0, 8075.0, 8078.0, 8077.0, 8075.0, 8073.0, 8079.0, 8084.0, 8082.0, 8085.0, 8085.0, 8085.0, 8101.0, 8106.0, 8113.0, 8109.0, 8104.0, 8105.0, 8105.0, 8107.0, 8106.0, 8104.0, 8106.0, 8106.0, 8110.0, 8107.0, 8110.0, 8111.0, 8104.0, 8098.0, 8098.0, 8098.0, 8098.0, 8094.0, 8097.0, 8096.0, 8099.0, 8098.0, 8099.0, 8098.0, 8095.0, 8096.0, 8086.0, 8088.0, 8093.0, 8092.0, 8096.0, 8100.0, 8104.0, 8104.0, 8108.0, 8107.0, 8103.0, 8104.0, 8110.0, 8105.0, 8102.0, 8104.0, 8096.0, 8099.0, 8103.0, 8102.0, 8108.0, 8107.0, 8107.0, 8104.0, 8095.0, 8091.0, 8092.0, 8090.0, 8093.0, 8093.0, 8094.0, 8095.0, 8096.0, 8088.0, 8090.0, 8079.0, 8077.0, 8079.0, 8081.0, 8083.0, 8084.0, 8084.0, 8087.0, 8091.0, 8089.0, 8089.0, 8091.0, 8087.0, 8093.0, 8090.0, 8090.0, 8095.0, 8093.0, 8088.0, 8087.0, 8090.0, 8089.0, 8087.0, 8084.0, 8087.0, 8084.0, 8080.0, 8078.0, 8077.0, 8077.0, 8076.0, 8072.0, 8072.0, 8075.0, 8076.0, 8074.0, 8077.0, 8081.0, 8080.0, 8076.0, 8075.0, 8077.0, 8080.0, 8077.0, 8076.0, 8076.0, 8070.0, 8071.0, 8070.0, 8073.0, 8069.0, 8069.0, 8068.0, 8072.0, 8078.0, 8077.0, 8079.0, 8081.0, 8076.0, 8076.0, 8077.0, 8077.0, 8078.0, 8075.0, 8066.0, 8064.0, 8064.0, 8062.0, 8062.0, 8065.0, 8062.0, 8063.0, 8074.0, 8070.0, 8069.0, 8068.0, 8074.0, 8075.0]`)
|
||||||
high := []float64{8279.0, 8282.0, 8280.0, 8280.0, 8284.0, 8284.0, 8280.0, 8282.0, 8284.0, 8289.0, 8288.0, 8285.0, 8284.0, 8287.0, 8286.0, 8294.0, 8290.0, 8292.0, 8289.0, 8288.0, 8278.0, 8279.0, 8279.0, 8284.0, 8282.0, 8270.0, 8261.0, 8260.0, 8252.0, 8244.0, 8233.0, 8227.0, 8222.0, 8217.0, 8217.0, 8211.0, 8202.0, 8203.0, 8203.0, 8196.0, 8186.0, 8193.0, 8194.0, 8187.0, 8185.0, 8168.0, 8165.0, 8169.0, 8166.0, 8163.0, 8162.0, 8159.0, 8143.0, 8148.0, 8143.0, 8146.0, 8152.0, 8149.0, 8152.0, 8147.0, 8138.0, 8128.0, 8134.0, 8131.0, 8133.0, 8123.0, 8106.0, 8105.0, 8104.0, 8113.0, 8112.0, 8112.0, 8111.0, 8114.0, 8115.0, 8114.0, 8110.0, 8101.0, 8107.0, 8103.0, 8100.0, 8101.0, 8100.0, 8102.0, 8101.0, 8100.0, 8070.0, 8076.0, 8072.0, 8072.0, 8069.0, 8050.0, 8048.0, 8044.0, 8049.0, 8055.0, 8063.0, 8070.0, 8067.0, 8061.0, 8059.0, 8060.0, 8063.0, 8058.0, 8061.0, 8061.0, 8068.0, 8066.0, 8071.0, 8073.0, 8068.0, 8066.0, 8066.0, 8065.0, 8070.0, 8072.0, 8072.0, 8075.0, 8078.0, 8084.0, 8085.0, 8084.0, 8077.0, 8076.0, 8075.0, 8079.0, 8081.0, 8083.0, 8088.0, 8086.0, 8088.0, 8088.0, 8092.0, 8086.0, 8086.0, 8083.0, 8075.0, 8074.0, 8073.0, 8073.0, 8077.0, 8077.0, 8078.0, 8077.0, 8076.0, 8073.0, 8075.0, 8079.0, 8079.0, 8078.0, 8074.0, 8080.0, 8086.0, 8086.0, 8085.0, 8085.0, 8087.0, 8102.0, 8109.0, 8113.0, 8114.0, 8110.0, 8105.0, 8106.0, 8109.0, 8114.0, 8107.0, 8106.0, 8106.0, 8110.0, 8111.0, 8110.0, 8112.0, 8112.0, 8109.0, 8102.0, 8098.0, 8099.0, 8098.0, 8097.0, 8099.0, 8099.0, 8099.0, 8102.0, 8099.0, 8099.0, 8096.0, 8097.0, 8091.0, 8094.0, 8094.0, 8096.0, 8102.0, 8106.0, 8109.0, 8109.0, 8110.0, 8108.0, 8106.0, 8110.0, 8122.0, 8105.0, 8105.0, 8104.0, 8103.0, 8104.0, 8103.0, 8110.0, 8110.0, 8107.0, 8109.0, 8105.0, 8097.0, 8095.0, 8093.0, 8094.0, 8097.0, 8096.0, 8096.0, 8096.0, 8097.0, 8092.0, 8090.0, 8081.0, 8081.0, 8083.0, 8087.0, 8085.0, 8085.0, 8087.0, 8092.0, 8094.0, 8090.0, 8093.0, 8092.0, 8094.0, 8093.0, 8091.0, 8095.0, 8095.0, 8092.0, 8089.0, 8090.0, 8090.0, 8091.0, 8088.0, 8089.0, 8089.0, 8085.0, 8081.0, 8080.0, 8078.0, 8078.0, 8076.0, 8073.0, 8077.0, 8078.0, 8077.0, 8077.0, 8083.0, 8082.0, 8082.0, 8077.0, 8079.0, 8082.0, 8080.0, 8077.0, 8078.0, 8076.0, 8073.0, 8074.0, 8073.0, 8073.0, 8070.0, 8070.0, 8072.0, 8079.0, 8078.0, 8079.0, 8081.0, 8083.0, 8077.0, 8078.0, 8080.0, 8079.0, 8080.0, 8077.0, 8069.0, 8071.0, 8066.0, 8064.0, 8066.0, 8066.0, 8063.0, 8074.0, 8075.0, 8071.0, 8070.0, 8075.0, 8075.0}
|
high := []byte(`[8279.0, 8282.0, 8280.0, 8280.0, 8284.0, 8284.0, 8280.0, 8282.0, 8284.0, 8289.0, 8288.0, 8285.0, 8284.0, 8287.0, 8286.0, 8294.0, 8290.0, 8292.0, 8289.0, 8288.0, 8278.0, 8279.0, 8279.0, 8284.0, 8282.0, 8270.0, 8261.0, 8260.0, 8252.0, 8244.0, 8233.0, 8227.0, 8222.0, 8217.0, 8217.0, 8211.0, 8202.0, 8203.0, 8203.0, 8196.0, 8186.0, 8193.0, 8194.0, 8187.0, 8185.0, 8168.0, 8165.0, 8169.0, 8166.0, 8163.0, 8162.0, 8159.0, 8143.0, 8148.0, 8143.0, 8146.0, 8152.0, 8149.0, 8152.0, 8147.0, 8138.0, 8128.0, 8134.0, 8131.0, 8133.0, 8123.0, 8106.0, 8105.0, 8104.0, 8113.0, 8112.0, 8112.0, 8111.0, 8114.0, 8115.0, 8114.0, 8110.0, 8101.0, 8107.0, 8103.0, 8100.0, 8101.0, 8100.0, 8102.0, 8101.0, 8100.0, 8070.0, 8076.0, 8072.0, 8072.0, 8069.0, 8050.0, 8048.0, 8044.0, 8049.0, 8055.0, 8063.0, 8070.0, 8067.0, 8061.0, 8059.0, 8060.0, 8063.0, 8058.0, 8061.0, 8061.0, 8068.0, 8066.0, 8071.0, 8073.0, 8068.0, 8066.0, 8066.0, 8065.0, 8070.0, 8072.0, 8072.0, 8075.0, 8078.0, 8084.0, 8085.0, 8084.0, 8077.0, 8076.0, 8075.0, 8079.0, 8081.0, 8083.0, 8088.0, 8086.0, 8088.0, 8088.0, 8092.0, 8086.0, 8086.0, 8083.0, 8075.0, 8074.0, 8073.0, 8073.0, 8077.0, 8077.0, 8078.0, 8077.0, 8076.0, 8073.0, 8075.0, 8079.0, 8079.0, 8078.0, 8074.0, 8080.0, 8086.0, 8086.0, 8085.0, 8085.0, 8087.0, 8102.0, 8109.0, 8113.0, 8114.0, 8110.0, 8105.0, 8106.0, 8109.0, 8114.0, 8107.0, 8106.0, 8106.0, 8110.0, 8111.0, 8110.0, 8112.0, 8112.0, 8109.0, 8102.0, 8098.0, 8099.0, 8098.0, 8097.0, 8099.0, 8099.0, 8099.0, 8102.0, 8099.0, 8099.0, 8096.0, 8097.0, 8091.0, 8094.0, 8094.0, 8096.0, 8102.0, 8106.0, 8109.0, 8109.0, 8110.0, 8108.0, 8106.0, 8110.0, 8122.0, 8105.0, 8105.0, 8104.0, 8103.0, 8104.0, 8103.0, 8110.0, 8110.0, 8107.0, 8109.0, 8105.0, 8097.0, 8095.0, 8093.0, 8094.0, 8097.0, 8096.0, 8096.0, 8096.0, 8097.0, 8092.0, 8090.0, 8081.0, 8081.0, 8083.0, 8087.0, 8085.0, 8085.0, 8087.0, 8092.0, 8094.0, 8090.0, 8093.0, 8092.0, 8094.0, 8093.0, 8091.0, 8095.0, 8095.0, 8092.0, 8089.0, 8090.0, 8090.0, 8091.0, 8088.0, 8089.0, 8089.0, 8085.0, 8081.0, 8080.0, 8078.0, 8078.0, 8076.0, 8073.0, 8077.0, 8078.0, 8077.0, 8077.0, 8083.0, 8082.0, 8082.0, 8077.0, 8079.0, 8082.0, 8080.0, 8077.0, 8078.0, 8076.0, 8073.0, 8074.0, 8073.0, 8073.0, 8070.0, 8070.0, 8072.0, 8079.0, 8078.0, 8079.0, 8081.0, 8083.0, 8077.0, 8078.0, 8080.0, 8079.0, 8080.0, 8077.0, 8069.0, 8071.0, 8066.0, 8064.0, 8066.0, 8066.0, 8063.0, 8074.0, 8075.0, 8071.0, 8070.0, 8075.0, 8075.0]`)
|
||||||
low := []float64{8260.0, 8272.0, 8275.0, 8274.0, 8275.0, 8277.0, 8276.0, 8278.0, 8277.0, 8283.0, 8282.0, 8283.0, 8283.0, 8283.0, 8283.0, 8279.0, 8281.0, 8282.0, 8277.0, 8276.0, 8273.0, 8275.0, 8274.0, 8275.0, 8266.0, 8256.0, 8255.0, 8250.0, 8239.0, 8230.0, 8214.0, 8218.0, 8216.0, 8208.0, 8209.0, 8201.0, 8190.0, 8195.0, 8193.0, 8181.0, 8175.0, 8183.0, 8182.0, 8181.0, 8159.0, 8152.0, 8150.0, 8160.0, 8161.0, 8153.0, 8153.0, 8137.0, 8135.0, 8139.0, 8130.0, 8130.0, 8140.0, 8137.0, 8145.0, 8134.0, 8123.0, 8116.0, 8122.0, 8124.0, 8122.0, 8105.0, 8096.0, 8096.0, 8097.0, 8100.0, 8100.0, 8104.0, 8101.0, 8103.0, 8109.0, 8108.0, 8089.0, 8092.0, 8097.0, 8098.0, 8094.0, 8092.0, 8087.0, 8094.0, 8094.0, 8069.0, 8058.0, 8065.0, 8066.0, 8065.0, 8046.0, 8041.0, 8036.0, 8038.0, 8039.0, 8047.0, 8053.0, 8058.0, 8056.0, 8056.0, 8053.0, 8052.0, 8054.0, 8051.0, 8053.0, 8056.0, 8055.0, 8063.0, 8064.0, 8063.0, 8062.0, 8061.0, 8059.0, 8059.0, 8063.0, 8066.0, 8067.0, 8068.0, 8071.0, 8071.0, 8079.0, 8074.0, 8073.0, 8074.0, 8073.0, 8073.0, 8076.0, 8079.0, 8080.0, 8083.0, 8083.0, 8085.0, 8082.0, 8082.0, 8081.0, 8072.0, 8072.0, 8068.0, 8070.0, 8070.0, 8072.0, 8074.0, 8075.0, 8073.0, 8071.0, 8070.0, 8067.0, 8074.0, 8076.0, 8072.0, 8070.0, 8072.0, 8079.0, 8081.0, 8082.0, 8082.0, 8084.0, 8083.0, 8097.0, 8103.0, 8107.0, 8104.0, 8103.0, 8104.0, 8103.0, 8105.0, 8103.0, 8102.0, 8102.0, 8103.0, 8106.0, 8107.0, 8108.0, 8102.0, 8098.0, 8096.0, 8095.0, 8096.0, 8093.0, 8094.0, 8094.0, 8096.0, 8097.0, 8097.0, 8096.0, 8094.0, 8094.0, 8086.0, 8086.0, 8087.0, 8090.0, 8091.0, 8095.0, 8099.0, 8104.0, 8102.0, 8106.0, 8101.0, 8103.0, 8104.0, 8104.0, 8101.0, 8102.0, 8096.0, 8096.0, 8098.0, 8100.0, 8102.0, 8106.0, 8103.0, 8103.0, 8094.0, 8090.0, 8090.0, 8089.0, 8088.0, 8090.0, 8093.0, 8094.0, 8094.0, 8088.0, 8087.0, 8079.0, 8075.0, 8076.0, 8077.0, 8081.0, 8083.0, 8083.0, 8084.0, 8087.0, 8089.0, 8088.0, 8088.0, 8086.0, 8087.0, 8090.0, 8088.0, 8090.0, 8091.0, 8087.0, 8087.0, 8086.0, 8088.0, 8087.0, 8082.0, 8083.0, 8083.0, 8078.0, 8077.0, 8077.0, 8072.0, 8074.0, 8071.0, 8070.0, 8072.0, 8073.0, 8073.0, 8072.0, 8076.0, 8079.0, 8075.0, 8075.0, 8075.0, 8076.0, 8076.0, 8074.0, 8076.0, 8069.0, 8068.0, 8069.0, 8069.0, 8065.0, 8067.0, 8067.0, 8067.0, 8073.0, 8075.0, 8076.0, 8077.0, 8075.0, 8072.0, 8074.0, 8075.0, 8074.0, 8072.0, 8066.0, 8063.0, 8062.0, 8058.0, 8060.0, 8059.0, 8060.0, 8059.0, 8062.0, 8067.0, 8068.0, 8067.0, 8068.0, 8071.0}
|
low := []byte(`[8260.0, 8272.0, 8275.0, 8274.0, 8275.0, 8277.0, 8276.0, 8278.0, 8277.0, 8283.0, 8282.0, 8283.0, 8283.0, 8283.0, 8283.0, 8279.0, 8281.0, 8282.0, 8277.0, 8276.0, 8273.0, 8275.0, 8274.0, 8275.0, 8266.0, 8256.0, 8255.0, 8250.0, 8239.0, 8230.0, 8214.0, 8218.0, 8216.0, 8208.0, 8209.0, 8201.0, 8190.0, 8195.0, 8193.0, 8181.0, 8175.0, 8183.0, 8182.0, 8181.0, 8159.0, 8152.0, 8150.0, 8160.0, 8161.0, 8153.0, 8153.0, 8137.0, 8135.0, 8139.0, 8130.0, 8130.0, 8140.0, 8137.0, 8145.0, 8134.0, 8123.0, 8116.0, 8122.0, 8124.0, 8122.0, 8105.0, 8096.0, 8096.0, 8097.0, 8100.0, 8100.0, 8104.0, 8101.0, 8103.0, 8109.0, 8108.0, 8089.0, 8092.0, 8097.0, 8098.0, 8094.0, 8092.0, 8087.0, 8094.0, 8094.0, 8069.0, 8058.0, 8065.0, 8066.0, 8065.0, 8046.0, 8041.0, 8036.0, 8038.0, 8039.0, 8047.0, 8053.0, 8058.0, 8056.0, 8056.0, 8053.0, 8052.0, 8054.0, 8051.0, 8053.0, 8056.0, 8055.0, 8063.0, 8064.0, 8063.0, 8062.0, 8061.0, 8059.0, 8059.0, 8063.0, 8066.0, 8067.0, 8068.0, 8071.0, 8071.0, 8079.0, 8074.0, 8073.0, 8074.0, 8073.0, 8073.0, 8076.0, 8079.0, 8080.0, 8083.0, 8083.0, 8085.0, 8082.0, 8082.0, 8081.0, 8072.0, 8072.0, 8068.0, 8070.0, 8070.0, 8072.0, 8074.0, 8075.0, 8073.0, 8071.0, 8070.0, 8067.0, 8074.0, 8076.0, 8072.0, 8070.0, 8072.0, 8079.0, 8081.0, 8082.0, 8082.0, 8084.0, 8083.0, 8097.0, 8103.0, 8107.0, 8104.0, 8103.0, 8104.0, 8103.0, 8105.0, 8103.0, 8102.0, 8102.0, 8103.0, 8106.0, 8107.0, 8108.0, 8102.0, 8098.0, 8096.0, 8095.0, 8096.0, 8093.0, 8094.0, 8094.0, 8096.0, 8097.0, 8097.0, 8096.0, 8094.0, 8094.0, 8086.0, 8086.0, 8087.0, 8090.0, 8091.0, 8095.0, 8099.0, 8104.0, 8102.0, 8106.0, 8101.0, 8103.0, 8104.0, 8104.0, 8101.0, 8102.0, 8096.0, 8096.0, 8098.0, 8100.0, 8102.0, 8106.0, 8103.0, 8103.0, 8094.0, 8090.0, 8090.0, 8089.0, 8088.0, 8090.0, 8093.0, 8094.0, 8094.0, 8088.0, 8087.0, 8079.0, 8075.0, 8076.0, 8077.0, 8081.0, 8083.0, 8083.0, 8084.0, 8087.0, 8089.0, 8088.0, 8088.0, 8086.0, 8087.0, 8090.0, 8088.0, 8090.0, 8091.0, 8087.0, 8087.0, 8086.0, 8088.0, 8087.0, 8082.0, 8083.0, 8083.0, 8078.0, 8077.0, 8077.0, 8072.0, 8074.0, 8071.0, 8070.0, 8072.0, 8073.0, 8073.0, 8072.0, 8076.0, 8079.0, 8075.0, 8075.0, 8075.0, 8076.0, 8076.0, 8074.0, 8076.0, 8069.0, 8068.0, 8069.0, 8069.0, 8065.0, 8067.0, 8067.0, 8067.0, 8073.0, 8075.0, 8076.0, 8077.0, 8075.0, 8072.0, 8074.0, 8075.0, 8074.0, 8072.0, 8066.0, 8063.0, 8062.0, 8058.0, 8060.0, 8059.0, 8060.0, 8059.0, 8062.0, 8067.0, 8068.0, 8067.0, 8068.0, 8071.0]`)
|
||||||
close := []float64{8262.0, 8273.0, 8279.0, 8279.0, 8275.0, 8282.0, 8278.0, 8279.0, 8281.0, 8285.0, 8287.0, 8284.0, 8283.0, 8283.0, 8285.0, 8286.0, 8287.0, 8290.0, 8283.0, 8287.0, 8278.0, 8275.0, 8276.0, 8275.0, 8281.0, 8270.0, 8257.0, 8258.0, 8252.0, 8243.0, 8231.0, 8219.0, 8220.0, 8216.0, 8210.0, 8211.0, 8201.0, 8197.0, 8201.0, 8193.0, 8183.0, 8184.0, 8191.0, 8184.0, 8185.0, 8161.0, 8154.0, 8163.0, 8164.0, 8162.0, 8156.0, 8158.0, 8141.0, 8139.0, 8142.0, 8130.0, 8145.0, 8140.0, 8149.0, 8146.0, 8136.0, 8123.0, 8126.0, 8130.0, 8125.0, 8122.0, 8106.0, 8096.0, 8103.0, 8102.0, 8111.0, 8105.0, 8111.0, 8103.0, 8112.0, 8113.0, 8109.0, 8093.0, 8101.0, 8101.0, 8100.0, 8095.0, 8096.0, 8095.0, 8100.0, 8095.0, 8069.0, 8068.0, 8072.0, 8068.0, 8067.0, 8046.0, 8045.0, 8043.0, 8040.0, 8049.0, 8055.0, 8062.0, 8062.0, 8058.0, 8056.0, 8055.0, 8058.0, 8057.0, 8054.0, 8056.0, 8057.0, 8066.0, 8065.0, 8069.0, 8064.0, 8063.0, 8064.0, 8059.0, 8065.0, 8069.0, 8068.0, 8069.0, 8072.0, 8074.0, 8084.0, 8084.0, 8076.0, 8074.0, 8074.0, 8075.0, 8077.0, 8080.0, 8082.0, 8086.0, 8084.0, 8087.0, 8087.0, 8083.0, 8083.0, 8082.0, 8074.0, 8073.0, 8072.0, 8071.0, 8072.0, 8075.0, 8076.0, 8076.0, 8074.0, 8071.0, 8071.0, 8075.0, 8079.0, 8077.0, 8074.0, 8072.0, 8079.0, 8084.0, 8082.0, 8085.0, 8086.0, 8084.0, 8102.0, 8107.0, 8113.0, 8109.0, 8104.0, 8104.0, 8105.0, 8108.0, 8106.0, 8104.0, 8106.0, 8105.0, 8110.0, 8107.0, 8109.0, 8112.0, 8104.0, 8099.0, 8097.0, 8097.0, 8098.0, 8095.0, 8096.0, 8097.0, 8099.0, 8098.0, 8099.0, 8099.0, 8095.0, 8097.0, 8086.0, 8088.0, 8093.0, 8092.0, 8096.0, 8101.0, 8105.0, 8105.0, 8109.0, 8107.0, 8103.0, 8104.0, 8109.0, 8105.0, 8102.0, 8104.0, 8097.0, 8100.0, 8103.0, 8103.0, 8109.0, 8107.0, 8106.0, 8104.0, 8096.0, 8090.0, 8092.0, 8089.0, 8093.0, 8093.0, 8094.0, 8095.0, 8096.0, 8088.0, 8089.0, 8079.0, 8077.0, 8079.0, 8082.0, 8083.0, 8084.0, 8084.0, 8087.0, 8091.0, 8088.0, 8088.0, 8091.0, 8087.0, 8092.0, 8090.0, 8091.0, 8095.0, 8092.0, 8088.0, 8087.0, 8090.0, 8089.0, 8087.0, 8084.0, 8088.0, 8084.0, 8079.0, 8078.0, 8078.0, 8076.0, 8075.0, 8071.0, 8072.0, 8074.0, 8077.0, 8074.0, 8077.0, 8081.0, 8080.0, 8076.0, 8076.0, 8078.0, 8079.0, 8076.0, 8076.0, 8076.0, 8070.0, 8072.0, 8069.0, 8072.0, 8070.0, 8069.0, 8069.0, 8073.0, 8078.0, 8077.0, 8079.0, 8080.0, 8076.0, 8076.0, 8076.0, 8077.0, 8078.0, 8075.0, 8067.0, 8064.0, 8064.0, 8062.0, 8062.0, 8065.0, 8062.0, 8063.0, 8074.0, 8070.0, 8069.0, 8068.0, 8074.0}
|
close := []byte(`[8262.0, 8273.0, 8279.0, 8279.0, 8275.0, 8282.0, 8278.0, 8279.0, 8281.0, 8285.0, 8287.0, 8284.0, 8283.0, 8283.0, 8285.0, 8286.0, 8287.0, 8290.0, 8283.0, 8287.0, 8278.0, 8275.0, 8276.0, 8275.0, 8281.0, 8270.0, 8257.0, 8258.0, 8252.0, 8243.0, 8231.0, 8219.0, 8220.0, 8216.0, 8210.0, 8211.0, 8201.0, 8197.0, 8201.0, 8193.0, 8183.0, 8184.0, 8191.0, 8184.0, 8185.0, 8161.0, 8154.0, 8163.0, 8164.0, 8162.0, 8156.0, 8158.0, 8141.0, 8139.0, 8142.0, 8130.0, 8145.0, 8140.0, 8149.0, 8146.0, 8136.0, 8123.0, 8126.0, 8130.0, 8125.0, 8122.0, 8106.0, 8096.0, 8103.0, 8102.0, 8111.0, 8105.0, 8111.0, 8103.0, 8112.0, 8113.0, 8109.0, 8093.0, 8101.0, 8101.0, 8100.0, 8095.0, 8096.0, 8095.0, 8100.0, 8095.0, 8069.0, 8068.0, 8072.0, 8068.0, 8067.0, 8046.0, 8045.0, 8043.0, 8040.0, 8049.0, 8055.0, 8062.0, 8062.0, 8058.0, 8056.0, 8055.0, 8058.0, 8057.0, 8054.0, 8056.0, 8057.0, 8066.0, 8065.0, 8069.0, 8064.0, 8063.0, 8064.0, 8059.0, 8065.0, 8069.0, 8068.0, 8069.0, 8072.0, 8074.0, 8084.0, 8084.0, 8076.0, 8074.0, 8074.0, 8075.0, 8077.0, 8080.0, 8082.0, 8086.0, 8084.0, 8087.0, 8087.0, 8083.0, 8083.0, 8082.0, 8074.0, 8073.0, 8072.0, 8071.0, 8072.0, 8075.0, 8076.0, 8076.0, 8074.0, 8071.0, 8071.0, 8075.0, 8079.0, 8077.0, 8074.0, 8072.0, 8079.0, 8084.0, 8082.0, 8085.0, 8086.0, 8084.0, 8102.0, 8107.0, 8113.0, 8109.0, 8104.0, 8104.0, 8105.0, 8108.0, 8106.0, 8104.0, 8106.0, 8105.0, 8110.0, 8107.0, 8109.0, 8112.0, 8104.0, 8099.0, 8097.0, 8097.0, 8098.0, 8095.0, 8096.0, 8097.0, 8099.0, 8098.0, 8099.0, 8099.0, 8095.0, 8097.0, 8086.0, 8088.0, 8093.0, 8092.0, 8096.0, 8101.0, 8105.0, 8105.0, 8109.0, 8107.0, 8103.0, 8104.0, 8109.0, 8105.0, 8102.0, 8104.0, 8097.0, 8100.0, 8103.0, 8103.0, 8109.0, 8107.0, 8106.0, 8104.0, 8096.0, 8090.0, 8092.0, 8089.0, 8093.0, 8093.0, 8094.0, 8095.0, 8096.0, 8088.0, 8089.0, 8079.0, 8077.0, 8079.0, 8082.0, 8083.0, 8084.0, 8084.0, 8087.0, 8091.0, 8088.0, 8088.0, 8091.0, 8087.0, 8092.0, 8090.0, 8091.0, 8095.0, 8092.0, 8088.0, 8087.0, 8090.0, 8089.0, 8087.0, 8084.0, 8088.0, 8084.0, 8079.0, 8078.0, 8078.0, 8076.0, 8075.0, 8071.0, 8072.0, 8074.0, 8077.0, 8074.0, 8077.0, 8081.0, 8080.0, 8076.0, 8076.0, 8078.0, 8079.0, 8076.0, 8076.0, 8076.0, 8070.0, 8072.0, 8069.0, 8072.0, 8070.0, 8069.0, 8069.0, 8073.0, 8078.0, 8077.0, 8079.0, 8080.0, 8076.0, 8076.0, 8076.0, 8077.0, 8078.0, 8075.0, 8067.0, 8064.0, 8064.0, 8062.0, 8062.0, 8065.0, 8062.0, 8063.0, 8074.0, 8070.0, 8069.0, 8068.0, 8074.0]`)
|
||||||
|
|
||||||
buildKLines := func(open, high, low, close []float64) (kLines []types.KLine) {
|
buildKLines := func(open, high, low, close []fixedpoint.Value) (kLines []types.KLine) {
|
||||||
for i := range high {
|
for i := range high {
|
||||||
kLines = append(kLines, types.KLine{Open: open[i], High: high[i], Low: low[i], Close: close[i], EndTime: types.Time(time.Now())})
|
kLines = append(kLines, types.KLine{Open: open[i], High: high[i], Low: low[i], Close: close[i], EndTime: types.Time(time.Now())})
|
||||||
}
|
}
|
||||||
return kLines
|
return kLines
|
||||||
}
|
}
|
||||||
|
var o, h, l, c []fixedpoint.Value
|
||||||
|
_ = json.Unmarshal(open, &o)
|
||||||
|
_ = json.Unmarshal(high, &h)
|
||||||
|
_ = json.Unmarshal(low, &l)
|
||||||
|
_ = json.Unmarshal(close, &c)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -39,7 +46,7 @@ func TestSTOCH_update(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "TXF1-1min_2016/1/4",
|
name: "TXF1-1min_2016/1/4",
|
||||||
kLines: buildKLines(open, high, low, close),
|
kLines: buildKLines(o, h, l, c),
|
||||||
window: 14,
|
window: 14,
|
||||||
want_k: 84.210526,
|
want_k: 84.210526,
|
||||||
want_d: 59.888357,
|
want_d: 59.888357,
|
||||||
|
|
|
@ -3,15 +3,25 @@ package indicator
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
var trivialPrices = []byte(`[0]`)
|
||||||
var randomPrices = []float64{0.6046702879796195, 0.9405190880450124, 0.6645700532184904, 0.4377241871869802, 0.4246474970712657, 0.6868330728671094, 0.06564701921747622, 0.15652925473279125, 0.09697951891448456, 0.3009218605852871}
|
var trivialVolumes = []byte(`[1]`)
|
||||||
var randomVolumes = []float64{0.5152226285020653, 0.8136499609900968, 0.21427387258237493, 0.380667189299686, 0.31806817433032986, 0.4688998449024232, 0.2830441511804452, 0.2931118573368158, 0.6790946759202162, 0.2185630525927643}
|
var easyPrices = []byte(`[1, 2, 3]`)
|
||||||
|
var easyVolumes = []byte(`[4, 5, 6]`)
|
||||||
|
var windowPrices = []byte(`[1, 2, 3, 4]`)
|
||||||
|
var windowVolumes = []byte(`[4, 5, 6, 7]`)
|
||||||
|
var randomPrices = []byte(`[0.6046702879796195, 0.9405190880450124, 0.6645700532184904, 0.4377241871869802, 0.4246474970712657, 0.6868330728671094, 0.06564701921747622, 0.15652925473279125, 0.09697951891448456, 0.3009218605852871]`)
|
||||||
|
var randomVolumes = []byte(`[0.5152226285020653, 0.8136499609900968, 0.21427387258237493, 0.380667189299686, 0.31806817433032986, 0.4688998449024232, 0.2830441511804452, 0.2931118573368158, 0.6790946759202162, 0.2185630525927643]`)
|
||||||
|
|
||||||
func Test_calculateVWAP(t *testing.T) {
|
func Test_calculateVWAP(t *testing.T) {
|
||||||
buildKLines := func(prices, volumes []float64) (kLines []types.KLine) {
|
buildKLines := func(pb, vb []byte) (kLines []types.KLine) {
|
||||||
|
var prices, volumes []fixedpoint.Value
|
||||||
|
_ = json.Unmarshal(pb, &prices)
|
||||||
|
_ = json.Unmarshal(vb, &volumes)
|
||||||
for i, p := range prices {
|
for i, p := range prices {
|
||||||
kLines = append(kLines, types.KLine{High: p, Low: p, Close: p, Volume: volumes[i]})
|
kLines = append(kLines, types.KLine{High: p, Low: p, Close: p, Volume: volumes[i]})
|
||||||
}
|
}
|
||||||
|
@ -26,19 +36,19 @@ func Test_calculateVWAP(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "trivial_case",
|
name: "trivial_case",
|
||||||
kLines: buildKLines([]float64{0}, []float64{1}),
|
kLines: buildKLines(trivialPrices, trivialVolumes),
|
||||||
window: 0,
|
window: 0,
|
||||||
want: 0.0,
|
want: 0.0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "easy_case",
|
name: "easy_case",
|
||||||
kLines: buildKLines([]float64{1, 2, 3}, []float64{4, 5, 6}),
|
kLines: buildKLines(easyPrices, easyVolumes),
|
||||||
window: 0,
|
window: 0,
|
||||||
want: (1*4 + 2*5 + 3*6) / float64(4+5+6),
|
want: (1*4 + 2*5 + 3*6) / float64(4+5+6),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "window_case",
|
name: "window_case",
|
||||||
kLines: buildKLines([]float64{1, 2, 3, 4}, []float64{4, 5, 6, 7}),
|
kLines: buildKLines(windowPrices, windowVolumes),
|
||||||
window: 3,
|
window: 3,
|
||||||
want: (2*5 + 3*6 + 4*7) / float64(5+6+7),
|
want: (2*5 + 3*6 + 4*7) / float64(5+6+7),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user