From e07fc9db3ce997c2c04dac890426e69da42e8df8 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 23 Oct 2023 23:04:21 +0200 Subject: [PATCH 01/17] wip --- pkg/bbgo/indicator_set.go | 26 +- pkg/fixedpoint/helpers.go | 12 + pkg/indicator/v2/atr.go | 12 - pkg/indicator/v2/ichimoku/builder.go | 79 +++++ pkg/indicator/v2/ichimoku/ichimoku.go | 220 +++++++++++++ pkg/indicator/v2/ichimoku/indicator.go | 77 +++++ pkg/indicator/v2/ichimoku/line-value.go | 30 ++ pkg/indicator/v2/ichimoku/line_helper.go | 159 ++++++++++ pkg/indicator/v2/ichimoku/status.go | 150 +++++++++ pkg/indicator/v2/ichimoku/types.go | 70 +++++ .../v2/ichimoku1/.vscode/launch.json | 15 + pkg/indicator/v2/ichimoku1/README.md | 36 +++ pkg/indicator/v2/ichimoku1/builder.go | 81 +++++ pkg/indicator/v2/ichimoku1/example/main.go | 242 +++++++++++++++ pkg/indicator/v2/ichimoku1/images/demo.png | Bin 0 -> 131507 bytes pkg/indicator/v2/ichimoku1/indicator.go | 293 ++++++++++++++++++ pkg/indicator/v2/ichimoku1/line-value.go | 28 ++ pkg/indicator/v2/ichimoku1/line_helper.go | 163 ++++++++++ pkg/indicator/v2/ichimoku1/status.go | 150 +++++++++ .../v2/ichimoku1/tests/analyse_test.go | 115 +++++++ .../v2/ichimoku1/tests/cloud_test.go | 157 ++++++++++ pkg/indicator/v2/ichimoku1/types.go | 70 +++++ pkg/indicator/v2/lookback.go | 40 +++ pkg/indicator/v2/lookback_test.go | 128 ++++++++ pkg/indicator/v2/{ => momentum}/rsi.go | 9 +- pkg/indicator/v2/{ => momentum}/rsi_test.go | 5 +- pkg/indicator/v2/pattern/README.md | 24 ++ pkg/indicator/v2/pattern/abondoned_baby.go | 61 ++++ .../v2/pattern/abondoned_baby_test.go | 29 ++ pkg/indicator/v2/pattern/belthold.go | 59 ++++ pkg/indicator/v2/pattern/belthold_test.go | 45 +++ pkg/indicator/v2/pattern/breakaway.go | 62 ++++ pkg/indicator/v2/pattern/breakaway_test.go | 49 +++ pkg/indicator/v2/pattern/dark_cloud.go | 48 +++ pkg/indicator/v2/pattern/dark_cloud_test.go | 28 ++ pkg/indicator/v2/pattern/doji.go | 34 ++ pkg/indicator/v2/pattern/doji_dragon_fly.go | 45 +++ .../v2/pattern/doji_dragon_fly_test.go | 39 +++ pkg/indicator/v2/pattern/doji_gravestone.go | 45 +++ .../v2/pattern/doji_gravestone_test.go | 40 +++ pkg/indicator/v2/pattern/doji_long_legged.go | 71 +++++ .../v2/pattern/doji_long_legged_test.go | 47 +++ pkg/indicator/v2/pattern/doji_star.go | 69 +++++ pkg/indicator/v2/pattern/doji_star_test.go | 44 +++ pkg/indicator/v2/pattern/doji_test.go | 40 +++ .../v2/pattern/downside_tazuki_gap.go | 52 ++++ .../v2/pattern/downside_tazuki_gap_test.go | 28 ++ pkg/indicator/v2/pattern/engulfing.go | 57 ++++ pkg/indicator/v2/pattern/engulfing_test.go | 42 +++ pkg/indicator/v2/pattern/hammerstick.go | 65 ++++ pkg/indicator/v2/pattern/hammerstick_test.go | 72 +++++ pkg/indicator/v2/pattern/harami.go | 56 ++++ pkg/indicator/v2/pattern/harami_cross.go | 58 ++++ pkg/indicator/v2/pattern/harami_cross_test.go | 42 +++ pkg/indicator/v2/pattern/harami_test.go | 42 +++ pkg/indicator/v2/pattern/kicking.go | 70 +++++ pkg/indicator/v2/pattern/kicking_test.go | 42 +++ pkg/indicator/v2/pattern/marubozu.go | 47 +++ pkg/indicator/v2/pattern/marubozu_test.go | 40 +++ pkg/indicator/v2/pattern/meeting_lines.go | 62 ++++ .../v2/pattern/meeting_lines_test.go | 44 +++ .../v2/pattern/morning_evening_star.go | 68 ++++ .../v2/pattern/morning_evening_star_test.go | 44 +++ pkg/indicator/v2/pattern/pattern.go | 15 + pkg/indicator/v2/pattern/piercing_line.go | 48 +++ .../v2/pattern/piercing_line_test.go | 27 ++ pkg/indicator/v2/pattern/separating_lines.go | 67 ++++ .../v2/pattern/separating_lines_test.go | 44 +++ .../v2/pattern/side_by_side_whitelines.go | 80 +++++ .../pattern/side_by_side_whitelines_test.go | 46 +++ pkg/indicator/v2/pattern/spinning_top.go | 46 +++ pkg/indicator/v2/pattern/spinning_top_test.go | 40 +++ pkg/indicator/v2/pattern/three_crows.go | 56 ++++ pkg/indicator/v2/pattern/three_crows_test.go | 31 ++ pkg/indicator/v2/pattern/three_line_strike.go | 73 +++++ .../v2/pattern/three_line_strike_test.go | 47 +++ .../v2/pattern/three_white_soldiers.go | 51 +++ .../v2/pattern/three_white_soldiers_test.go | 28 ++ pkg/indicator/v2/subtract_test.go | 31 +- pkg/indicator/v2/trend/alma.go | 74 +++++ pkg/indicator/v2/trend/alma_test.go | 47 +++ pkg/indicator/v2/trend/aroon.go | 100 ++++++ pkg/indicator/v2/trend/aroon_test.go | 61 ++++ pkg/indicator/v2/{ => trend}/cma.go | 2 +- pkg/indicator/v2/trend/dema.go | 43 +++ pkg/indicator/v2/{ => trend}/ewma.go | 2 +- pkg/indicator/v2/{ => trend}/macd.go | 11 +- pkg/indicator/v2/{ => trend}/macd_test.go | 5 +- pkg/indicator/v2/{ => trend}/rma.go | 2 +- pkg/indicator/v2/{ => trend}/sma.go | 2 +- pkg/indicator/v2/{ => trend}/sma_test.go | 2 +- pkg/indicator/v2/volatility/atr.go | 17 + pkg/indicator/v2/{ => volatility}/atr_test.go | 5 +- pkg/indicator/v2/{ => volatility}/atrp.go | 12 +- pkg/indicator/v2/{ => volatility}/boll.go | 12 +- pkg/indicator/v2/{ => volatility}/tr.go | 5 +- pkg/indicator/v2/{ => volatility}/tr_test.go | 8 +- .../v2/volume/accumulation_distiribution.go | 41 +++ .../volume/accumulation_distiribution_test.go | 20 ++ .../v2/volume/negative_volume_index.go | 49 +++ .../v2/volume/negative_volume_index_test.go | 34 ++ pkg/risk/riskcontrol/circuit_break.go | 6 +- pkg/risk/riskcontrol/circuit_break_test.go | 4 +- pkg/strategy/scmaker/intensity.go | 7 +- pkg/strategy/scmaker/strategy.go | 5 +- pkg/strategy/xfixedmaker/order_price_risk.go | 6 +- .../xfixedmaker/order_price_risk_test.go | 4 +- 107 files changed, 5408 insertions(+), 85 deletions(-) delete mode 100644 pkg/indicator/v2/atr.go create mode 100644 pkg/indicator/v2/ichimoku/builder.go create mode 100644 pkg/indicator/v2/ichimoku/ichimoku.go create mode 100644 pkg/indicator/v2/ichimoku/indicator.go create mode 100644 pkg/indicator/v2/ichimoku/line-value.go create mode 100644 pkg/indicator/v2/ichimoku/line_helper.go create mode 100644 pkg/indicator/v2/ichimoku/status.go create mode 100644 pkg/indicator/v2/ichimoku/types.go create mode 100644 pkg/indicator/v2/ichimoku1/.vscode/launch.json create mode 100644 pkg/indicator/v2/ichimoku1/README.md create mode 100644 pkg/indicator/v2/ichimoku1/builder.go create mode 100644 pkg/indicator/v2/ichimoku1/example/main.go create mode 100644 pkg/indicator/v2/ichimoku1/images/demo.png create mode 100644 pkg/indicator/v2/ichimoku1/indicator.go create mode 100644 pkg/indicator/v2/ichimoku1/line-value.go create mode 100644 pkg/indicator/v2/ichimoku1/line_helper.go create mode 100644 pkg/indicator/v2/ichimoku1/status.go create mode 100644 pkg/indicator/v2/ichimoku1/tests/analyse_test.go create mode 100644 pkg/indicator/v2/ichimoku1/tests/cloud_test.go create mode 100644 pkg/indicator/v2/ichimoku1/types.go create mode 100644 pkg/indicator/v2/lookback.go create mode 100644 pkg/indicator/v2/lookback_test.go rename pkg/indicator/v2/{ => momentum}/rsi.go (92%) rename pkg/indicator/v2/{ => momentum}/rsi_test.go (95%) create mode 100644 pkg/indicator/v2/pattern/README.md create mode 100644 pkg/indicator/v2/pattern/abondoned_baby.go create mode 100644 pkg/indicator/v2/pattern/abondoned_baby_test.go create mode 100644 pkg/indicator/v2/pattern/belthold.go create mode 100644 pkg/indicator/v2/pattern/belthold_test.go create mode 100644 pkg/indicator/v2/pattern/breakaway.go create mode 100644 pkg/indicator/v2/pattern/breakaway_test.go create mode 100644 pkg/indicator/v2/pattern/dark_cloud.go create mode 100644 pkg/indicator/v2/pattern/dark_cloud_test.go create mode 100644 pkg/indicator/v2/pattern/doji.go create mode 100644 pkg/indicator/v2/pattern/doji_dragon_fly.go create mode 100644 pkg/indicator/v2/pattern/doji_dragon_fly_test.go create mode 100644 pkg/indicator/v2/pattern/doji_gravestone.go create mode 100644 pkg/indicator/v2/pattern/doji_gravestone_test.go create mode 100644 pkg/indicator/v2/pattern/doji_long_legged.go create mode 100644 pkg/indicator/v2/pattern/doji_long_legged_test.go create mode 100644 pkg/indicator/v2/pattern/doji_star.go create mode 100644 pkg/indicator/v2/pattern/doji_star_test.go create mode 100644 pkg/indicator/v2/pattern/doji_test.go create mode 100644 pkg/indicator/v2/pattern/downside_tazuki_gap.go create mode 100644 pkg/indicator/v2/pattern/downside_tazuki_gap_test.go create mode 100644 pkg/indicator/v2/pattern/engulfing.go create mode 100644 pkg/indicator/v2/pattern/engulfing_test.go create mode 100644 pkg/indicator/v2/pattern/hammerstick.go create mode 100644 pkg/indicator/v2/pattern/hammerstick_test.go create mode 100644 pkg/indicator/v2/pattern/harami.go create mode 100644 pkg/indicator/v2/pattern/harami_cross.go create mode 100644 pkg/indicator/v2/pattern/harami_cross_test.go create mode 100644 pkg/indicator/v2/pattern/harami_test.go create mode 100644 pkg/indicator/v2/pattern/kicking.go create mode 100644 pkg/indicator/v2/pattern/kicking_test.go create mode 100644 pkg/indicator/v2/pattern/marubozu.go create mode 100644 pkg/indicator/v2/pattern/marubozu_test.go create mode 100644 pkg/indicator/v2/pattern/meeting_lines.go create mode 100644 pkg/indicator/v2/pattern/meeting_lines_test.go create mode 100644 pkg/indicator/v2/pattern/morning_evening_star.go create mode 100644 pkg/indicator/v2/pattern/morning_evening_star_test.go create mode 100644 pkg/indicator/v2/pattern/pattern.go create mode 100644 pkg/indicator/v2/pattern/piercing_line.go create mode 100644 pkg/indicator/v2/pattern/piercing_line_test.go create mode 100644 pkg/indicator/v2/pattern/separating_lines.go create mode 100644 pkg/indicator/v2/pattern/separating_lines_test.go create mode 100644 pkg/indicator/v2/pattern/side_by_side_whitelines.go create mode 100644 pkg/indicator/v2/pattern/side_by_side_whitelines_test.go create mode 100644 pkg/indicator/v2/pattern/spinning_top.go create mode 100644 pkg/indicator/v2/pattern/spinning_top_test.go create mode 100644 pkg/indicator/v2/pattern/three_crows.go create mode 100644 pkg/indicator/v2/pattern/three_crows_test.go create mode 100644 pkg/indicator/v2/pattern/three_line_strike.go create mode 100644 pkg/indicator/v2/pattern/three_line_strike_test.go create mode 100644 pkg/indicator/v2/pattern/three_white_soldiers.go create mode 100644 pkg/indicator/v2/pattern/three_white_soldiers_test.go create mode 100644 pkg/indicator/v2/trend/alma.go create mode 100644 pkg/indicator/v2/trend/alma_test.go create mode 100644 pkg/indicator/v2/trend/aroon.go create mode 100644 pkg/indicator/v2/trend/aroon_test.go rename pkg/indicator/v2/{ => trend}/cma.go (96%) create mode 100644 pkg/indicator/v2/trend/dema.go rename pkg/indicator/v2/{ => trend}/ewma.go (96%) rename pkg/indicator/v2/{ => trend}/macd.go (76%) rename pkg/indicator/v2/{ => trend}/macd_test.go (94%) rename pkg/indicator/v2/{ => trend}/rma.go (98%) rename pkg/indicator/v2/{ => trend}/sma.go (96%) rename pkg/indicator/v2/{ => trend}/sma_test.go (94%) create mode 100644 pkg/indicator/v2/volatility/atr.go rename pkg/indicator/v2/{ => volatility}/atr_test.go (96%) rename pkg/indicator/v2/{ => volatility}/atrp.go (54%) rename pkg/indicator/v2/{ => volatility}/boll.go (82%) rename pkg/indicator/v2/{ => volatility}/tr.go (87%) rename pkg/indicator/v2/{ => volatility}/tr_test.go (93%) create mode 100644 pkg/indicator/v2/volume/accumulation_distiribution.go create mode 100644 pkg/indicator/v2/volume/accumulation_distiribution_test.go create mode 100644 pkg/indicator/v2/volume/negative_volume_index.go create mode 100644 pkg/indicator/v2/volume/negative_volume_index_test.go diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index 0d5dbd3636..e4cf118096 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -3,7 +3,9 @@ package bbgo import ( "github.com/sirupsen/logrus" - "github.com/c9s/bbgo/pkg/indicator/v2" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/momentum" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -73,16 +75,16 @@ func (i *IndicatorSet) VOLUME(interval types.Interval) *indicatorv2.PriceStream return indicatorv2.Volumes(i.KLines(interval)) } -func (i *IndicatorSet) RSI(iw types.IntervalWindow) *indicatorv2.RSIStream { - return indicatorv2.RSI2(i.CLOSE(iw.Interval), iw.Window) +func (i *IndicatorSet) RSI(iw types.IntervalWindow) *momentum.RSIStream { + return momentum.RSI2(i.CLOSE(iw.Interval), iw.Window) } -func (i *IndicatorSet) EMA(iw types.IntervalWindow) *indicatorv2.EWMAStream { +func (i *IndicatorSet) EMA(iw types.IntervalWindow) *trend.EWMAStream { return i.EWMA(iw) } -func (i *IndicatorSet) EWMA(iw types.IntervalWindow) *indicatorv2.EWMAStream { - return indicatorv2.EWMA2(i.CLOSE(iw.Interval), iw.Window) +func (i *IndicatorSet) EWMA(iw types.IntervalWindow) *trend.EWMAStream { + return trend.EWMA2(i.CLOSE(iw.Interval), iw.Window) } func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *indicatorv2.StochStream { @@ -93,14 +95,14 @@ func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BOL return indicatorv2.BOLL(i.CLOSE(iw.Interval), iw.Window, k) } -func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *indicatorv2.MACDStream { - return indicatorv2.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) +func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *trend.MACDStream { + return trend.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) } -func (i *IndicatorSet) ATR(interval types.Interval, window int) *indicatorv2.ATRStream { - return indicatorv2.ATR2(i.KLines(interval), window) +func (i *IndicatorSet) ATR(interval types.Interval, window int) *trend.ATRStream { + return trend.ATR2(i.KLines(interval), window) } -func (i *IndicatorSet) ATRP(interval types.Interval, window int) *indicatorv2.ATRPStream { - return indicatorv2.ATRP2(i.KLines(interval), window) +func (i *IndicatorSet) ATRP(interval types.Interval, window int) *trend.ATRPStream { + return trend.ATRP2(i.KLines(interval), window) } diff --git a/pkg/fixedpoint/helpers.go b/pkg/fixedpoint/helpers.go index cb585e5c0f..2d3ed53845 100644 --- a/pkg/fixedpoint/helpers.go +++ b/pkg/fixedpoint/helpers.go @@ -13,3 +13,15 @@ func Avg(values []Value) (avg Value) { avg = s.Div(NewFromInt(int64(len(values)))) return avg } + +// maxDiff is the maximum deviation between a and b to consider them approximately equal +func ApproxEqual(a, b Value, maxDiff float64) bool { + // Calculate the absolute difference + diff := Abs(a.Sub(b)) + + // Define the small multiple + smallMultiple := a.Mul(NewFromFloat(maxDiff)) + + // Compare the absolute difference to the small multiple + return diff <= smallMultiple +} diff --git a/pkg/indicator/v2/atr.go b/pkg/indicator/v2/atr.go deleted file mode 100644 index da92c5c5b8..0000000000 --- a/pkg/indicator/v2/atr.go +++ /dev/null @@ -1,12 +0,0 @@ -package indicatorv2 - -type ATRStream struct { - // embedded struct - *RMAStream -} - -func ATR2(source KLineSubscription, window int) *ATRStream { - tr := TR2(source) - rma := RMA2(tr, window, true) - return &ATRStream{RMAStream: rma} -} diff --git a/pkg/indicator/v2/ichimoku/builder.go b/pkg/indicator/v2/ichimoku/builder.go new file mode 100644 index 0000000000..c2c3953ba2 --- /dev/null +++ b/pkg/indicator/v2/ichimoku/builder.go @@ -0,0 +1,79 @@ +package ichimoku + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +func BuildIchimokuStatus(bars []types.KLine) (*IchimokuStatus, error) { + if len(bars) == 0 { + return nil, ErrDataNotFill + } + + if len(bars) < 52 { + return nil, ErrNotEnoughData + } + + tenkenLine := calcLine(Line_Tenkan_sen, bars) + kijonLine := calcLine(Line_kijon_sen, bars) + + span_a := calculate_span_a(tenkenLine, kijonLine) + span_b := calcLine(Line_spanPeriod, bars) + chiko_index := (len(bars) - int(Line_chikoPeriod)) - 1 + cheko_span := bars[chiko_index] + + var latestPrice types.KLine + latestPriceIndex := (len(bars) - 1) + if (len(bars) - 1) >= latestPriceIndex { + latestPrice = bars[latestPriceIndex] + } + + if !tenkenLine.isNil && !kijonLine.isNil && !span_a.isNil && !span_b.isNil { + ichi := NewIchimokuStatus(tenkenLine, kijonLine, span_a, span_b, cheko_span, latestPrice) + return ichi, nil + } + + return nil, ErrBuildFailed +} + +func calcLine(line_type ELine, bars []types.KLine) ValueLine { + high := NewValueLineNil() + low := NewValueLineNil() + l := len(bars) + from := l - 1 - int(line_type) + if from == -1 { + from = 0 + } + bars_tmp := bars[from : l-1] + if len(bars) < int(line_type) { + return NewValueLineNil() + } + for _, v := range bars_tmp { + + if high.isNil { + high.SetValue(v.High) + } + if low.isNil { + low.SetValue(v.Low) + } + + if v.High > high.valLine { + high.SetValue(v.High) + } + + if v.Low < low.valLine { + low.SetValue(v.Low) + } + + } + line := low.valLine + (high.valLine / 2) + return NewValue(line) +} + +func calculate_span_a(tenken ValueLine, kijon ValueLine) ValueLine { + if !tenken.isNil && !kijon.isNil { + v := tenken.valLine + (kijon.valLine / 2) + return NewValue(v) + } + + return NewValueLineNil() +} diff --git a/pkg/indicator/v2/ichimoku/ichimoku.go b/pkg/indicator/v2/ichimoku/ichimoku.go new file mode 100644 index 0000000000..698bd01d55 --- /dev/null +++ b/pkg/indicator/v2/ichimoku/ichimoku.go @@ -0,0 +1,220 @@ +package ichimoku + +import ( + "github.com/algo-boyz/decimal" + "github.com/thecolngroup/gou/dec" + + "github.com/c9s/bbgo/pkg/types" +) + +// type IIchimokuIndicator interface { +// // out result array sort: [new day -to- old day] +// // one call per asset +// MakeIchimokuInPast(bars []types.KLine, numberOfRead int) error + +// //one call per asset +// PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) + +// //Analyse Trigger Cross tenken & kijon sen +// AnalyseTriggerCross(previous *IchimokuStatus, bars_only_25_bars_latest []types.KLine) (*IchimokuStatus, error) + +// GetLast() *IchimokuStatus +// GetList() []*IchimokuStatus +// } + +func (s *IchimokuStream) GetList() []*IchimokuStatus { + return s.Ichimokus +} + +// analyse with two days +func (s *IchimokuStream) FindStatusin26BarPast() { + + for i := 0; i < s.NumberOfIchimokus(); i++ { + item := s.Ichimokus[i] + sen_a, sen_b := s.calc_Cloud_InPast(i) + item.Set_SenCo_A_Past(sen_a) + item.Set_SenCo_B_Past(sen_b) + } + +} + +// Analyse Trigger Cross tenken & kijon sen +// bars : contain with new bar +func (s *IchimokuStream) AnalyseTriggerCross(previous *IchimokuStatus, _52_bars_latest []types.KLine) (*IchimokuStatus, error) { + + if len(_52_bars_latest) == 0 { + return nil, ErrDataNotFill + } + + if len(_52_bars_latest) < 52 { + return nil, ErrNotEnoughData + } + + newIchi, e := BuildIchimokuStatus(_52_bars_latest) + + if e != nil { + return nil, e + } + sen_a_in_26_past, sen_b_in_26_past := s.calc_Cloud_InPast(0) + + if sen_a_in_26_past.isNil || sen_b_in_26_past.isNil { + return nil, ErrChikoStatus26InPastNotMade + } + + newIchi.Set_SenCo_A_Past(sen_a_in_26_past) + newIchi.Set_SenCo_B_Past(sen_b_in_26_past) + + if newIchi.SencoA_Past.isNil || newIchi.SencoB_Past.isNil { + return nil, ErrChikoStatus26InPastNotMade + } + + if !newIchi.bar.StartTime.After(previous.bar.StartTime.Time()) { + return nil, ErrDateNotGreaterThanPrevious + } + has_collision1, intersection := s.CrossCheck(previous, newIchi) + if has_collision1 == EInterSectionStatus_Find { + newIchi.SetStatus(newIchi.CloudStatus(intersection)) + newIchi.SetCloudSwitching(s.isSwitchCloud(previous, newIchi)) + + return newIchi, nil + } + return nil, nil + +} + +// analyse with two days +func (s *IchimokuStream) PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) { + + if len(data) != 2 { + return nil, ErrNotEnoughData + } + + current := data[0] + previous := data[1] + + line1_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.TenkenSen.valLine) + line1_point_b := NewPoint(dec.New(current.bar.StartTime.Unix()), current.TenkenSen.valLine) + + line2_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.KijonSen.valLine) + line2_point_b := NewPoint(dec.New(current.bar.StartTime.Unix()), current.KijonSen.valLine) + + has_collision1, intersection := s.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) + + if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { + return nil, nil + } + + Line_Eq_A := s.getLineEquation(line1_point_a, line1_point_b) // tenken + Line_Eq_B := s.getLineEquation(line2_point_a, line2_point_b) //kijon + + if line1_point_a == line2_point_a { + return nil, nil //paraller + + } + + if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { + return nil, nil + + } + + if has_collision1 == EInterSectionStatus_Find { + + current.SetStatus(current.CloudStatus(intersection)) + + current.SetCloudSwitching(o.isSwitchCloud(previous, current)) + return current, nil + } + return nil, nil +} + +func (s *IchimokuStream) NumberOfIchimokus() int { + return len(s.Ichimokus) +} + +func (s *IchimokuStream) GetLast() *IchimokuStatus { + + if s.Ichimokus != nil && len(s.Ichimokus) == 0 { + return nil + } + + latest := s.Ichimokus[0] + + return latest +} + +func (s *IchimokuStream) Put(v *IchimokuStatus) { + o.Ichimokus = append(o.Ichimokus, v) +} + +// -------------------------------------------------------------------------------------------------------- +func (s *IchimokuStream) CrossCheck(previous, newIchi *IchimokuStatus) (EInterSectionStatus, decimal.Decimal) { + line1_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.TenkenSen.valLine) + line1_point_b := NewPoint(dec.New(newIchi.bar.StartTime.Unix()), newIchi.TenkenSen.valLine) + + line2_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.KijonSen.valLine) + line2_point_b := NewPoint(dec.New(newIchi.bar.StartTime.Unix()), newIchi.KijonSen.valLine) + + has_collision1, intersection := s.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) + + if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { + return EInterSectionStatus_NAN, decimal.Zero + } + + Line_Eq_A := s.getLineEquation(line1_point_a, line1_point_b) // tenken + Line_Eq_B := s.getLineEquation(line2_point_a, line2_point_b) //kijon + + if line1_point_a == line2_point_a { + return EInterSectionStatus_NAN, intersection //paraller + + } + + if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { + return EInterSectionStatus_NAN, intersection + + } + return has_collision1, intersection +} + +// analyse with two days +func (s *IchimokuStream) isSwitchCloud(previous, current *IchimokuStatus) bool { + + if previous.SenKoA_Shifted26.valLine >= previous.SenKoB_Shifted26.valLine && + current.SenKoA_Shifted26.valLine > current.SenKoB_Shifted26.valLine || + previous.SenKoA_Shifted26.valLine < previous.SenKoB_Shifted26.valLine && + current.SenKoA_Shifted26.valLine >= current.SenKoB_Shifted26.valLine { + if current.TenkenSen.valLine >= current.KijonSen.valLine { + return true + } + } + return false +} + +// find cloud Span A,B in Past (26 day ) +func (s *IchimokuStream) calc_Cloud_InPast(current int) (Point, Point) { + + if s.NumberOfIchimokus() < 26 { + return NewNilPoint(), NewNilPoint() + } + + rem := s.NumberOfIchimokus() - current + max := 26 //from 26 bar in past (find Shift index) + + if rem < max { + return NewNilPoint(), NewNilPoint() + } + + index := current + 25 + c := s.Ichimokus[index] + buff_senco_a := NewPoint(dec.New(c.bar.StartTime.Unix()/1000), c.SenKoA_Shifted26.valLine) + buff_senco_b := NewPoint(dec.New(c.bar.StartTime.Unix()/1000), c.SenKoB_Shifted26.valLine) + + return buff_senco_a, buff_senco_b +} + +func (s *IchimokuStream) getLineEquation(p1 Point, p2 Point) *Equation { + eq := Equation{} + eq.Slope = (p2.Y.Sub(p1.Y)).Mul(p2.X.Sub(p1.X)) + //eq.Intercept = (-1 * eq.Slope * p1.X) + p1.Y + eq.Intercept = p1.Y.Sub(eq.Slope).Mul(p1.X) + return &eq +} diff --git a/pkg/indicator/v2/ichimoku/indicator.go b/pkg/indicator/v2/ichimoku/indicator.go new file mode 100644 index 0000000000..11190fbc8d --- /dev/null +++ b/pkg/indicator/v2/ichimoku/indicator.go @@ -0,0 +1,77 @@ +package ichimoku + +import ( + "fmt" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type IchimokuStream struct { + *types.KLineSeries + line_helper lineHelper + Ichimokus []*IchimokuStatus + ConversionLine *types.Float64Series + BaseLine *types.Float64Series + LeadingSpanA *types.Float64Series + LeadingSpanB *types.Float64Series + laggingSpan *types.Float64Series + window int +} + +func Ichimoku(source v2.KLineSubscription, window int) *IchimokuStream { + s := &IchimokuStream{ + KLineSeries: v2.KlineSeries(), + window: window, + } + s.Bind(source, s) + return s +} + +func (s *IchimokuStream) Calculate(v float64) float64 { + bars_len := s.Length() + + if bars_len < numberOfRead || bars_len < 52 { + return ErrNotEnoughData + } + + fmt.Printf("Calc ichi from Last %v days on %d total candles\r\n", numberOfRead, len(series)) + + // descending + for day := 0; day < numberOfRead; day++ { + + from := bars_len - 52 - day + to := bars_len - day + + ic, err := BuildIchimokuStatus(s.loadbars(from, to)) + if err != nil { + return err + } + s.Put(ic) + + } + + for day_index := 0; day_index < s.NumberOfIchimokus(); day_index++ { + item := s.Ichimokus[day_index] + sen_a, sen_b := s.Calc_Cloud_InPast(day_index) + item.Set_SenCo_A_Past(sen_a) + item.Set_SenCo_B_Past(sen_b) + } + + return sma +} + +func (s *IchimokuStream) loadbars(from int, to int) []types.KLine { + if s.Length() == 0 { + return nil + } + if from < 0 { + from = 0 + } + if to > s.Length() { + to = s.Length() + } + + return s.Last(0) // (from:to) + +} diff --git a/pkg/indicator/v2/ichimoku/line-value.go b/pkg/indicator/v2/ichimoku/line-value.go new file mode 100644 index 0000000000..720e609daf --- /dev/null +++ b/pkg/indicator/v2/ichimoku/line-value.go @@ -0,0 +1,30 @@ +package ichimoku + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +type ValueLine struct { + valLine fixedpoint.Value + isNil bool +} + +func (n *ValueLine) Value() interface{} { + if n.isNil { + return nil + } + return n.valLine +} + +func (n *ValueLine) SetValue(v fixedpoint.Value) { + n.valLine = v + n.isNil = false +} + +func NewValue(x fixedpoint.Value) ValueLine { + return ValueLine{x, false} +} + +func NewValueLineNil() ValueLine { + return ValueLine{fixedpoint.Zero, true} +} diff --git a/pkg/indicator/v2/ichimoku/line_helper.go b/pkg/indicator/v2/ichimoku/line_helper.go new file mode 100644 index 0000000000..2833d91709 --- /dev/null +++ b/pkg/indicator/v2/ichimoku/line_helper.go @@ -0,0 +1,159 @@ +package ichimoku + +import ( + "fmt" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +type lineHelper struct { +} +type EPointLocation int + +const ( + EPointLocation_NAN EPointLocation = 0 + EPointLocation_above EPointLocation = 1 + EPointLocation_below EPointLocation = 2 + EPointLocation_overlap EPointLocation = 3 +) + +func NewLineHelper() lineHelper { + f := lineHelper{} + return f +} + +// check Point above or below line +func (n *lineHelper) isAboveLine(point Point, line []Point) EPointLocation { + zero := fixedpoint.Zero + if len(line) < 2 { + return EPointLocation_NAN + } + + checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) EPointLocation { + //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) + // v := (p.X-line_p_a.X)*(line_p_b.Y-line_p_a.Y) - (p.Y-line_p_a.Y)*(line_p_b.X-line_p_a.X) + yOverX := p.Y.Sub(line_p_a.Y).Mul(line_p_b.X.Sub(line_p_a.X)) + xOverY := p.X.Sub(line_p_a.X).Mul(line_p_b.Y.Sub(line_p_a.Y)) + v := xOverY.Sub(yOverX) + + if v.Compare(zero) == 0 { + return EPointLocation_overlap + } else if v > zero { + return EPointLocation_above + } else { + return EPointLocation_below + } + } + + return checkAboveOrBelow(point, line[0], line[1]) + +} + +func (n *lineHelper) positionPointInline(point Point, line []Point) fixedpoint.Value { + zero := fixedpoint.Zero + + if len(line) < 2 { + return zero + } + + checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) fixedpoint.Value { + //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) + return (p.X.Sub(line_p_a.X)).Mul(line_p_b.Y.Sub(line_p_a.Y)).Sub(p.Y.Sub(line_p_a.Y)).Mul(line_p_b.X.Sub(line_p_a.X)) + } + + res := checkAboveOrBelow(point, line[0], line[1]) + + return res + +} + +func (o *lineHelper) GetCollisionDetection(a Point, b Point, c Point, d Point) (EInterSectionStatus, fixedpoint.Value) { + + denominator := ((b.X.Sub(a.X)).Mul(d.Y.Sub(c.Y))).Sub((b.Y.Sub(a.Y)).Mul(d.X.Sub(c.X))) + numerator1 := ((a.Y.Sub(c.Y)).Mul(d.X.Sub(c.X))).Sub((a.X.Sub(c.X)).Mul(d.Y.Sub(c.Y))) + numerator2 := ((a.Y.Sub(c.Y)).Mul(b.X.Sub(a.X))).Sub((a.X.Sub(c.X)).Mul(b.Y.Sub(a.Y))) + + // Detect coincident lines (has a problem, read below) + if denominator.Compare(fixedpoint.Zero) == 0 { + return EInterSectionStatus_NAN, fixedpoint.Zero + } + r := numerator1.Div(denominator) + s := numerator2.Div(denominator) + zero := fixedpoint.Zero + one := fixedpoint.One + if r >= zero && r <= one && + s >= zero && s <= one { + // fmt.Printf("collision detec : a:%v , b:%v, c:%v ,d:%v ,r %v s %v\r\n", a, b, c, d, r, s) + intersection := o.get_intersection_point(a, b, c, d) + + return EInterSectionStatus_Collision_Find, intersection + } + return EInterSectionStatus_NAN, fixedpoint.Zero +} + +//line senco A or B +func (o *lineHelper) GetCollisionWithLine(price_point Point, line_clouds []Point) (EPointLocation, error) { + zero := fixedpoint.Zero + + len_line_clouds := len(line_clouds) + if len_line_clouds < 1 { + return EPointLocation_NAN, ErrNotEnoughData + } + // Create a point at infinity, y is same as point p + //x := time.Now().AddDate(0, -1, 0).Unix() + //line1_a := NewPoint(decimal.NewFromInt(x), price_point.Y) + // line1_b := price_point + // line_b := NewPoint(0,price_point) + //var ps EPointLocation = EPointLocation_NaN + below := 0 + above := 0 + fmt.Println("___") + fmt.Printf("Cloud : check point :x:%.0f y:%.0f \r\n", price_point.X.Float64(), price_point.Y.Float64()) + sum := fixedpoint.Zero + for i := 1; i < len_line_clouds; i++ { + line2_a := line_clouds[i-1] + line2_b := line_clouds[i] + //fmt.Printf("Cloud :x:%.0f y:%.0f ,\r\n", line2_a.X, line2_a.Y) + fmt.Printf("%.0f,%.0f,\r\n", line2_a.X.Float64(), line2_a.Y.Float64()) + //res := o.GetCollisionDetection(line1_a, line1_b, line2_a, line2_b) + buff := []Point{line2_a, line2_b} + // res := o.isAboveLine(price_point, buff) + c := o.positionPointInline(price_point, buff) + if c > zero { //below + below++ + } else { + above++ + } + + sum = sum.Add(c) + + } + v := sum.Div(fixedpoint.NewFromInt(int64(len_line_clouds))) + + if v > zero { + return EPointLocation_below, nil // above + } else { + return EPointLocation_above, nil //below + } + +} +func (o *lineHelper) getLineEquation(p1 Point, p2 Point) *Equation { + eq := Equation{} + x := p1.X.Sub(p2.X) + y := p1.Y.Sub(p2.Y) + eq.Slope = y.Div(x) + eq.Intercept = fixedpoint.One.Neg().Mul(eq.Slope).Mul(p1.X).Add(p1.Y) + return &eq +} + +func (o *lineHelper) get_intersection_point(line1_pointA Point, line1_pointB Point, line2_pointA Point, line2_pointB Point) fixedpoint.Value { + + tenken := o.getLineEquation(line1_pointA, line1_pointB) + kijon := o.getLineEquation(line2_pointA, line2_pointB) + intercept := kijon.Intercept.Sub(tenken.Intercept) + slope := tenken.Slope.Sub(kijon.Slope) + x_intersection := intercept.Div(slope) + x := kijon.Slope.Mul(x_intersection) + y_intersection := x.Add(kijon.Intercept) + return y_intersection +} diff --git a/pkg/indicator/v2/ichimoku/status.go b/pkg/indicator/v2/ichimoku/status.go new file mode 100644 index 0000000000..8474f38383 --- /dev/null +++ b/pkg/indicator/v2/ichimoku/status.go @@ -0,0 +1,150 @@ +package ichimoku + +import ( + "fmt" + "time" + + "github.com/algo-boyz/alphakit/market" + decimal "github.com/algo-boyz/decimal128" + + "github.com/c9s/bbgo/pkg/types" +) + +type IchimokuStatus struct { + TenkenSen ValueLine + + //_______________ + + KijonSen ValueLine + + //in the future + SenKoA_Shifted26 ValueLine + + //in the future + SenKoB_Shifted26 ValueLine + + //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) + //SencoA 26 candle in the past (for check) + SencoA_Past Point + //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) + //SencoB 26 candle in the past (for check) + SencoB_Past Point + + ChikoSpan *types.KLine //close bar + + bar *types.KLine + //----- + Status EIchimokuStatus + cloudSwitching bool + + line_helper lineHelper +} + +func NewIchimokuStatus(tenken ValueLine, kijon ValueLine, senKoA_Shifted26 ValueLine, senKoB_Shifted52 ValueLine, chiko_span, bar *market.Kline) *IchimokuStatus { + + o := IchimokuStatus{} + + o.TenkenSen = tenken + + o.KijonSen = kijon + + o.SenKoA_Shifted26 = senKoA_Shifted26 + o.SenKoB_Shifted26 = senKoB_Shifted52 + + o.ChikoSpan = chiko_span + o.bar = bar + o.Status = IchimokuStatus_NAN + o.line_helper = NewLineHelper() + + return &o +} + +func (o *IchimokuStatus) SetChikoSpan(v *market.Kline) { + o.ChikoSpan = v +} + +func (o *IchimokuStatus) Set_SenCo_A_Past(p Point) { + o.SencoA_Past = p +} + +func (o *IchimokuStatus) Set_SenCo_B_Past(p Point) { + o.SencoB_Past = p +} + +func (o *IchimokuStatus) SetStatus(status EIchimokuStatus) { + o.Status = status +} + +func (o *IchimokuStatus) GetStatus() EIchimokuStatus { + return o.Status +} + +func (o *IchimokuStatus) SetCloudSwitching(v bool) { + o.cloudSwitching = v +} + +func (o *IchimokuStatus) GetCloudSwitching() bool { + return o.cloudSwitching +} + +func (o *IchimokuStatus) Is_cloud_green() bool { + return o.SenKoA_Shifted26.valLine > o.SenKoB_Shifted26.valLine +} + +func (o *IchimokuStatus) IsChikoAbovePrice() bool { + return o.ChikoSpan.High > o.bar.Close +} + +func (o *IchimokuStatus) CloudStatus(intersection decimal.Decimal) EIchimokuStatus { + if o.SenKoA_Shifted26.isNil || o.SenKoB_Shifted26.isNil { + return IchimokuStatus_NAN + } + if o.SencoA_Past.isNil || o.SencoB_Past.isNil { + return IchimokuStatus_NAN + } + + sen_B := o.SencoB_Past //Senko B in_26_candle_pass + sen_A := o.SencoA_Past //Senko A in_26_candle_pass + if sen_A.Y > intersection && sen_B.Y > intersection { + return IchimokuStatus_Cross_Below + } else if sen_A.Y < intersection && sen_B.Y < intersection { + return IchimokuStatus_Cross_Above + } else if sen_A.Y < intersection && sen_B.Y > intersection || sen_A.Y > intersection && sen_B.Y < intersection { + return IchimokuStatus_Cross_Inside + } + + return IchimokuStatus_NAN + +} + +func (o *IchimokuStatus) GetStatusString() string { + result := "" + switch o.Status { + case IchimokuStatus_NAN: + result = "nan" + + case IchimokuStatus_Cross_Below: + result = "cross below" + case IchimokuStatus_Cross_Above: + result = "cross above" + case IchimokuStatus_Cross_Inside: + result = "cross inside" + } + + return result +} + +func (o *IchimokuStatus) Print() string { + return fmt.Sprintf("ichimoku cloud %v|%v|%v|%v|%v| Green: %v, Chiko UP: %v | status: %v | %v\n", + o.TenkenSen.Value(), + o.KijonSen.Value(), + o.SenKoA_Shifted26.Value(), + o.SenKoB_Shifted26.Value(), + o.ChikoSpan.Close, + o.Is_cloud_green(), + o.IsChikoAbovePrice(), + o.GetStatusString(), + o.bar.StartTime.Time().Format(time.DateTime), + ) + +} diff --git a/pkg/indicator/v2/ichimoku/types.go b/pkg/indicator/v2/ichimoku/types.go new file mode 100644 index 0000000000..97e7171e08 --- /dev/null +++ b/pkg/indicator/v2/ichimoku/types.go @@ -0,0 +1,70 @@ +package ichimoku + +import ( + "errors" + + decimal "github.com/algo-boyz/decimal128" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +var ( + ErrBuildFailed = errors.New("build failed") + ErrNotEnoughData = errors.New("not enough data") + ErrDataNotFill = errors.New("data not fill") + ErrChikoStatus26InPastNotMade = errors.New("chiko status 26 in past not reached") + ErrDateNotGreaterThanPrevious = errors.New("date is not greater than previous") +) + +type Point struct { + X, Y fixedpoint.Value + isNil bool +} + +func NewPoint(x, y fixedpoint.Value) Point { + p := Point{} + p.X = x + p.Y = y + p.isNil = false + return p +} +func NewNilPoint() Point { + p := Point{} + p.X = fixedpoint.NewFromInt(-1) + p.Y = fixedpoint.NewFromInt(-1) + p.isNil = true + return p +} + +type Equation struct { + Slope decimal.Decimal + Intercept decimal.Decimal +} + +type EInterSectionStatus int + +const ( + EInterSectionStatus_NAN EInterSectionStatus = 0 + EInterSectionStatus_Find EInterSectionStatus = 1 + EInterSectionStatus_Parallel EInterSectionStatus = 2 + EInterSectionStatus_Collision_Find EInterSectionStatus = 1 +) + +type ELine int + +const ( + Line_Tenkan_sen ELine = 9 + Line_kijon_sen ELine = 26 + Line_spanPeriod ELine = 52 + Line_chikoPeriod ELine = 26 //-26 +) + +type EIchimokuStatus int + +const ( + IchimokuStatus_NAN EIchimokuStatus = 0 + IchimokuStatus_Cross_Inside EIchimokuStatus = 1 + IchimokuStatus_Cross_Below EIchimokuStatus = 2 + IchimokuStatus_Cross_Above EIchimokuStatus = 3 + IchimokuStatus_overLab EIchimokuStatus = 4 +) diff --git a/pkg/indicator/v2/ichimoku1/.vscode/launch.json b/pkg/indicator/v2/ichimoku1/.vscode/launch.json new file mode 100644 index 0000000000..3e7cd5fe07 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "example/main.go" + } + ] +} \ No newline at end of file diff --git a/pkg/indicator/v2/ichimoku1/README.md b/pkg/indicator/v2/ichimoku1/README.md new file mode 100644 index 0000000000..7e9bcf04db --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/README.md @@ -0,0 +1,36 @@ +# (Ichimoku indicator)[https://www.investopedia.com/terms/i/ichimoku-cloud.asp] + +- (Intersection Point Of Two Lines)[https://web.archive.org/web/20060911055655/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d] + +## Calculation + +``` +There are five plots that make up the Ichimoku Cloud indicator. Their names and calculations are: + +TenkanSen (Conversion Line): (High + Low) / 2 default period = 9 +KijunSen (Base Line): (High + Low) / 2 default period = 26 +Chiku Span (Lagging Span): Price Close shifted back 26 bars +Senkou A (Leading Span A): (TenkanSen + KijunSen) / 2 (Senkou A is shifted forward 26 bars) +Senkou B (Leading Span B): (High + Low) / 2 using period = 52 (Senkou B is shifted forward 26 bars) +``` + +![alt text](images/demo.png) + +```console +➜ Ichimoku git:(main) ✗ go run example/main.go + +Calc ichi from Last 135 days +____ + Find ichi 8705|8710|8707.5|8930|8870|G:false,Chiko UP :true |status : nan |2022 Sun Oct 2 10:30:00 |1664699400000 +.____ + Find ichi 8630|8630|8630|8710|8430|G:false,Chiko UP :false |status : cross below |2022 Tue Oct 11 08:30:00 |1665469800000 +.____ + Find ichi 8685|8690|8687.5|8695|8550|G:false,Chiko UP :false |status : cross inside |2022 Tue Oct 18 08:30:00 |1666074600000 +.____ + Find ichi 8135|8135|8135|8295|8450|G:false,Chiko UP :true |status : cross below |2022 Tue Nov 1 07:30:00 |1667284200000 +.____ + Find ichi 9485|9525|9505|8790|9430|G:true,Chiko UP :false |status : cross above |2022 Tue Nov 15 08:30:00 |1668497400000 +.____ + Find ichi 9570|9545|9557.5|8980|9470|G:true,Chiko UP :false |status : cross above |2022 Wed Nov 16 09:30:00 |1668587400000 +.190 +``` \ No newline at end of file diff --git a/pkg/indicator/v2/ichimoku1/builder.go b/pkg/indicator/v2/ichimoku1/builder.go new file mode 100644 index 0000000000..a36e331245 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/builder.go @@ -0,0 +1,81 @@ +package ichimoku + +import ( + "github.com/algo-boyz/alphakit/market" + + "github.com/algo-boyz/alphakit/ta/dec" +) + +func BuildIchimokuStatus(bars []*market.Kline) (*IchimokuStatus, error) { + if len(bars) == 0 { + return nil, ErrDataNotFill + } + + if len(bars) < 52 { + return nil, ErrNotEnoughData + } + + tenkenLine := calcLine(Line_Tenkan_sen, bars) + kijonLine := calcLine(Line_kijon_sen, bars) + + span_a := calculate_span_a(tenkenLine, kijonLine) + span_b := calcLine(Line_spanPeriod, bars) + chiko_index := (len(bars) - int(Line_chikoPeriod)) - 1 + cheko_span := bars[chiko_index] + + var latestPrice *market.Kline + latestPriceIndex := (len(bars) - 1) + if (len(bars) - 1) >= latestPriceIndex { + latestPrice = bars[latestPriceIndex] + } + + if !tenkenLine.isNil && !kijonLine.isNil && !span_a.isNil && !span_b.isNil { + ichi := NewIchimokuStatus(tenkenLine, kijonLine, span_a, span_b, cheko_span, latestPrice) + return ichi, nil + } + + return nil, ErrBuildFailed +} + +func calcLine(line_type ELine, bars []*market.Kline) ValueLine { + high := NewValueLineNil() + low := NewValueLineNil() + l := len(bars) + from := l - 1 - int(line_type) + if from == -1 { + from = 0 + } + bars_tmp := bars[from : l-1] + if len(bars) < int(line_type) { + return NewValueLineNil() + } + for _, v := range bars_tmp { + + if high.isNil { + high.SetValue(v.H) + } + if low.isNil { + low.SetValue(v.L) + } + + if v.H.GreaterThan(high.valLine) { + high.SetValue(v.H) + } + + if v.L.LessThan(low.valLine) { + low.SetValue(v.L) + } + + } + line := low.valLine.Add(high.valLine).Quo(dec.New(2)) + return NewValue(line) +} + +func calculate_span_a(tenken ValueLine, kijon ValueLine) ValueLine { + if !tenken.isNil && !kijon.isNil { + v := tenken.valLine.Add(kijon.valLine).Quo(dec.New(2)) + return NewValue(v) + } + + return NewValueLineNil() +} diff --git a/pkg/indicator/v2/ichimoku1/example/main.go b/pkg/indicator/v2/ichimoku1/example/main.go new file mode 100644 index 0000000000..a8dfc19898 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/example/main.go @@ -0,0 +1,242 @@ +package main + +import ( + "fmt" + "time" + + "github.com/algo-boyz/alphakit/market" + decimal "github.com/algo-boyz/decimal128" + + "github.com/algo-boyz/alphakit/ta/dec" + "github.com/algo-boyz/alphakit/ta/ichimoku" +) + +var interval = time.Minute * 30 + +func d(v float64) decimal.Decimal { + return dec.New(v) +} + +func p(v int64) time.Time { + return time.UnixMilli(v).UTC() +} + +func main() { + + // sort ts [old date to new date] ascending + ts := []*market.Kline{ + {L: d(9450.00), H: d(9570.00), C: d(9490.00), O: d(9530.00), Volume: d(1158096.00), Start: p(1662525000000)}, + {L: d(9450.00), H: d(9550.00), C: d(9480.00), O: d(9530.00), Volume: d(1041077.00), Start: p(1662528600000)}, + {L: d(9420.00), H: d(9520.00), C: d(9500.00), O: d(9500.00), Volume: d(1966815.00), Start: p(1662532200000)}, + {L: d(9480.00), H: d(9520.00), C: d(9510.00), O: d(9480.00), Volume: d(748430.00), Start: p(1662535800000)}, + {L: d(9250.00), H: d(9500.00), C: d(9390.00), O: d(9500.00), Volume: d(1961310.00), Start: p(1662784200000)}, + {L: d(9340.00), H: d(9570.00), C: d(9520.00), O: d(9350.00), Volume: d(1881148.00), Start: p(1662787800000)}, + {L: d(9300.00), H: d(9520.00), C: d(9320.00), O: d(9520.00), Volume: d(2174744.00), Start: p(1662791400000)}, + {L: d(9320.00), H: d(9440.00), C: d(9440.00), O: d(9320.00), Volume: d(428193.00), Start: p(1662795000000)}, + {L: d(9280.00), H: d(9500.00), C: d(9470.00), O: d(9440.00), Volume: d(1174617.00), Start: p(1662870600000)}, + {L: d(9300.00), H: d(9490.00), C: d(9330.00), O: d(9480.00), Volume: d(564590.00), Start: p(1662874200000)}, + {L: d(9260.00), H: d(9360.00), C: d(9300.00), O: d(9330.00), Volume: d(1325195.00), Start: p(1662877800000)}, + {L: d(9280.00), H: d(9360.00), C: d(9360.00), O: d(9290.00), Volume: d(725716.00), Start: p(1662881400000)}, + {L: d(9290.00), H: d(9470.00), C: d(9310.00), O: d(9310.00), Volume: d(1156762.00), Start: p(1662957000000)}, + {L: d(9210.00), H: d(9330.00), C: d(9250.00), O: d(9310.00), Volume: d(1463096.00), Start: p(1662960600000)}, + {L: d(9240.00), H: d(9440.00), C: d(9380.00), O: d(9240.00), Volume: d(1350073.00), Start: p(1662964200000)}, + {L: d(9360.00), H: d(9400.00), C: d(9390.00), O: d(9380.00), Volume: d(526677.00), Start: p(1662967800000)}, + {L: d(9260.00), H: d(9450.00), C: d(9280.00), O: d(9300.00), Volume: d(685445.00), Start: p(1663043400000)}, + {L: d(9270.00), H: d(9450.00), C: d(9440.00), O: d(9280.00), Volume: d(957947.00), Start: p(1663047000000)}, + {L: d(9340.00), H: d(9440.00), C: d(9340.00), O: d(9440.00), Volume: d(716902.00), Start: p(1663050600000)}, + {L: d(9300.00), H: d(9380.00), C: d(9380.00), O: d(9350.00), Volume: d(860525.00), Start: p(1663054200000)}, + {L: d(9230.00), H: d(9360.00), C: d(9250.00), O: d(9300.00), Volume: d(1844161.00), Start: p(1663129800000)}, + {L: d(9230.00), H: d(9290.00), C: d(9240.00), O: d(9250.00), Volume: d(876713.00), Start: p(1663133400000)}, + {L: d(9210.00), H: d(9280.00), C: d(9260.00), O: d(9240.00), Volume: d(909086.00), Start: p(1663137000000)}, + {L: d(9200.00), H: d(9270.00), C: d(9240.00), O: d(9260.00), Volume: d(1347750.00), Start: p(1663140600000)}, + {L: d(9060.00), H: d(9240.00), C: d(9100.00), O: d(9240.00), Volume: d(1513067.00), Start: p(1663475400000)}, + {L: d(9060.00), H: d(9150.00), C: d(9080.00), O: d(9080.00), Volume: d(1770320.00), Start: p(1663479000000)}, + {L: d(8950.00), H: d(9100.00), C: d(8970.00), O: d(9080.00), Volume: d(2172300.00), Start: p(1663482600000)}, + {L: d(8950.00), H: d(9120.00), C: d(9070.00), O: d(8980.00), Volume: d(2417598.00), Start: p(1663486200000)}, + {L: d(8960.00), H: d(9160.00), C: d(9040.00), O: d(8960.00), Volume: d(1154404.00), Start: p(1663561800000)}, + {L: d(8980.00), H: d(9070.00), C: d(8990.00), O: d(9040.00), Volume: d(544846.00), Start: p(1663565400000)}, + {L: d(8930.00), H: d(9020.00), C: d(8960.00), O: d(8990.00), Volume: d(901781.00), Start: p(1663569000000)}, + {L: d(8910.00), H: d(8970.00), C: d(8920.00), O: d(8970.00), Volume: d(1021775.00), Start: p(1663572600000)}, + {L: d(8900.00), H: d(9060.00), C: d(8960.00), O: d(8900.00), Volume: d(1163197.00), Start: p(1663648200000)}, + {L: d(8860.00), H: d(9000.00), C: d(8870.00), O: d(8950.00), Volume: d(932584.00), Start: p(1663651800000)}, + {L: d(8820.00), H: d(8880.00), C: d(8830.00), O: d(8880.00), Volume: d(1458995.00), Start: p(1663655400000)}, + {L: d(8840.00), H: d(8880.00), C: d(8880.00), O: d(8840.00), Volume: d(462403.00), Start: p(1663659000000)}, + {L: d(8800.00), H: d(8900.00), C: d(8820.00), O: d(8810.00), Volume: d(787614.00), Start: p(1663734600000)}, + {L: d(8800.00), H: d(8870.00), C: d(8810.00), O: d(8810.00), Volume: d(677890.00), Start: p(1663738200000)}, + {L: d(8800.00), H: d(8850.00), C: d(8810.00), O: d(8810.00), Volume: d(1599221.00), Start: p(1663741800000)}, + {L: d(8800.00), H: d(8950.00), C: d(8930.00), O: d(8810.00), Volume: d(1817537.00), Start: p(1663745400000)}, + {L: d(8560.00), H: d(8920.00), C: d(8590.00), O: d(8850.00), Volume: d(1956165.00), Start: p(1663997400000)}, + {L: d(8530.00), H: d(8630.00), C: d(8570.00), O: d(8580.00), Volume: d(963507.00), Start: p(1664001000000)}, + {L: d(8560.00), H: d(8650.00), C: d(8560.00), O: d(8570.00), Volume: d(1202470.00), Start: p(1664004600000)}, + {L: d(8470.00), H: d(8570.00), C: d(8490.00), O: d(8560.00), Volume: d(1795527.00), Start: p(1664008200000)}, + {L: d(8360.00), H: d(8900.00), C: d(8860.00), O: d(8360.00), Volume: d(2232707.00), Start: p(1664170200000)}, + {L: d(8700.00), H: d(8850.00), C: d(8710.00), O: d(8850.00), Volume: d(804025.00), Start: p(1664173800000)}, + {L: d(8710.00), H: d(8750.00), C: d(8740.00), O: d(8720.00), Volume: d(490415.00), Start: p(1664177400000)}, + {L: d(8700.00), H: d(8740.00), C: d(8740.00), O: d(8710.00), Volume: d(354268.00), Start: p(1664181000000)}, + {L: d(8720.00), H: d(9000.00), C: d(8960.00), O: d(8720.00), Volume: d(1527278.00), Start: p(1664343000000)}, + {L: d(8910.00), H: d(9060.00), C: d(9000.00), O: d(8960.00), Volume: d(1085106.00), Start: p(1664346600000)}, + {L: d(8980.00), H: d(9030.00), C: d(9020.00), O: d(9000.00), Volume: d(473696.00), Start: p(1664350200000)}, + {L: d(8980.00), H: d(9020.00), C: d(8990.00), O: d(9010.00), Volume: d(699219.00), Start: p(1664353800000)}, + {L: d(8570.00), H: d(8990.00), C: d(8650.00), O: d(8950.00), Volume: d(2525245.00), Start: p(1664602200000)}, + {L: d(8540.00), H: d(8750.00), C: d(8580.00), O: d(8670.00), Volume: d(862745.00), Start: p(1664605800000)}, + {L: d(8400.00), H: d(8590.00), C: d(8450.00), O: d(8570.00), Volume: d(2648031.00), Start: p(1664609400000)}, + {L: d(8400.00), H: d(8490.00), C: d(8430.00), O: d(8470.00), Volume: d(880884.00), Start: p(1664613000000)}, + {L: d(8380.00), H: d(8610.00), C: d(8450.00), O: d(8460.00), Volume: d(2047200.00), Start: p(1664688600000)}, + {L: d(8410.00), H: d(8490.00), C: d(8460.00), O: d(8470.00), Volume: d(508220.00), Start: p(1664692200000)}, + {L: d(8430.00), H: d(8480.00), C: d(8450.00), O: d(8460.00), Volume: d(652416.00), Start: p(1664695800000)}, + {L: d(8400.00), H: d(8460.00), C: d(8440.00), O: d(8440.00), Volume: d(906352.00), Start: p(1664699400000)}, + {L: d(8420.00), H: d(8600.00), C: d(8480.00), O: d(8490.00), Volume: d(826543.00), Start: p(1664775000000)}, + {L: d(8430.00), H: d(8570.00), C: d(8450.00), O: d(8480.00), Volume: d(867974.00), Start: p(1664778600000)}, + {L: d(8430.00), H: d(8480.00), C: d(8450.00), O: d(8450.00), Volume: d(580218.00), Start: p(1664782200000)}, + {L: d(8440.00), H: d(8540.00), C: d(8500.00), O: d(8450.00), Volume: d(957990.00), Start: p(1664785800000)}, + {L: d(8400.00), H: d(8560.00), C: d(8500.00), O: d(8400.00), Volume: d(659743.00), Start: p(1664861400000)}, + {L: d(8450.00), H: d(8500.00), C: d(8480.00), O: d(8500.00), Volume: d(1096047.00), Start: p(1664865000000)}, + {L: d(8490.00), H: d(8520.00), C: d(8500.00), O: d(8490.00), Volume: d(390241.00), Start: p(1664868600000)}, + {L: d(8480.00), H: d(8530.00), C: d(8520.00), O: d(8510.00), Volume: d(1052288.00), Start: p(1664872200000)}, + {L: d(8400.00), H: d(8650.00), C: d(8620.00), O: d(8400.00), Volume: d(1420025.00), Start: p(1665207000000)}, + {L: d(8580.00), H: d(8630.00), C: d(8580.00), O: d(8630.00), Volume: d(664976.00), Start: p(1665210600000)}, + {L: d(8520.00), H: d(8580.00), C: d(8520.00), O: d(8570.00), Volume: d(811777.00), Start: p(1665214200000)}, + {L: d(8500.00), H: d(8640.00), C: d(8620.00), O: d(8520.00), Volume: d(1135548.00), Start: p(1665217800000)}, + {L: d(8360.00), H: d(8620.00), C: d(8400.00), O: d(8460.00), Volume: d(1757266.00), Start: p(1665293400000)}, + {L: d(8390.00), H: d(8540.00), C: d(8410.00), O: d(8400.00), Volume: d(2069165.00), Start: p(1665297000000)}, + {L: d(8370.00), H: d(8460.00), C: d(8450.00), O: d(8420.00), Volume: d(1283825.00), Start: p(1665300600000)}, + {L: d(8450.00), H: d(8550.00), C: d(8550.00), O: d(8450.00), Volume: d(1443903.00), Start: p(1665304200000)}, + {L: d(8460.00), H: d(8590.00), C: d(8500.00), O: d(8500.00), Volume: d(792803.00), Start: p(1665379800000)}, + {L: d(8420.00), H: d(8520.00), C: d(8470.00), O: d(8510.00), Volume: d(1158445.00), Start: p(1665383400000)}, + {L: d(8460.00), H: d(8500.00), C: d(8490.00), O: d(8480.00), Volume: d(806689.00), Start: p(1665387000000)}, + {L: d(8460.00), H: d(8540.00), C: d(8540.00), O: d(8490.00), Volume: d(1334939.00), Start: p(1665390600000)}, + {L: d(8490.00), H: d(8900.00), C: d(8800.00), O: d(8490.00), Volume: d(2464838.00), Start: p(1665466200000)}, + {L: d(8700.00), H: d(8900.00), C: d(8740.00), O: d(8810.00), Volume: d(2086815.00), Start: p(1665469800000)}, + {L: d(8730.00), H: d(8820.00), C: d(8750.00), O: d(8740.00), Volume: d(911276.00), Start: p(1665473400000)}, + {L: d(8740.00), H: d(8890.00), C: d(8890.00), O: d(8760.00), Volume: d(1329047.00), Start: p(1665477000000)}, + {L: d(8720.00), H: d(8960.00), C: d(8800.00), O: d(8900.00), Volume: d(1709787.00), Start: p(1665552600000)}, + {L: d(8790.00), H: d(8850.00), C: d(8840.00), O: d(8800.00), Volume: d(1069264.00), Start: p(1665556200000)}, + {L: d(8840.00), H: d(8930.00), C: d(8900.00), O: d(8840.00), Volume: d(1340324.00), Start: p(1665559800000)}, + {L: d(8880.00), H: d(8950.00), C: d(8950.00), O: d(8900.00), Volume: d(1694492.00), Start: p(1665563400000)}, + {L: d(8750.00), H: d(8960.00), C: d(8900.00), O: d(8750.00), Volume: d(1787429.00), Start: p(1665811800000)}, + {L: d(8780.00), H: d(8910.00), C: d(8780.00), O: d(8910.00), Volume: d(1494451.00), Start: p(1665815400000)}, + {L: d(8730.00), H: d(8880.00), C: d(8820.00), O: d(8780.00), Volume: d(924913.00), Start: p(1665819000000)}, + {L: d(8790.00), H: d(8900.00), C: d(8860.00), O: d(8820.00), Volume: d(1028523.00), Start: p(1665822600000)}, + {L: d(8640.00), H: d(8880.00), C: d(8650.00), O: d(8870.00), Volume: d(1524800.00), Start: p(1665898200000)}, + {L: d(8620.00), H: d(8700.00), C: d(8690.00), O: d(8680.00), Volume: d(1513406.00), Start: p(1665901800000)}, + {L: d(8570.00), H: d(8690.00), C: d(8600.00), O: d(8640.00), Volume: d(1445787.00), Start: p(1665905400000)}, + {L: d(8490.00), H: d(8690.00), C: d(8500.00), O: d(8590.00), Volume: d(1722207.00), Start: p(1665909000000)}, + {L: d(8500.00), H: d(8650.00), C: d(8500.00), O: d(8500.00), Volume: d(795140.00), Start: p(1665984600000)}, + {L: d(8510.00), H: d(8580.00), C: d(8550.00), O: d(8510.00), Volume: d(488220.00), Start: p(1665988200000)}, + {L: d(8530.00), H: d(8610.00), C: d(8600.00), O: d(8550.00), Volume: d(501777.00), Start: p(1665991800000)}, + {L: d(8540.00), H: d(8700.00), C: d(8690.00), O: d(8590.00), Volume: d(1029969.00), Start: p(1665995400000)}, + {L: d(8600.00), H: d(8750.00), C: d(8680.00), O: d(8600.00), Volume: d(911243.00), Start: p(1666071000000)}, + {L: d(8630.00), H: d(8700.00), C: d(8650.00), O: d(8680.00), Volume: d(757086.00), Start: p(1666074600000)}, + {L: d(8600.00), H: d(8700.00), C: d(8700.00), O: d(8640.00), Volume: d(425422.00), Start: p(1666078200000)}, + {L: d(8630.00), H: d(8730.00), C: d(8700.00), O: d(8640.00), Volume: d(660782.00), Start: p(1666081800000)}, + {L: d(8600.00), H: d(8720.00), C: d(8670.00), O: d(8620.00), Volume: d(469671.00), Start: p(1666157400000)}, + {L: d(8650.00), H: d(8700.00), C: d(8660.00), O: d(8670.00), Volume: d(546293.00), Start: p(1666161000000)}, + {L: d(8620.00), H: d(8670.00), C: d(8670.00), O: d(8650.00), Volume: d(804228.00), Start: p(1666164600000)}, + {L: d(8660.00), H: d(8730.00), C: d(8700.00), O: d(8670.00), Volume: d(1012749.00), Start: p(1666168200000)}, + {L: d(8580.00), H: d(8840.00), C: d(8720.00), O: d(8580.00), Volume: d(939987.00), Start: p(1666416600000)}, + {L: d(8700.00), H: d(8830.00), C: d(8720.00), O: d(8720.00), Volume: d(1003220.00), Start: p(1666420200000)}, + {L: d(8680.00), H: d(8780.00), C: d(8680.00), O: d(8730.00), Volume: d(767169.00), Start: p(1666423800000)}, + {L: d(8610.00), H: d(8770.00), C: d(8610.00), O: d(8680.00), Volume: d(472382.00), Start: p(1666427400000)}, + {L: d(8500.00), H: d(8610.00), C: d(8500.00), O: d(8610.00), Volume: d(785573.00), Start: p(1666503000000)}, + {L: d(8490.00), H: d(8540.00), C: d(8490.00), O: d(8500.00), Volume: d(1158605.00), Start: p(1666506600000)}, + {L: d(8450.00), H: d(8520.00), C: d(8520.00), O: d(8490.00), Volume: d(797369.00), Start: p(1666510200000)}, + {L: d(8450.00), H: d(8530.00), C: d(8450.00), O: d(8510.00), Volume: d(816922.00), Start: p(1666513800000)}, + {L: d(8490.00), H: d(8580.00), C: d(8520.00), O: d(8580.00), Volume: d(965156.00), Start: p(1666589400000)}, + {L: d(8380.00), H: d(8520.00), C: d(8380.00), O: d(8520.00), Volume: d(1881966.00), Start: p(1666593000000)}, + {L: d(8300.00), H: d(8430.00), C: d(8310.00), O: d(8380.00), Volume: d(1552299.00), Start: p(1666596600000)}, + {L: d(8290.00), H: d(8360.00), C: d(8340.00), O: d(8310.00), Volume: d(1326790.00), Start: p(1666600200000)}, + {L: d(8280.00), H: d(8450.00), C: d(8320.00), O: d(8450.00), Volume: d(1639128.00), Start: p(1666675800000)}, + {L: d(8160.00), H: d(8320.00), C: d(8180.00), O: d(8310.00), Volume: d(2019753.00), Start: p(1666679400000)}, + {L: d(8170.00), H: d(8320.00), C: d(8200.00), O: d(8180.00), Volume: d(1416805.00), Start: p(1666683000000)}, + {L: d(8150.00), H: d(8230.00), C: d(8190.00), O: d(8200.00), Volume: d(1475601.00), Start: p(1666686600000)}, + {L: d(8010.00), H: d(8260.00), C: d(8010.00), O: d(8150.00), Volume: d(1740023.00), Start: p(1666762200000)}, + {L: d(7920.00), H: d(8040.00), C: d(7940.00), O: d(8010.00), Volume: d(4274066.00), Start: p(1666765800000)}, + {L: d(7920.00), H: d(7950.00), C: d(7920.00), O: d(7940.00), Volume: d(3708253.00), Start: p(1666769400000)}, + {L: d(7920.00), H: d(8040.00), C: d(8020.00), O: d(7920.00), Volume: d(2467113.00), Start: p(1666773000000)}, + {L: d(7990.00), H: d(8230.00), C: d(7990.00), O: d(8230.00), Volume: d(3782570.00), Start: p(1667021400000)}, + {L: d(7900.00), H: d(8010.00), C: d(7900.00), O: d(7990.00), Volume: d(4110182.00), Start: p(1667025000000)}, + {L: d(7740.00), H: d(7970.00), C: d(7750.00), O: d(7910.00), Volume: d(1834825.00), Start: p(1667028600000)}, + {L: d(7690.00), H: d(7800.00), C: d(7760.00), O: d(7760.00), Volume: d(2606139.00), Start: p(1667032200000)}, + {L: d(7820.00), H: d(7990.00), C: d(7950.00), O: d(7950.00), Volume: d(4859163.00), Start: p(1667107800000)}, + {L: d(7920.00), H: d(8030.00), C: d(8010.00), O: d(7960.00), Volume: d(4220234.00), Start: p(1667111400000)}, + {L: d(8000.00), H: d(8080.00), C: d(8050.00), O: d(8010.00), Volume: d(1975520.00), Start: p(1667115000000)}, + {L: d(8030.00), H: d(8210.00), C: d(8200.00), O: d(8040.00), Volume: d(2780194.00), Start: p(1667118600000)}, + {L: d(8070.00), H: d(8250.00), C: d(8210.00), O: d(8070.00), Volume: d(1003287.00), Start: p(1667194200000)}, + {L: d(8100.00), H: d(8210.00), C: d(8110.00), O: d(8210.00), Volume: d(642473.00), Start: p(1667197800000)}, + {L: d(8110.00), H: d(8180.00), C: d(8160.00), O: d(8110.00), Volume: d(664372.00), Start: p(1667201400000)}, + {L: d(8100.00), H: d(8260.00), C: d(8200.00), O: d(8150.00), Volume: d(1241301.00), Start: p(1667205000000)}, + {L: d(8110.00), H: d(8450.00), C: d(8440.00), O: d(8170.00), Volume: d(2909458.00), Start: p(1667280600000)}, + {L: d(8310.00), H: d(8450.00), C: d(8360.00), O: d(8440.00), Volume: d(778238.00), Start: p(1667284200000)}, + {L: d(8240.00), H: d(8370.00), C: d(8260.00), O: d(8360.00), Volume: d(658420.00), Start: p(1667287800000)}, + {L: d(8240.00), H: d(8450.00), C: d(8440.00), O: d(8260.00), Volume: d(1814124.00), Start: p(1667291400000)}, + {L: d(8270.00), H: d(8440.00), C: d(8300.00), O: d(8440.00), Volume: d(1267103.00), Start: p(1667367000000)}, + {L: d(8270.00), H: d(8510.00), C: d(8510.00), O: d(8300.00), Volume: d(1821017.00), Start: p(1667370600000)}, + {L: d(8430.00), H: d(8540.00), C: d(8440.00), O: d(8510.00), Volume: d(559250.00), Start: p(1667374200000)}, + {L: d(8420.00), H: d(8470.00), C: d(8440.00), O: d(8440.00), Volume: d(544851.00), Start: p(1667377800000)}, + {L: d(8480.00), H: d(8730.00), C: d(8730.00), O: d(8550.00), Volume: d(4284720.00), Start: p(1667626200000)}, + {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(1382828.00), Start: p(1667629800000)}, + {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(1678201.00), Start: p(1667633400000)}, + {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(549277.00), Start: p(1667637000000)}, + {L: d(8800.00), H: d(9070.00), C: d(9060.00), O: d(8800.00), Volume: d(5342062.00), Start: p(1667712600000)}, + {L: d(9040.00), H: d(9070.00), C: d(9070.00), O: d(9060.00), Volume: d(8126959.00), Start: p(1667716200000)}, + {L: d(9070.00), H: d(9070.00), C: d(9070.00), O: d(9070.00), Volume: d(527101.00), Start: p(1667719800000)}, + {L: d(9070.00), H: d(9070.00), C: d(9070.00), O: d(9070.00), Volume: d(702521.00), Start: p(1667723400000)}, + {L: d(9160.00), H: d(9440.00), C: d(9430.00), O: d(9290.00), Volume: d(4409696.00), Start: p(1667799000000)}, + {L: d(9410.00), H: d(9490.00), C: d(9490.00), O: d(9420.00), Volume: d(7522839.00), Start: p(1667802600000)}, + {L: d(9490.00), H: d(9490.00), C: d(9490.00), O: d(9490.00), Volume: d(777299.00), Start: p(1667806200000)}, + {L: d(9490.00), H: d(9490.00), C: d(9490.00), O: d(9490.00), Volume: d(405416.00), Start: p(1667809800000)}, + {L: d(9300.00), H: d(9890.00), C: d(9530.00), O: d(9890.00), Volume: d(7097789.00), Start: p(1667885400000)}, + {L: d(9460.00), H: d(9570.00), C: d(9470.00), O: d(9520.00), Volume: d(3033312.00), Start: p(1667889000000)}, + {L: d(9380.00), H: d(9490.00), C: d(9410.00), O: d(9470.00), Volume: d(2714433.00), Start: p(1667892600000)}, + {L: d(9390.00), H: d(9490.00), C: d(9450.00), O: d(9420.00), Volume: d(3876877.00), Start: p(1667896200000)}, + {L: d(9250.00), H: d(9540.00), C: d(9410.00), O: d(9350.00), Volume: d(3448605.00), Start: p(1667971800000)}, + {L: d(9400.00), H: d(9840.00), C: d(9800.00), O: d(9410.00), Volume: d(6547559.00), Start: p(1667975400000)}, + {L: d(9640.00), H: d(9830.00), C: d(9650.00), O: d(9800.00), Volume: d(2416825.00), Start: p(1667979000000)}, + {L: d(9650.00), H: d(9860.00), C: d(9680.00), O: d(9700.00), Volume: d(2463503.00), Start: p(1667982600000)}, + {L: d(9640.00), H: d(9870.00), C: d(9800.00), O: d(9750.00), Volume: d(2000789.00), Start: p(1668231000000)}, + {L: d(9520.00), H: d(9800.00), C: d(9520.00), O: d(9780.00), Volume: d(3214849.00), Start: p(1668234600000)}, + {L: d(9520.00), H: d(9680.00), C: d(9620.00), O: d(9550.00), Volume: d(3019512.00), Start: p(1668238200000)}, + {L: d(9610.00), H: d(9810.00), C: d(9740.00), O: d(9640.00), Volume: d(2473212.00), Start: p(1668241800000)}, + {L: d(9450.00), H: d(9710.00), C: d(9530.00), O: d(9710.00), Volume: d(1455003.00), Start: p(1668317400000)}, + {L: d(9510.00), H: d(9700.00), C: d(9700.00), O: d(9520.00), Volume: d(1341450.00), Start: p(1668321000000)}, + {L: d(9520.00), H: d(9720.00), C: d(9650.00), O: d(9700.00), Volume: d(2922575.00), Start: p(1668324600000)}, + {L: d(9470.00), H: d(9650.00), C: d(9470.00), O: d(9650.00), Volume: d(907574.00), Start: p(1668328200000)}, + {L: d(9250.00), H: d(9620.00), C: d(9250.00), O: d(9510.00), Volume: d(1573592.00), Start: p(1668403800000)}, + {L: d(9220.00), H: d(9420.00), C: d(9380.00), O: d(9270.00), Volume: d(1372258.00), Start: p(1668407400000)}, + {L: d(9340.00), H: d(9530.00), C: d(9490.00), O: d(9380.00), Volume: d(3147032.00), Start: p(1668411000000)}, + {L: d(9370.00), H: d(9550.00), C: d(9370.00), O: d(9490.00), Volume: d(2153637.00), Start: p(1668414600000)}, + {L: d(9380.00), H: d(9750.00), C: d(9670.00), O: d(9450.00), Volume: d(1861478.00), Start: p(1668490200000)}, + {L: d(9580.00), H: d(9700.00), C: d(9650.00), O: d(9670.00), Volume: d(2890813.00), Start: p(1668493800000)}, + {L: d(9610.00), H: d(9700.00), C: d(9670.00), O: d(9610.00), Volume: d(1288957.00), Start: p(1668497400000)}, + {L: d(9630.00), H: d(9800.00), C: d(9730.00), O: d(9650.00), Volume: d(2413843.00), Start: p(1668501000000)}, + {L: d(9580.00), H: d(9780.00), C: d(9630.00), O: d(9750.00), Volume: d(803830.00), Start: p(1668576600000)}, + {L: d(9630.00), H: d(9720.00), C: d(9670.00), O: d(9650.00), Volume: d(699785.00), Start: p(1668580200000)}, + {L: d(9640.00), H: d(9700.00), C: d(9640.00), O: d(9700.00), Volume: d(393592.00), Start: p(1668583800000)}, + {L: d(9580.00), H: d(9660.00), C: d(9630.00), O: d(9640.00), Volume: d(1443871.00), Start: p(1668587400000)}, + {L: d(9300.00), H: d(9600.00), C: d(9370.00), O: d(9510.00), Volume: d(3845936.00), Start: p(1668835800000)}, + {L: d(9310.00), H: d(9380.00), C: d(9330.00), O: d(9380.00), Volume: d(1380628.00), Start: p(1668839400000)}, + } + + indicator := ichimoku.NewIndicator() + + err := indicator.MakeIchimokuInPast(ts, 135) + if err != nil { + fmt.Println("error :", err) + } + + lines_result := make([]*ichimoku.IchimokuStatus, 2) + arr := indicator.GetList() + for i := len(arr) - 2; i > 0; i-- { + lines_result[0] = arr[i] //current + lines_result[1] = arr[i+1] // previous + + a, e := indicator.PreAnalyseIchimoku(lines_result) + + if e != nil { + fmt.Println("err", e) + } + if a != nil { + fmt.Print(a.Print()) + } + } +} diff --git a/pkg/indicator/v2/ichimoku1/images/demo.png b/pkg/indicator/v2/ichimoku1/images/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..8162b8415c9ac0c706d70358e31ec8324b6f843f GIT binary patch literal 131507 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%0Dl@deHxuq4VSFst+qfB33@ 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 JB>07x{{XirAAkS= literal 0 HcmV?d00001 diff --git a/pkg/indicator/v2/ichimoku1/indicator.go b/pkg/indicator/v2/ichimoku1/indicator.go new file mode 100644 index 0000000000..b38e801115 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/indicator.go @@ -0,0 +1,293 @@ +package ichimoku + +import ( + "fmt" + + "github.com/algo-boyz/alphakit/market" + decimal "github.com/algo-boyz/decimal128" + + "github.com/algo-boyz/alphakit/ta/dec" +) + +type IIchimokuIndicator interface { + // out result array sort: [new day -to- old day] + // one call per asset + MakeIchimokuInPast(bars []*market.Kline, numberOfRead int) error + + //one call per asset + PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) + + //Analyse Trigger Cross tenken & kijon sen + AnalyseTriggerCross(previous *IchimokuStatus, bars_only_25_bars_latest []*market.Kline) (*IchimokuStatus, error) + + GetLast() *IchimokuStatus + GetList() []*IchimokuStatus +} + +type IchimokuIndicator struct { + line_helper lineHelper + series []*market.Kline + Ichimokus []*IchimokuStatus + ConversionLine []float64 + BaseLine []float64 + LeadingSpanA []float64 + LeadingSpanB []float64 + laggingSpan []float64 +} + +func NewIndicator() IIchimokuIndicator { + xx := IchimokuIndicator{} + xx.Ichimokus = make([]*IchimokuStatus, 0) + xx.line_helper = NewLineHelper() + return &xx +} + +func (xx *IchimokuIndicator) loadbars(from int, to int) []*market.Kline { + if len(xx.series) == 0 { + return nil + } + if from < 0 { + from = 0 + } + if to > len(xx.series) { + to = len(xx.series) + } + + return xx.series[from:to] + +} + +func (o *IchimokuIndicator) GetList() []*IchimokuStatus { + return o.Ichimokus +} + +func (o *IchimokuIndicator) MakeIchimokuInPast(series []*market.Kline, numberOfRead int) error { + length := len(series) + if length == 0 { + return ErrDataNotFill + } + + if length < numberOfRead || length < 52 { + return ErrNotEnoughData + } + + fmt.Printf("Calc ichi from Last %v days on %d total candles\r\n", numberOfRead, len(series)) + o.series = series + + // descending + bars_len := len(o.series) + for day := 0; day < numberOfRead; day++ { + + from := bars_len - 52 - day + to := bars_len - day + + ic, err := BuildIchimokuStatus(o.loadbars(from, to)) + if err != nil { + return err + } + o.Put(ic) + + } + + for day_index := 0; day_index < o.NumberOfIchimokus(); day_index++ { + item := o.Ichimokus[day_index] + sen_a, sen_b := o.Calc_Cloud_InPast(day_index) + item.Set_SenCo_A_Past(sen_a) + item.Set_SenCo_B_Past(sen_b) + } + + return nil + +} + +// analyse with two days +func (o *IchimokuIndicator) FindStatusin26BarPast() { + + for i := 0; i < o.NumberOfIchimokus(); i++ { + item := o.Ichimokus[i] + sen_a, sen_b := o.Calc_Cloud_InPast(i) + item.Set_SenCo_A_Past(sen_a) + item.Set_SenCo_B_Past(sen_b) + } + +} + +// Analyse Trigger Cross tenken & kijon sen +// bars : contain with new bar +func (o *IchimokuIndicator) AnalyseTriggerCross(previous *IchimokuStatus, _52_bars_latest []*market.Kline) (*IchimokuStatus, error) { + + if len(_52_bars_latest) == 0 { + return nil, ErrDataNotFill + } + + if len(_52_bars_latest) < 52 { + return nil, ErrNotEnoughData + } + + newIchi, e := BuildIchimokuStatus(_52_bars_latest) + + if e != nil { + return nil, e + } + sen_a_in_26_past, sen_b_in_26_past := o.Calc_Cloud_InPast(0) + + if sen_a_in_26_past.isNil || sen_b_in_26_past.isNil { + return nil, ErrChikoStatus26InPastNotMade + } + + newIchi.Set_SenCo_A_Past(sen_a_in_26_past) + newIchi.Set_SenCo_B_Past(sen_b_in_26_past) + + if newIchi.SencoA_Past.isNil || newIchi.SencoB_Past.isNil { + return nil, ErrChikoStatus26InPastNotMade + } + + if !newIchi.bar.Start.After(previous.bar.Start) { + return nil, ErrDateNotGreaterThanPrevious + } + has_collision1, intersection := o.CrossCheck(previous, newIchi) + if has_collision1 == EInterSectionStatus_Find { + newIchi.SetStatus(newIchi.CloudStatus(intersection)) + newIchi.SetCloudSwitching(o.isSwitchCloud(previous, newIchi)) + + return newIchi, nil + } + return nil, nil + +} + +// analyse with two days +func (o *IchimokuIndicator) PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) { + + if len(data) != 2 { + return nil, ErrNotEnoughData + } + + current := data[0] + previous := data[1] + + line1_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.TenkenSen.valLine) + line1_point_b := NewPoint(dec.New(current.bar.Start.Unix()), current.TenkenSen.valLine) + + line2_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.KijonSen.valLine) + line2_point_b := NewPoint(dec.New(current.bar.Start.Unix()), current.KijonSen.valLine) + + has_collision1, intersection := o.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) + + if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { + return nil, nil + } + + Line_Eq_A := o.getLineEquation(line1_point_a, line1_point_b) // tenken + Line_Eq_B := o.getLineEquation(line2_point_a, line2_point_b) //kijon + + if line1_point_a == line2_point_a { + return nil, nil //paraller + + } + + if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { + return nil, nil + + } + + if has_collision1 == EInterSectionStatus_Find { + + current.SetStatus(current.CloudStatus(intersection)) + + current.SetCloudSwitching(o.isSwitchCloud(previous, current)) + return current, nil + } + return nil, nil +} + +func (o *IchimokuIndicator) NumberOfIchimokus() int { + return len(o.Ichimokus) +} + +func (o *IchimokuIndicator) GetLast() *IchimokuStatus { + + if o.Ichimokus != nil && len(o.Ichimokus) == 0 { + return nil + } + + latest := o.Ichimokus[0] + + return latest +} +func (o *IchimokuIndicator) Put(v *IchimokuStatus) { + o.Ichimokus = append(o.Ichimokus, v) +} + +// -------------------------------------------------------------------------------------------------------- +func (o *IchimokuIndicator) CrossCheck(previous, newIchi *IchimokuStatus) (EInterSectionStatus, decimal.Decimal) { + line1_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.TenkenSen.valLine) + line1_point_b := NewPoint(dec.New(newIchi.bar.Start.Unix()), newIchi.TenkenSen.valLine) + + line2_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.KijonSen.valLine) + line2_point_b := NewPoint(dec.New(newIchi.bar.Start.Unix()), newIchi.KijonSen.valLine) + + has_collision1, intersection := o.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) + + if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { + return EInterSectionStatus_NAN, decimal.Zero + } + + Line_Eq_A := o.getLineEquation(line1_point_a, line1_point_b) // tenken + Line_Eq_B := o.getLineEquation(line2_point_a, line2_point_b) //kijon + + if line1_point_a == line2_point_a { + return EInterSectionStatus_NAN, intersection //paraller + + } + + if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { + return EInterSectionStatus_NAN, intersection + + } + return has_collision1, intersection +} + +// analyse with two days +func (o *IchimokuIndicator) isSwitchCloud(previous, current *IchimokuStatus) bool { + + if previous.SenKoA_Shifted26.valLine.GreaterThanOrEqual(previous.SenKoB_Shifted26.valLine) && + current.SenKoA_Shifted26.valLine.GreaterThan(current.SenKoB_Shifted26.valLine) || + previous.SenKoA_Shifted26.valLine.LessThan(previous.SenKoB_Shifted26.valLine) && + current.SenKoA_Shifted26.valLine.GreaterThanOrEqual(current.SenKoB_Shifted26.valLine) { + if current.TenkenSen.valLine.GreaterThanOrEqual(current.KijonSen.valLine) { + return true + } + } + return false +} + +// find cloud Span A,B in Past (26 day ) +func (o *IchimokuIndicator) Calc_Cloud_InPast(current int) (Point, Point) { + + if o.NumberOfIchimokus() < 26 { + return NewNilPoint(), NewNilPoint() + } + + rem := o.NumberOfIchimokus() - current + max := 26 //from 26 bar in past (find Shift index) + + if rem < max { + return NewNilPoint(), NewNilPoint() + } + + index := current + 25 + c := o.Ichimokus[index] + buff_senco_a := NewPoint(dec.New(c.bar.Start.Unix()/1000), c.SenKoA_Shifted26.valLine) + buff_senco_b := NewPoint(dec.New(c.bar.Start.Unix()/1000), c.SenKoB_Shifted26.valLine) + + return buff_senco_a, buff_senco_b +} + +func (o *IchimokuIndicator) getLineEquation(p1 Point, p2 Point) *Equation { + eq := Equation{} + eq.Slope = (p2.Y.Sub(p1.Y)).Mul(p2.X.Sub(p1.X)) + //eq.Intercept = (-1 * eq.Slope * p1.X) + p1.Y + eq.Intercept = p1.Y.Sub(eq.Slope).Mul(p1.X) + return &eq +} diff --git a/pkg/indicator/v2/ichimoku1/line-value.go b/pkg/indicator/v2/ichimoku1/line-value.go new file mode 100644 index 0000000000..cc2ce0c64b --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/line-value.go @@ -0,0 +1,28 @@ +package ichimoku + +import decimal "github.com/algo-boyz/decimal128" + +type ValueLine struct { + valLine decimal.Decimal + isNil bool +} + +func (n *ValueLine) Value() interface{} { + if n.isNil { + return nil + } + return n.valLine +} + +func (n *ValueLine) SetValue(v decimal.Decimal) { + n.valLine = v + n.isNil = false +} + +func NewValue(x decimal.Decimal) ValueLine { + return ValueLine{x, false} +} + +func NewValueLineNil() ValueLine { + return ValueLine{decimal.Zero, true} +} diff --git a/pkg/indicator/v2/ichimoku1/line_helper.go b/pkg/indicator/v2/ichimoku1/line_helper.go new file mode 100644 index 0000000000..cab244f355 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/line_helper.go @@ -0,0 +1,163 @@ +package ichimoku + +import ( + "fmt" + + "github.com/algo-boyz/alphakit/ta/dec" + decimal "github.com/algo-boyz/decimal128" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +type lineHelper struct { +} +type EPointLocation int + +const ( + EPointLocation_NAN EPointLocation = 0 + EPointLocation_above EPointLocation = 1 + EPointLocation_below EPointLocation = 2 + EPointLocation_overlap EPointLocation = 3 +) + +func NewLineHelper() lineHelper { + f := lineHelper{} + return f +} + +// check Point above or below line +func (n *lineHelper) isAboveLine(point Point, line []Point) EPointLocation { + zero := fixedpoint.Zero + if len(line) < 2 { + return EPointLocation_NAN + } + + checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) EPointLocation { + //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) + // v := (p.X-line_p_a.X)*(line_p_b.Y-line_p_a.Y) - (p.Y-line_p_a.Y)*(line_p_b.X-line_p_a.X) + yOverX := p.Y.Sub(line_p_a.Y).Mul(line_p_b.X.Sub(line_p_a.X)) + xOverY := p.X.Sub(line_p_a.X).Mul(line_p_b.Y.Sub(line_p_a.Y)) + v := xOverY.Sub(yOverX) + + if v.Cmp(zero) == 0 { + return EPointLocation_overlap + } else if v > zero { + return EPointLocation_above + } else { + return EPointLocation_below + } + } + + return checkAboveOrBelow(point, line[0], line[1]) + +} + +func (n *lineHelper) positionPointInline(point Point, line []Point) decimal.Decimal { + zero := fixedpoint.Zero + + if len(line) < 2 { + return zero + } + + checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) decimal.Decimal { + //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) + return (p.X.Sub(line_p_a.X)).Mul(line_p_b.Y.Sub(line_p_a.Y)).Sub(p.Y.Sub(line_p_a.Y)).Mul(line_p_b.X.Sub(line_p_a.X)) + } + + res := checkAboveOrBelow(point, line[0], line[1]) + + return res + +} + +func (o *lineHelper) GetCollisionDetection(a Point, b Point, c Point, d Point) (EInterSectionStatus, decimal.Decimal) { + + denominator := ((b.X.Sub(a.X)).Mul(d.Y.Sub(c.Y))).Sub((b.Y.Sub(a.Y)).Mul(d.X.Sub(c.X))) + numerator1 := ((a.Y.Sub(c.Y)).Mul(d.X.Sub(c.X))).Sub((a.X.Sub(c.X)).Mul(d.Y.Sub(c.Y))) + numerator2 := ((a.Y.Sub(c.Y)).Mul(b.X.Sub(a.X))).Sub((a.X.Sub(c.X)).Mul(b.Y.Sub(a.Y))) + + // Detect coincident lines (has a problem, read below) + if denominator.Cmp(decimal.Zero) == 0 { + return EInterSectionStatus_NAN, decimal.Zero + } + r := numerator1.Quo(denominator) + s := numerator2.Quo(denominator) + one := dec.New(1) + if (r.GreaterThanOrEqual(decimal.Zero) && + r.LessThanOrEqual(one)) && + (s.GreaterThanOrEqual(decimal.Zero) && + s.LessThanOrEqual(one)) { + // fmt.Printf("collision detec : a:%v , b:%v, c:%v ,d:%v ,r %v s %v\r\n", a, b, c, d, r, s) + intersection := o.get_intersection_point(a, b, c, d) + + return EInterSectionStatus_Collision_Find, intersection + } + return EInterSectionStatus_NAN, decimal.Zero +} + +//line senco A or B +func (o *lineHelper) GetCollisionWithLine(price_point Point, line_clouds []Point) (EPointLocation, error) { + zero := fixedpoint.Zero + + len_line_clouds := len(line_clouds) + if len_line_clouds < 1 { + return EPointLocation_NAN, ErrNotEnoughData + } + // Create a point at infinity, y is same as point p + //x := time.Now().AddDate(0, -1, 0).Unix() + //line1_a := NewPoint(decimal.NewFromInt(x), price_point.Y) + // line1_b := price_point + // line_b := NewPoint(0,price_point) + //var ps EPointLocation = EPointLocation_NaN + below := 0 + above := 0 + fmt.Println("___") + fmt.Printf("Cloud : check point :x:%.0f y:%.0f \r\n", price_point.X.Float64(), price_point.Y.Float64()) + sum := dec.New(0) + for i := 1; i < len_line_clouds; i++ { + line2_a := line_clouds[i-1] + line2_b := line_clouds[i] + //fmt.Printf("Cloud :x:%.0f y:%.0f ,\r\n", line2_a.X, line2_a.Y) + fmt.Printf("%.0f,%.0f,\r\n", line2_a.X.Float64(), line2_a.Y.Float64()) + //res := o.GetCollisionDetection(line1_a, line1_b, line2_a, line2_b) + buff := []Point{line2_a, line2_b} + // res := o.isAboveLine(price_point, buff) + c := o.positionPointInline(price_point, buff) + if c > zero { //below + below++ + } else { + above++ + } + + sum = sum.Add(c) + + } + v := sum.Quo(dec.New(int64(len_line_clouds))) + + if v > zero { + return EPointLocation_below, nil // above + } else { + return EPointLocation_above, nil //below + } + +} +func (o *lineHelper) getLineEquation(p1 Point, p2 Point) *Equation { + eq := Equation{} + x := p1.X.Sub(p2.X) + y := p1.Y.Sub(p2.Y) + eq.Slope = y.Quo(x) + eq.Intercept = dec.New(-1).Mul(eq.Slope).Mul(p1.X).Add(p1.Y) + return &eq +} + +func (o *lineHelper) get_intersection_point(line1_pointA Point, line1_pointB Point, line2_pointA Point, line2_pointB Point) decimal.Decimal { + + tenken := o.getLineEquation(line1_pointA, line1_pointB) + kijon := o.getLineEquation(line2_pointA, line2_pointB) + intercept := kijon.Intercept.Sub(tenken.Intercept) + slope := tenken.Slope.Sub(kijon.Slope) + x_intersection := intercept.Quo(slope) + x := kijon.Slope.Mul(x_intersection) + y_intersection := x.Add(kijon.Intercept) + return y_intersection +} diff --git a/pkg/indicator/v2/ichimoku1/status.go b/pkg/indicator/v2/ichimoku1/status.go new file mode 100644 index 0000000000..24f251cbde --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/status.go @@ -0,0 +1,150 @@ +package ichimoku + +import ( + "fmt" + "time" + + "github.com/algo-boyz/alphakit/market" + decimal "github.com/algo-boyz/decimal128" + + "github.com/c9s/bbgo/pkg/types" +) + +type IchimokuStatus struct { + TenkenSen ValueLine + + //_______________ + + KijonSen ValueLine + + //in the future + SenKoA_Shifted26 ValueLine + + //in the future + SenKoB_Shifted26 ValueLine + + //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) + //SencoA 26 candle in the past (for check) + SencoA_Past Point + //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) + //SencoB 26 candle in the past (for check) + SencoB_Past Point + + ChikoSpan *types.KLine //close bar + + bar *types.KLine + //----- + Status EIchimokuStatus + cloudSwitching bool + + line_helper lineHelper +} + +func NewIchimokuStatus(tenken ValueLine, kijon ValueLine, senKoA_Shifted26 ValueLine, senKoB_Shifted52 ValueLine, chiko_span, bar *market.Kline) *IchimokuStatus { + + o := IchimokuStatus{} + + o.TenkenSen = tenken + + o.KijonSen = kijon + + o.SenKoA_Shifted26 = senKoA_Shifted26 + o.SenKoB_Shifted26 = senKoB_Shifted52 + + o.ChikoSpan = chiko_span + o.bar = bar + o.Status = IchimokuStatus_NAN + o.line_helper = NewLineHelper() + + return &o +} + +func (o *IchimokuStatus) SetChikoSpan(v *market.Kline) { + o.ChikoSpan = v +} + +func (o *IchimokuStatus) Set_SenCo_A_Past(p Point) { + o.SencoA_Past = p +} + +func (o *IchimokuStatus) Set_SenCo_B_Past(p Point) { + o.SencoB_Past = p +} + +func (o *IchimokuStatus) SetStatus(status EIchimokuStatus) { + o.Status = status +} + +func (o *IchimokuStatus) GetStatus() EIchimokuStatus { + return o.Status +} + +func (o *IchimokuStatus) SetCloudSwitching(v bool) { + o.cloudSwitching = v +} + +func (o *IchimokuStatus) GetCloudSwitching() bool { + return o.cloudSwitching +} + +func (o *IchimokuStatus) Is_cloud_green() bool { + return o.SenKoA_Shifted26.valLine > o.SenKoB_Shifted26.valLine +} + +func (o *IchimokuStatus) IsChikoAbovePrice() bool { + return o.ChikoSpan.High > o.bar.Close +} + +func (o *IchimokuStatus) CloudStatus(intersection decimal.Decimal) EIchimokuStatus { + if o.SenKoA_Shifted26.isNil || o.SenKoB_Shifted26.isNil { + return IchimokuStatus_NAN + } + if o.SencoA_Past.isNil || o.SencoB_Past.isNil { + return IchimokuStatus_NAN + } + + sen_B := o.SencoB_Past //Senko B in_26_candle_pass + sen_A := o.SencoA_Past //Senko A in_26_candle_pass + if sen_A.Y > intersection && sen_B.Y > intersection { + return IchimokuStatus_Cross_Below + } else if sen_A.Y < intersection && sen_B.Y < intersection { + return IchimokuStatus_Cross_Above + } else if sen_A.Y < intersection && sen_B.Y > intersection || sen_A.Y > intersection && sen_B.Y < intersection { + return IchimokuStatus_Cross_Inside + } + + return IchimokuStatus_NAN + +} + +func (o *IchimokuStatus) GetStatusString() string { + result := "" + switch o.Status { + case IchimokuStatus_NAN: + result = "nan" + + case IchimokuStatus_Cross_Below: + result = "cross below" + case IchimokuStatus_Cross_Above: + result = "cross above" + case IchimokuStatus_Cross_Inside: + result = "cross inside" + } + + return result +} + +func (o *IchimokuStatus) Print() string { + return fmt.Sprintf("ichimoku cloud %v|%v|%v|%v|%v| Green: %v, Chiko UP: %v | status: %v | %v\n", + o.TenkenSen.Value(), + o.KijonSen.Value(), + o.SenKoA_Shifted26.Value(), + o.SenKoB_Shifted26.Value(), + o.ChikoSpan.Close), + o.Is_cloud_green(), + o.IsChikoAbovePrice(), + o.GetStatusString(), + o.bar.StartTime.Time().Format(time.DateTime), + ) + +} diff --git a/pkg/indicator/v2/ichimoku1/tests/analyse_test.go b/pkg/indicator/v2/ichimoku1/tests/analyse_test.go new file mode 100644 index 0000000000..c240dd8163 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/tests/analyse_test.go @@ -0,0 +1,115 @@ +package tests + +import ( + "testing" + "time" + + "github.com/algo-boyz/alphakit/market" + "github.com/stretchr/testify/assert" + + "github.com/algo-boyz/alphakit/ta/ichimoku" +) + +var ( + interval = time.Minute * 30 + //52 bar + ts = []*market.Kline{ + {L: d(8110), H: d(8180), C: d(8160), O: d(8110), Volume: d(664372.00), Start: p(1667201400000)}, + {L: d(8100), H: d(8260), C: d(8200), O: d(8150), Volume: d(1241301.00), Start: p(1667205000000)}, + {L: d(8110), H: d(8450), C: d(8440), O: d(8170), Volume: d(2909458.00), Start: p(1667280600000)}, + {L: d(8310), H: d(8450), C: d(8360), O: d(8440), Volume: d(778238.00), Start: p(1667284200000)}, + {L: d(8240), H: d(8370), C: d(8260), O: d(8360), Volume: d(658420.00), Start: p(1667287800000)}, + {L: d(8240), H: d(8450), C: d(8440), O: d(8260), Volume: d(1814124.00), Start: p(1667291400000)}, + {L: d(8270), H: d(8440), C: d(8300), O: d(8440), Volume: d(1267103.00), Start: p(1667367000000)}, + {L: d(8270), H: d(8510), C: d(8510), O: d(8300), Volume: d(1821017.00), Start: p(1667370600000)}, + {L: d(8430), H: d(8540), C: d(8440), O: d(8510), Volume: d(559250.00), Start: p(1667374200000)}, + {L: d(8420), H: d(8470), C: d(8440), O: d(8440), Volume: d(544851.00), Start: p(1667377800000)}, + {L: d(8480), H: d(8730), C: d(8730), O: d(8550), Volume: d(4284720.00), Start: p(1667626200000)}, + {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(1382828.00), Start: p(1667629800000)}, + {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(1678201.00), Start: p(1667633400000)}, + {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(549277.00), Start: p(1667637000000)}, + {L: d(8800), H: d(9070), C: d(9060), O: d(8800), Volume: d(5342062.00), Start: p(1667712600000)}, + {L: d(9040), H: d(9070), C: d(9070), O: d(9060), Volume: d(8126959.00), Start: p(1667716200000)}, + {L: d(9070), H: d(9070), C: d(9070), O: d(9070), Volume: d(527101.00), Start: p(1667719800000)}, + {L: d(9070), H: d(9070), C: d(9070), O: d(9070), Volume: d(702521.00), Start: p(1667723400000)}, + {L: d(9160), H: d(9440), C: d(9430), O: d(9290), Volume: d(4409696.00), Start: p(1667799000000)}, + {L: d(9410), H: d(9490), C: d(9490), O: d(9420), Volume: d(7522839.00), Start: p(1667802600000)}, + {L: d(9490), H: d(9490), C: d(9490), O: d(9490), Volume: d(777299.00), Start: p(1667806200000)}, + {L: d(9490), H: d(9490), C: d(9490), O: d(9490), Volume: d(405416.00), Start: p(1667809800000)}, + {L: d(9300), H: d(9890), C: d(9530), O: d(9890), Volume: d(7097789.00), Start: p(1667885400000)}, + {L: d(9460), H: d(9570), C: d(9470), O: d(9520), Volume: d(3033312.00), Start: p(1667889000000)}, + {L: d(9380), H: d(9490), C: d(9410), O: d(9470), Volume: d(2714433.00), Start: p(1667892600000)}, + {L: d(9390), H: d(9490), C: d(9450), O: d(9420), Volume: d(3876877.00), Start: p(1667896200000)}, + {L: d(9250), H: d(9540), C: d(9410), O: d(9350), Volume: d(3448605.00), Start: p(1667971800000)}, + {L: d(9400), H: d(9840), C: d(9800), O: d(9410), Volume: d(6547559.00), Start: p(1667975400000)}, + {L: d(9640), H: d(9830), C: d(9650), O: d(9800), Volume: d(2416825.00), Start: p(1667979000000)}, + {L: d(9650), H: d(9860), C: d(9680), O: d(9700), Volume: d(2463503.00), Start: p(1667982600000)}, + {L: d(9640), H: d(9870), C: d(9800), O: d(9750), Volume: d(2000789.00), Start: p(1668231000000)}, + {L: d(9520), H: d(9800), C: d(9520), O: d(9780), Volume: d(3214849.00), Start: p(1668234600000)}, + {L: d(9520), H: d(9680), C: d(9620), O: d(9550), Volume: d(3019512.00), Start: p(1668238200000)}, + {L: d(9610), H: d(9810), C: d(9740), O: d(9640), Volume: d(2473212.00), Start: p(1668241800000)}, + {L: d(9450), H: d(9710), C: d(9530), O: d(9710), Volume: d(1455003.00), Start: p(1668317400000)}, + {L: d(9510), H: d(9700), C: d(9700), O: d(9520), Volume: d(1341450.00), Start: p(1668321000000)}, + {L: d(9520), H: d(9720), C: d(9650), O: d(9700), Volume: d(2922575.00), Start: p(1668324600000)}, + {L: d(9470), H: d(9650), C: d(9470), O: d(9650), Volume: d(907574.00), Start: p(1668328200000)}, + {L: d(9250), H: d(9620), C: d(9250), O: d(9510), Volume: d(1573592.00), Start: p(1668403800000)}, + {L: d(9220), H: d(9420), C: d(9380), O: d(9270), Volume: d(1372258.00), Start: p(1668407400000)}, + {L: d(9340), H: d(9530), C: d(9490), O: d(9380), Volume: d(3147032.00), Start: p(1668411000000)}, + {L: d(9370), H: d(9550), C: d(9370), O: d(9490), Volume: d(2153637.00), Start: p(1668414600000)}, + {L: d(9380), H: d(9750), C: d(9670), O: d(9450), Volume: d(1861478.00), Start: p(1668490200000)}, + {L: d(9580), H: d(9700), C: d(9650), O: d(9670), Volume: d(2890813.00), Start: p(1668493800000)}, + {L: d(9610), H: d(9700), C: d(9670), O: d(9610), Volume: d(1288957.00), Start: p(1668497400000)}, + {L: d(9630), H: d(9800), C: d(9730), O: d(9650), Volume: d(2413843.00), Start: p(1668501000000)}, + {L: d(9580), H: d(9780), C: d(9630), O: d(9750), Volume: d(803830.00), Start: p(1668576600000)}, + {L: d(9630), H: d(9720), C: d(9670), O: d(9650), Volume: d(699785.00), Start: p(1668580200000)}, + {L: d(9640), H: d(9700), C: d(9640), O: d(9700), Volume: d(393592.00), Start: p(1668583800000)}, + {L: d(9580), H: d(9660), C: d(9630), O: d(9640), Volume: d(1443871.00), Start: p(1668587400000)}, + {L: d(9300), H: d(9600), C: d(9370), O: d(9510), Volume: d(3845936.00), Start: p(1668835800000)}, + {L: d(9310), H: d(9380), C: d(9330), O: d(9380), Volume: d(1380628.00), Start: p(1668839400000)}, + } +) + +func Test_26DayinThePastNotExist(t *testing.T) { + + indicator := ichimoku.NewIndicator() + + indicator.MakeIchimokuInPast(ts, 1) + + _, e1 := indicator.AnalyseTriggerCross(indicator.GetLast(), ts) + + assert.Equal(t, e1, ichimoku.ErrChikoStatus26InPastNotMade) + +} +func TestInside(t *testing.T) { + + indicator := ichimoku.NewIndicator() + + today := ichimoku.NewIchimokuStatus( + ichimoku.NewValue(d(8705)), + ichimoku.NewValue(d(8710)), + ichimoku.NewValue(d(8707)), + ichimoku.NewValue(d(8930)), + &market.Kline{}, + &market.Kline{L: d(8400), H: d(8460), C: d(8440), O: d(8440), Volume: d(906352), Start: p(1664699400000)}) + + yesterday := ichimoku.NewIchimokuStatus( + ichimoku.NewValue(d(8720)), + ichimoku.NewValue(d(8710)), + ichimoku.NewValue(d(8715)), + ichimoku.NewValue(d(8940)), + &market.Kline{}, + &market.Kline{L: d(8430), H: d(8480), C: d(8450), O: d(8460), Volume: d(652416), Start: p(1664695800000)}) + + lines_result := make([]*ichimoku.IchimokuStatus, 2) + lines_result[0] = today //today + lines_result[1] = yesterday + + a, e := indicator.PreAnalyseIchimoku(lines_result) + assert.Empty(t, e) + assert.Equal(t, a.Status, ichimoku.IchimokuStatus_Cross_Above) + +} + +func p(v int64) time.Time { + return time.UnixMilli(v).UTC() +} diff --git a/pkg/indicator/v2/ichimoku1/tests/cloud_test.go b/pkg/indicator/v2/ichimoku1/tests/cloud_test.go new file mode 100644 index 0000000000..eea4ed7de5 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/tests/cloud_test.go @@ -0,0 +1,157 @@ +package tests + +import ( + "testing" + + decimal "github.com/algo-boyz/decimal128" + "github.com/stretchr/testify/assert" + + "github.com/algo-boyz/alphakit/ta/dec" + "github.com/algo-boyz/alphakit/ta/ichimoku" +) + +func i(v int64) decimal.Decimal { + return dec.New(v) +} + +func d(v float64) decimal.Decimal { + return dec.New(v) +} + +func TestCheckCloud_Above(t *testing.T) { + + h1_above_ := []ichimoku.Point{ + {X: i(1667802600), Y: d(8762.00)}, + {X: i(1667806200), Y: d(8882.00)}, + {X: i(1667809800), Y: d(8908.00)}, + {X: i(1667885400), Y: d(8928.00)}, + {X: i(1667889000), Y: d(9152.00)}, + {X: i(1667892600), Y: d(9222.00)}, + {X: i(1667896200), Y: d(9238.00)}, + {X: i(1667971800), Y: d(9238.00)}, + {X: i(1667975400), Y: d(9260.00)}, + {X: i(1667979000), Y: d(9285.00)}, + {X: i(1667982600), Y: d(9318.00)}, + {X: i(1668231000), Y: d(9318.00)}, + {X: i(1668234600), Y: d(9318.00)}, + {X: i(1668238200), Y: d(9320.00)}, + {X: i(1668241800), Y: d(9320.00)}, + {X: i(1668317400), Y: d(9358.00)}, + {X: i(1668321000), Y: d(9358.00)}, + {X: i(1668324600), Y: d(9410.00)}, + {X: i(1668328200), Y: d(9485.00)}, + {X: i(1668403800), Y: d(9485.00)}, + {X: i(1668407400), Y: d(9435.00)}, + {X: i(1668411000), Y: d(9430.00)}, + {X: i(1668414600), Y: d(9490.00)}, + {X: i(1668490200), Y: d(9498.00)}, + {X: i(1668493800), Y: d(9482.00)}, + } + line_helper := ichimoku.NewLineHelper() + point_from_price := ichimoku.NewPoint(dec.New(1668497400/1000), d(9670)) + res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) + + //fmt.Println("senko A", res_senko_a, "err:", err) + assert.Equal(t, res_senko_a, ichimoku.EPointLocation_above) + assert.Empty(t, err) + +} +func TestCheckCloud_below(t *testing.T) { + + h1_above_ := []ichimoku.Point{ + {X: i(1666589400), Y: d(8660.00)}, + {X: i(1666593000), Y: d(8660.00)}, + {X: i(1666596600), Y: d(8618.00)}, + {X: i(1666600200), Y: d(8555.00)}, + {X: i(1666675800), Y: d(8548.00)}, + {X: i(1666679400), Y: d(8502.00)}, + {X: i(1666683000), Y: d(8435.00)}, + {X: i(1666686600), Y: d(8435.00)}, + {X: i(1666762200), Y: d(8430.00)}, + {X: i(1666765800), Y: d(8360.00)}, + {X: i(1666769400), Y: d(8300.00)}, + {X: i(1666773000), Y: d(8282.00)}, + {X: i(1667021400), Y: d(8282.00)}, + {X: i(1667025000), Y: d(8282.00)}, + {X: i(1667028600), Y: d(8240.00)}, + {X: i(1667032200), Y: d(8160.00)}, + {X: i(1667107800), Y: d(8120.00)}, + {X: i(1667111400), Y: d(8120.00)}, + {X: i(1667115000), Y: d(8112.00)}, + {X: i(1667118600), Y: d(8110.00)}, + {X: i(1667194200), Y: d(8098.00)}, + {X: i(1667197800), Y: d(8100.00)}, + {X: i(1667201400), Y: d(8060.00)}, + {X: i(1667205000), Y: d(8052.00)}, + {X: i(1667280600), Y: d(8055.00)}, + } + line_helper := ichimoku.NewLineHelper() + point_from_price := ichimoku.NewPoint(dec.New(1667284200/1000), d(8360)) + res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) + + assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) + assert.Empty(t, err) + +} +func TestCheckCloud_below1(t *testing.T) { + // h1 shegoya Tue Oct 2022 18 10:00:00 + + h1_above_ := []ichimoku.Point{ + {X: i(1665819000), Y: d(8745.00)}, + {X: i(1665822600), Y: d(8750.00)}, + {X: i(1665898200), Y: d(8750.00)}, + {X: i(1665901800), Y: d(8730.00)}, + {X: i(1665905400), Y: d(8725.00)}, + {X: i(1665909000), Y: d(8712.00)}, + {X: i(1665984600), Y: d(8692.00)}, + {X: i(1665988200), Y: d(8692.00)}, + {X: i(1665991800), Y: d(8680.00)}, + {X: i(1665995400), Y: d(8680.00)}, + {X: i(1666071000), Y: d(8680.00)}, + } + line_helper := ichimoku.NewLineHelper() + point_from_price := ichimoku.NewPoint(dec.New(1666074600/1000), d(8650)) + res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) + + assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) + assert.Empty(t, err) + +} +func TestCheckCloud_below3(t *testing.T) { + //|2022 Tue Nov 1 10:00:00 + h1_above_ := []ichimoku.Point{ + {X: i(1666589400), Y: d(8660.00)}, + {X: i(1666593000), Y: d(8660.00)}, + {X: i(1666596600), Y: d(8618.00)}, + {X: i(1666600200), Y: d(8555.00)}, + {X: i(1666675800), Y: d(8548.00)}, + {X: i(1666679400), Y: d(8502.00)}, + {X: i(1666683000), Y: d(8435.00)}, + {X: i(1666686600), Y: d(8435.00)}, + {X: i(1666762200), Y: d(8430.00)}, + {X: i(1666765800), Y: d(8360.00)}, + {X: i(1666769400), Y: d(8300.00)}, + {X: i(1666773000), Y: d(8282.00)}, + {X: i(1667021400), Y: d(8282.00)}, + {X: i(1667025000), Y: d(8282.00)}, + {X: i(1667028600), Y: d(8240.00)}, + {X: i(1667032200), Y: d(8160.00)}, + {X: i(1667107800), Y: d(8120.00)}, + {X: i(1667111400), Y: d(8120.00)}, + {X: i(1667115000), Y: d(8112.00)}, + {X: i(1667118600), Y: d(8110.00)}, + {X: i(1667194200), Y: d(8098.00)}, + {X: i(1667197800), Y: d(8100.00)}, + {X: i(1667201400), Y: d(8060.00)}, + {X: i(1667205000), Y: d(8052.00)}, + {X: i(1667280600), Y: d(8055.00)}, + } + line_helper := ichimoku.NewLineHelper() + point_from_price := ichimoku.NewPoint(dec.New(1667284200/1000), dec.New(8360)) + res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) + + //fmt.Println("senko A", res_senko_a, "err:", err) + assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) + assert.Empty(t, err) + +} diff --git a/pkg/indicator/v2/ichimoku1/types.go b/pkg/indicator/v2/ichimoku1/types.go new file mode 100644 index 0000000000..97e7171e08 --- /dev/null +++ b/pkg/indicator/v2/ichimoku1/types.go @@ -0,0 +1,70 @@ +package ichimoku + +import ( + "errors" + + decimal "github.com/algo-boyz/decimal128" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +var ( + ErrBuildFailed = errors.New("build failed") + ErrNotEnoughData = errors.New("not enough data") + ErrDataNotFill = errors.New("data not fill") + ErrChikoStatus26InPastNotMade = errors.New("chiko status 26 in past not reached") + ErrDateNotGreaterThanPrevious = errors.New("date is not greater than previous") +) + +type Point struct { + X, Y fixedpoint.Value + isNil bool +} + +func NewPoint(x, y fixedpoint.Value) Point { + p := Point{} + p.X = x + p.Y = y + p.isNil = false + return p +} +func NewNilPoint() Point { + p := Point{} + p.X = fixedpoint.NewFromInt(-1) + p.Y = fixedpoint.NewFromInt(-1) + p.isNil = true + return p +} + +type Equation struct { + Slope decimal.Decimal + Intercept decimal.Decimal +} + +type EInterSectionStatus int + +const ( + EInterSectionStatus_NAN EInterSectionStatus = 0 + EInterSectionStatus_Find EInterSectionStatus = 1 + EInterSectionStatus_Parallel EInterSectionStatus = 2 + EInterSectionStatus_Collision_Find EInterSectionStatus = 1 +) + +type ELine int + +const ( + Line_Tenkan_sen ELine = 9 + Line_kijon_sen ELine = 26 + Line_spanPeriod ELine = 52 + Line_chikoPeriod ELine = 26 //-26 +) + +type EIchimokuStatus int + +const ( + IchimokuStatus_NAN EIchimokuStatus = 0 + IchimokuStatus_Cross_Inside EIchimokuStatus = 1 + IchimokuStatus_Cross_Below EIchimokuStatus = 2 + IchimokuStatus_Cross_Above EIchimokuStatus = 3 + IchimokuStatus_overLab EIchimokuStatus = 4 +) diff --git a/pkg/indicator/v2/lookback.go b/pkg/indicator/v2/lookback.go new file mode 100644 index 0000000000..c599fa9f6f --- /dev/null +++ b/pkg/indicator/v2/lookback.go @@ -0,0 +1,40 @@ +// Copyright 2022 The Coln Group Ltd +// SPDX-License-Identifier: MIT + +package indicatorv2 + +// Lookback returns a value from series at n index ago. +// Series must be in chronological order, with the earliest value at slice index 0. +// n = 0 returns the latest value. n = 1 returns the value before the latest etc. +func Lookback[T any](series []T, n int) T { + var empty T + i := (len(series) - n) - 1 + if i < 0 { + return empty + } + return series[i] +} + +// Window returns a copied slice of series starting at n index ago. +// Semantics of n argument are the same as Lookback function. +func Window[T any](series []T, n int) []T { + + ln := len(series) + if ln <= n { + window := make([]T, ln) + copy(window, series) + return window + } + + i := (ln - n) - 1 + window := make([]T, n+1) + copy(window, series[i:]) + + return window +} + +// WindowAppend appends a value to the end of the series and slices it to the window starting at n index ago. +// Semantics of n argument are the same as Window and Lookback functions. +func WindowAppend[T any](series []T, n int, v T) []T { + return Window(append(series, v), n) +} diff --git a/pkg/indicator/v2/lookback_test.go b/pkg/indicator/v2/lookback_test.go new file mode 100644 index 0000000000..d03380b115 --- /dev/null +++ b/pkg/indicator/v2/lookback_test.go @@ -0,0 +1,128 @@ +// Copyright 2022 The Coln Group Ltd +// SPDX-License-Identifier: MIT + +package indicatorv2 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLookback(t *testing.T) { + tests := []struct { + name string + giveSeries []float64 + giveN int + want float64 + }{ + { + name: "Last value", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 0, + want: 5, + }, + { + name: "First value", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 6, + want: 0, + }, + { + name: "Value", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 2, + want: 3, + }, + { + name: "Index out of range return 0", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 7, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + act := Lookback(tt.giveSeries, tt.giveN) + assert.Equal(t, tt.want, act) + }) + } +} + +func TestWindow(t *testing.T) { + tests := []struct { + name string + giveSeries []float64 + giveN int + want []float64 + }{ + { + name: "Latest value only", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 0, + want: []float64{5}, + }, + { + name: "All values", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 6, + want: []float64{0, 1, 2, 3, 4, 5}, + }, + { + name: "Index out of range - returns all values", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 7, + want: []float64{0, 1, 2, 3, 4, 5}, + }, + { + name: "Sub window", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 3, + want: []float64{2, 3, 4, 5}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + act := Window(tt.giveSeries, tt.giveN) + assert.Equal(t, tt.want, act) + }) + } +} + +func TestWindowAppend(t *testing.T) { + tests := []struct { + name string + giveSeries []float64 + giveN int + giveV float64 + want []float64 + }{ + { + name: "Append and no slice", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 7, + giveV: 99, + want: []float64{0, 1, 2, 3, 4, 5, 99}, + }, + { + name: "Append and slice", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 2, + giveV: 99, + want: []float64{4, 5, 99}, + }, + { + name: "Append and slice to new value only", + giveSeries: []float64{0, 1, 2, 3, 4, 5}, + giveN: 0, + giveV: 99, + want: []float64{99}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + act := WindowAppend(tt.giveSeries, tt.giveN, tt.giveV) + assert.Equal(t, tt.want, act) + }) + } +} diff --git a/pkg/indicator/v2/rsi.go b/pkg/indicator/v2/momentum/rsi.go similarity index 92% rename from pkg/indicator/v2/rsi.go rename to pkg/indicator/v2/momentum/rsi.go index d4ca1489d8..fc96c8138c 100644 --- a/pkg/indicator/v2/rsi.go +++ b/pkg/indicator/v2/momentum/rsi.go @@ -1,4 +1,4 @@ -package indicatorv2 +package momentum import ( "github.com/c9s/bbgo/pkg/types" @@ -47,13 +47,6 @@ func (s *RSIStream) Calculate(_ float64) float64 { return rsi } -func max(x, y int) int { - if x > y { - return x - } - return y -} - func min(x, y int) int { if x < y { return x diff --git a/pkg/indicator/v2/rsi_test.go b/pkg/indicator/v2/momentum/rsi_test.go similarity index 95% rename from pkg/indicator/v2/rsi_test.go rename to pkg/indicator/v2/momentum/rsi_test.go index 779132d34c..3789acc97a 100644 --- a/pkg/indicator/v2/rsi_test.go +++ b/pkg/indicator/v2/momentum/rsi_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package momentum import ( "encoding/json" @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" ) func Test_RSI2(t *testing.T) { @@ -67,7 +68,7 @@ func Test_RSI2(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // RSI2() - prices := ClosePrices(nil) + prices := v2.ClosePrices(nil) rsi := RSI2(prices, tt.window) t.Logf("data length: %d", len(tt.values)) diff --git a/pkg/indicator/v2/pattern/README.md b/pkg/indicator/v2/pattern/README.md new file mode 100644 index 0000000000..26885f3df5 --- /dev/null +++ b/pkg/indicator/v2/pattern/README.md @@ -0,0 +1,24 @@ +[explanations](https://analyzingalpha.com/candlestick-patterns#The_Best_Crypto_Candlestick_Patterns) + +## Use + +Pass a dataframe containing OHLC data and get a bullish or bearish pattern identified: + +- 1: BULL +- -1: BEAR +- 0: NULL + +## Todo + +Check repos for more indicators +https://github.com/markcheno/go-talib/ +https://github.com/gobacktest/gobacktest/blob/main/strategy/ma-cross.go +https://github.com/iamjinlei/go-tart +https://pkg.go.dev/github.com/uvite/u8/tart + + +montecarlo black and scholes +https://ggcarvalho.dev/posts/montecarlo/ +https://medium.com/@matt.a.french/predicting-stock-prices-using-monte-carlo-simulations-in-go-26060ab2836 + +https://github.com/c9s/bbgo/blob/main/pkg/strategy/skeleton/strategy.go \ No newline at end of file diff --git a/pkg/indicator/v2/pattern/abondoned_baby.go b/pkg/indicator/v2/pattern/abondoned_baby.go new file mode 100644 index 0000000000..1a773ee4b2 --- /dev/null +++ b/pkg/indicator/v2/pattern/abondoned_baby.go @@ -0,0 +1,61 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type AbondonedBabyStream struct { + *types.Float64Series + + window int +} + +func AbondonedBaby(source v2.KLineSubscription) *AbondonedBabyStream { + s := &AbondonedBabyStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + one = source.Last(2) + two = source.Last(1) + three = source.Last(0) + ) + + if one.Open < one.Close { + if one.High < two.Low { + if fixedpoint.Abs((two.Close-two.Open)/(two.Open)) < threshold { + if three.Open < two.Low && three.Close < three.Open { + output = -1.0 + } + } + } + } + + if one.Open > one.Close { + if one.Low > two.High { + if fixedpoint.Abs((two.Close-two.Open)/two.Open) <= threshold { + if three.Open > two.High && three.Close > three.Open { + output = 1.0 + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/abondoned_baby_test.go b/pkg/indicator/v2/pattern/abondoned_baby_test.go new file mode 100644 index 0000000000..973c72fa34 --- /dev/null +++ b/pkg/indicator/v2/pattern/abondoned_baby_test.go @@ -0,0 +1,29 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestAbandonedBaby(t *testing.T) { + ts := []types.KLine{ + {Open: 90, Low: 85, High: 105, Close: 100}, + {Open: 125, Low: 120, High: 135, Close: 130}, + {Open: 110, Low: 92, High: 115, Close: 95}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := AbondonedBaby(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestAbandonedBaby Bear unexpected result: got %v want %v", ind, expectedBear) + } +} diff --git a/pkg/indicator/v2/pattern/belthold.go b/pkg/indicator/v2/pattern/belthold.go new file mode 100644 index 0000000000..7b57b856b8 --- /dev/null +++ b/pkg/indicator/v2/pattern/belthold.go @@ -0,0 +1,59 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type BeltholdStream struct { + *types.Float64Series + + window int +} + +func Belthold(source v2.KLineSubscription) *BeltholdStream { + s := &BeltholdStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + ) + + if two.Close > two.Open { + if two.High < one.Open { + if one.Open == one.High { + if one.Close < one.Open { + output = Bear + } + } + } + } + + if two.Close < two.Open { + if two.Low > one.Open { + if one.Open == one.Low { + if one.Close > one.Open { + output = Bull + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/belthold_test.go b/pkg/indicator/v2/pattern/belthold_test.go new file mode 100644 index 0000000000..c742825d13 --- /dev/null +++ b/pkg/indicator/v2/pattern/belthold_test.go @@ -0,0 +1,45 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestBelthold(t *testing.T) { + + ts := []types.KLine{ + {Open: 60, Low: 55, High: 75, Close: 70}, + {Open: 100, Low: 75, High: 100, Close: 80}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Belthold(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestBelthold Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 120, Low: 100, High: 125, Close: 105}, + {Open: 70, Low: 70, High: 95, Close: 90}, + } + + ind = Belthold(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestBelthold Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/breakaway.go b/pkg/indicator/v2/pattern/breakaway.go new file mode 100644 index 0000000000..4e63755e6f --- /dev/null +++ b/pkg/indicator/v2/pattern/breakaway.go @@ -0,0 +1,62 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type BreakAwayStream struct { + *types.Float64Series + + window int +} + +func BreakAway(source v2.KLineSubscription) *BreakAwayStream { + s := &BreakAwayStream{ + Float64Series: types.NewFloat64Series(), + window: 5, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + five = source.Last(4) + four = source.Last(3) + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + + if five.Open < five.Close { + if four.Open < four.Close && five.Close < four.Open { + if four.Close < three.Close && three.Close < two.Close { + if one.Open > one.Close && one.Close > five.Close { + output = Bear + } + } + } + } + + if five.Open > five.Close { + if four.Open > four.Close && five.Close > four.Open { + if four.Close > three.Close && three.Close > two.Close { + if one.Open < one.Close && one.Close < five.Close { + output = Bull + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/breakaway_test.go b/pkg/indicator/v2/pattern/breakaway_test.go new file mode 100644 index 0000000000..085fe76284 --- /dev/null +++ b/pkg/indicator/v2/pattern/breakaway_test.go @@ -0,0 +1,49 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestBreakAway(t *testing.T) { + ts := []types.KLine{ + {Open: 70, Low: 60, High: 85, Close: 80}, + {Open: 115, Low: 110, High: 125, Close: 120}, + {Open: 120, Low: 115, High: 130, Close: 125}, + {Open: 125, Low: 120, High: 135, Close: 130}, + {Open: 125, Low: 95, High: 130, Close: 100}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := BreakAway(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestBreakAway Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 130, Low: 115, High: 135, Close: 120}, + {Open: 100, Low: 85, High: 105, Close: 90}, + {Open: 95, Low: 80, High: 100, Close: 85}, + {Open: 90, Low: 75, High: 95, Close: 80}, + {Open: 85, Low: 80, High: 115, Close: 110}, + } + ind = BreakAway(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestBreakAway Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/dark_cloud.go b/pkg/indicator/v2/pattern/dark_cloud.go new file mode 100644 index 0000000000..0214fcda0c --- /dev/null +++ b/pkg/indicator/v2/pattern/dark_cloud.go @@ -0,0 +1,48 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DarkCloudStream struct { + *types.Float64Series + + window int +} + +func DarkCloud(source v2.KLineSubscription) *DarkCloudStream { + s := &DarkCloudStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + twoMidpoint = (two.Close + two.Open) / 2 + isFirstBullish = two.Close > two.Open + isSecondBearish = one.Close < one.Open + isDarkCloud = one.Open > two.High && + one.Close < twoMidpoint && one.Close > two.Open + ) + + if isFirstBullish && isSecondBearish && isDarkCloud { + output = Bear + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/dark_cloud_test.go b/pkg/indicator/v2/pattern/dark_cloud_test.go new file mode 100644 index 0000000000..87b7355ff8 --- /dev/null +++ b/pkg/indicator/v2/pattern/dark_cloud_test.go @@ -0,0 +1,28 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDarkCloud(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(28.30), High: n(37.40), Close: n(35.36)}, + {Open: n(39.45), Low: n(31.25), High: n(41.45), Close: n(32.50)}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := DarkCloud(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDarkCloud Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } +} diff --git a/pkg/indicator/v2/pattern/doji.go b/pkg/indicator/v2/pattern/doji.go new file mode 100644 index 0000000000..ff4edbbd7b --- /dev/null +++ b/pkg/indicator/v2/pattern/doji.go @@ -0,0 +1,34 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DojiStream struct { + *types.Float64Series +} + +// maxDiff is the maximum deviation between a and b to consider them approximately equal +func Doji(source v2.KLineSubscription, maxDiff float64) *DojiStream { + s := &DojiStream{ + Float64Series: types.NewFloat64Series(), + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + output = Neutral + one = source.Last(0) + openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) + highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) + lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, maxDiff) + ) + if openEqualClose && lowEqualsClose == highEqualsOpen { + output = Bull + } + s.PushAndEmit(output) + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly.go b/pkg/indicator/v2/pattern/doji_dragon_fly.go new file mode 100644 index 0000000000..96e1f835dc --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_dragon_fly.go @@ -0,0 +1,45 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DojiDragonFlyStream struct { + *types.Float64Series + + window int +} + +func DojiDragonFly(source v2.KLineSubscription) *DojiDragonFlyStream { + s := &DojiDragonFlyStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + one = source.Last(0) + openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, 0.001) + highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, 0.001) + lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, 0.001) + ) + + if openEqualClose && highEqualsOpen && !lowEqualsClose { + output = Bull + } + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly_test.go b/pkg/indicator/v2/pattern/doji_dragon_fly_test.go new file mode 100644 index 0000000000..20e580534f --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_dragon_fly_test.go @@ -0,0 +1,39 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDojiDragonFly(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(30.10), High: n(30.13), Close: n(28.10)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := DojiDragonFly(kLines) + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDojiDragonFly Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + ts = []types.KLine{ + {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, + } + + ind = DojiDragonFly(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiDragonFly Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/doji_gravestone.go b/pkg/indicator/v2/pattern/doji_gravestone.go new file mode 100644 index 0000000000..afe4e62de4 --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_gravestone.go @@ -0,0 +1,45 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DojiGraveStoneStream struct { + *types.Float64Series + + window int +} + +func DojiGraveStone(source v2.KLineSubscription) *DojiGraveStoneStream { + s := &DojiGraveStoneStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + one = source.Last(0) + openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, 0.001) + highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, 0.001) + lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, 0.001) + ) + + if openEqualClose && lowEqualsClose && !highEqualsOpen { + output = Bear + } + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/doji_gravestone_test.go b/pkg/indicator/v2/pattern/doji_gravestone_test.go new file mode 100644 index 0000000000..6de2c730ca --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_gravestone_test.go @@ -0,0 +1,40 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDojiGraveStone(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(36.13), High: n(30.13), Close: n(30.12)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := DojiGraveStone(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDojiGraveStone Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, + } + ind = DojiGraveStone(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiGraveStone Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/doji_long_legged.go b/pkg/indicator/v2/pattern/doji_long_legged.go new file mode 100644 index 0000000000..3191e5e9f4 --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_long_legged.go @@ -0,0 +1,71 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DojiLongLeggedStream struct { + *types.Float64Series + + window int +} + +func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { + s := &DojiLongLeggedStream{ + Float64Series: types.NewFloat64Series(), + window: 4, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + four = source.Last(3) + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + // BEAR + if four.Close > four.Open { + if three.Close > three.Open { + if two.Close > two.Open { + if fixedpoint.Abs((one.Close-one.Open)/one.Open) < threshold { + if fixedpoint.Abs((one.High-one.Open)/one.Open) > limit { + if fixedpoint.Abs((one.Close-one.Low)/one.Low) > limit { + output = Bear + } + } + } + } + } + } + + // BULL + if four.Close < four.Open { + if three.Close < three.Open { + if two.Close < two.Open { + if fixedpoint.Abs((one.Open-one.Close)/one.Close) < threshold { + if fixedpoint.Abs((one.Low-one.Close)/one.Close) > limit { + if fixedpoint.Abs((one.Open-one.High)/one.High) > limit { + output = Bull + } + } + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/doji_long_legged_test.go b/pkg/indicator/v2/pattern/doji_long_legged_test.go new file mode 100644 index 0000000000..3ea84122a3 --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_long_legged_test.go @@ -0,0 +1,47 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDojiLongLegged(t *testing.T) { + ts := []types.KLine{ + {Open: 85, Low: 80, High: 95, Close: 90}, + {Open: 95, Low: 90, High: 105, Close: 100}, + {Open: 105, Low: 100, High: 115, Close: 110}, + {Open: 170, Low: 120, High: 210, Close: 160}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := DojiLongLegged(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDojiLL Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 90, Low: 80, High: 95, Close: 85}, + {Open: 100, Low: 90, High: 105, Close: 95}, + {Open: 110, Low: 100, High: 115, Close: 105}, + {Open: 160, Low: 120, High: 210, Close: 170}, + } + ind = DojiLongLegged(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiLL Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/doji_star.go b/pkg/indicator/v2/pattern/doji_star.go new file mode 100644 index 0000000000..b61103876d --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_star.go @@ -0,0 +1,69 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DojiStarStream struct { + *types.Float64Series + + window int +} + +// maxDiff is the maximum deviation between a and b to consider them approximately equal +func DojiStar(source v2.KLineSubscription, maxDiff float64) *DojiStarStream { + s := &DojiStarStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + var doji = Doji(source, maxDiff) + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + firstMidpoint = (three.Open + three.Close) / 2 + isFirstBearish = three.Close < three.Open + isThirdBullish = one.Close > one.Open + gapExists = two.High < three.Low && + two.Low < three.Low && + one.Open > two.High && + two.Close < one.Open + doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + ) + var dojiExists = doji.Last(0) == Bull + if isFirstBearish && dojiExists && isThirdBullish && gapExists && doesCloseAboveFirstMidpoint { + output = Bull + } else { + var ( + isFirstBullish = two.Close > two.Open + isThirdBearish = one.Open > one.Close + ) + gapExists = two.High > three.High && + two.Low > three.High && + one.Open < two.Low && + two.Close > one.Open + var doesCloseBelowFirstMidpoint = one.Close < firstMidpoint + if isFirstBullish && dojiExists && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { + output = Bear + } + + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/doji_star_test.go b/pkg/indicator/v2/pattern/doji_star_test.go new file mode 100644 index 0000000000..7e1650453f --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_star_test.go @@ -0,0 +1,44 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDojiStar(t *testing.T) { + ts := []types.KLine{ + {Open: n(18.35), Low: n(18.13), High: n(21.60), Close: n(21.30)}, + {Open: n(22.20), Low: n(21.87), High: n(22.40), Close: n(22.22)}, + {Open: n(21.60), Low: n(19.30), High: n(22.05), Close: n(19.45)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := DojiStar(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDojiEveningStar Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(22.20), Low: n(20.65), High: n(22.50), Close: n(20.80)}, + {Open: n(20.30), Low: n(20.10), High: n(20.45), Close: n(20.30)}, + {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(21.58)}, + } + ind = DojiStar(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiMorningStar Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/doji_test.go b/pkg/indicator/v2/pattern/doji_test.go new file mode 100644 index 0000000000..8f4d87265a --- /dev/null +++ b/pkg/indicator/v2/pattern/doji_test.go @@ -0,0 +1,40 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDoji(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(32.10), High: n(30.13), Close: n(28.10)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Doji(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestDojiGraveStone Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, + } + ind = Doji(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiGraveStone Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap.go b/pkg/indicator/v2/pattern/downside_tazuki_gap.go new file mode 100644 index 0000000000..ccefb90d8c --- /dev/null +++ b/pkg/indicator/v2/pattern/downside_tazuki_gap.go @@ -0,0 +1,52 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type TazukiGapStream struct { + *types.Float64Series + + window int +} + +func TazukiGap(source v2.KLineSubscription) *TazukiGapStream { + s := &TazukiGapStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + isFirstBearish = three.Close < three.Open + isSecondBearish = two.Close < two.Open + isThirdBullish = one.Close > one.Open + isFirstGapExists = two.High < three.Low + isTazukiGap = two.Open > one.Open && + two.Close < one.Open && + one.Close > two.Open && + one.Close < three.Close + ) + + if isFirstBearish && isSecondBearish && isThirdBullish && isFirstGapExists && isTazukiGap { + output = Bear + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go b/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go new file mode 100644 index 0000000000..d2fd4b64a7 --- /dev/null +++ b/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go @@ -0,0 +1,28 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestTazukiGap(t *testing.T) { + ts := []types.KLine{ + {Open: n(45.00), Low: n(38.56), High: n(46.20), Close: n(41.20)}, + {Open: n(33.45), Low: n(28), High: n(34.70), Close: n(29.31)}, + {Open: n(30.20), Low: n(29.80), High: n(36.63), Close: n(36.28)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Doji(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestTazukiGap Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } +} diff --git a/pkg/indicator/v2/pattern/engulfing.go b/pkg/indicator/v2/pattern/engulfing.go new file mode 100644 index 0000000000..0481ac8fcf --- /dev/null +++ b/pkg/indicator/v2/pattern/engulfing.go @@ -0,0 +1,57 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type EngulfingStream struct { + *types.Float64Series + + window int +} + +func Engulfing(source v2.KLineSubscription) *EngulfingStream { + s := &EngulfingStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + ) + + // BEAR + if two.Open < two.Close { + if one.Open > two.Close { + if one.Close < two.Open { + output = Bear + } + } + } + + // BULL + if two.Open > two.Close { + if one.Open < two.Close { + if one.Close > two.Open { + output = Bull + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/engulfing_test.go b/pkg/indicator/v2/pattern/engulfing_test.go new file mode 100644 index 0000000000..07929545bb --- /dev/null +++ b/pkg/indicator/v2/pattern/engulfing_test.go @@ -0,0 +1,42 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestEngulfing(t *testing.T) { + ts := []types.KLine{ + {Open: 80, Low: 75, High: 95, Close: 90}, + {Open: 100, Low: 65, High: 105, Close: 70}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Engulfing(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestEngulfing Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 90, Low: 75, High: 95, Close: 80}, + {Open: 70, Low: 65, High: 105, Close: 100}, + } + ind = Engulfing(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestEngulfing Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/hammerstick.go b/pkg/indicator/v2/pattern/hammerstick.go new file mode 100644 index 0000000000..598600bcc9 --- /dev/null +++ b/pkg/indicator/v2/pattern/hammerstick.go @@ -0,0 +1,65 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type HammerStickStream struct { + *types.Float64Series + inverted bool + window int +} + +func HammerStick(source v2.KLineSubscription, multiplier float64, inverted ...bool) *HammerStickStream { + var i bool + if len(inverted) > 0 { + i = true + } + + s := &HammerStickStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + inverted: i, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + one = source.Last(0) + oc = one.Open - one.Close + co = one.Close - one.Open + isBearishHammer = one.Open > one.Close && + fixedpoint.ApproxEqual(one.Open, one.High, multiplier) && + oc >= 2*(one.Close-one.Low) + isBearishInvertedHammer = one.Open > one.Close && + fixedpoint.ApproxEqual(one.Close, one.Low, multiplier) && + oc <= 2*(one.High-one.Open) + isBullishHammer = one.Close > one.Open && + fixedpoint.ApproxEqual(one.Close, one.High, multiplier) && + co <= 2*(one.Open-one.Low) + isBullishInvertedHammer = one.Close > one.Open && + fixedpoint.ApproxEqual(one.Open, one.Low, multiplier) && + co <= 2*(one.High-one.Close) + ) + + if !s.inverted && isBearishHammer || s.inverted && isBearishInvertedHammer { + output = Bear + } else if !s.inverted && isBullishHammer || s.inverted && isBullishInvertedHammer { + output = Bull + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/hammerstick_test.go b/pkg/indicator/v2/pattern/hammerstick_test.go new file mode 100644 index 0000000000..7e561bd83c --- /dev/null +++ b/pkg/indicator/v2/pattern/hammerstick_test.go @@ -0,0 +1,72 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestHammerStick(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(10.06), High: n(30.10), Close: n(26.13)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := HammerStick(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestHammerStick Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(26.13), Low: n(30.10), High: n(30.10), Close: n(10.06)}, + } + ind = HammerStick(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestHammerStick Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} + +func TestHammerStickInverted(t *testing.T) { + ts := []types.KLine{ + {Open: n(30.10), Low: n(26.13), High: n(52.06), Close: n(26.13)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := HammerStick(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestHammerStick Inverted Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(26.13), Low: n(30.10), High: n(52.06), Close: n(30.10)}, + } + ind = HammerStick(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := -1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestHammerStick Inverted Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/harami.go b/pkg/indicator/v2/pattern/harami.go new file mode 100644 index 0000000000..6c1a72444c --- /dev/null +++ b/pkg/indicator/v2/pattern/harami.go @@ -0,0 +1,56 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type HaramiStream struct { + *types.Float64Series + + window int +} + +func Harami(source v2.KLineSubscription) *HaramiStream { + s := &HaramiStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + ) + + // BEAR + if two.Open < two.Close { + if one.Open > one.Close { + if one.Open < two.Close && one.Close > two.Open { + output = Bear + } + } + } + + // BULL + if two.Open > two.Close { + if one.Open < one.Close { + if one.Open > two.Close && one.Close < two.Open { + output = Bull + } + } + } + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/harami_cross.go b/pkg/indicator/v2/pattern/harami_cross.go new file mode 100644 index 0000000000..2069f68368 --- /dev/null +++ b/pkg/indicator/v2/pattern/harami_cross.go @@ -0,0 +1,58 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type HaramiCrossStream struct { + *types.Float64Series + + window int +} + +func HaramiCross(source v2.KLineSubscription, maxDiff float64) *HaramiCrossStream { + s := &HaramiCrossStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + isSecondDayDoji = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) + isBullishHaramiCrossPattern = two.Open > one.Open && + two.Close > one.Open && + two.Close > one.Close && + two.Open < one.Low && + two.High < one.High + ) + if isBullishHaramiCrossPattern && isSecondDayDoji { + output = Bull + } else { + var isBearishHaramiCrossPattern = two.Open < one.Open && + two.Close < one.Open && + two.Close < one.Close && + two.Open > one.Low && + two.High > one.High + if isBearishHaramiCrossPattern && isSecondDayDoji { + output = Bear + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/harami_cross_test.go b/pkg/indicator/v2/pattern/harami_cross_test.go new file mode 100644 index 0000000000..9095afc286 --- /dev/null +++ b/pkg/indicator/v2/pattern/harami_cross_test.go @@ -0,0 +1,42 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestHaramiCross(t *testing.T) { + ts := []types.KLine{ + {Open: n(20.12), Low: n(19.88), High: n(23.82), Close: n(23.50)}, + {Open: n(22.13), Low: n(21.31), High: n(22.76), Close: n(22.13)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := HaramiCross(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestHaramiCross Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(25.13), Low: n(21.7), High: n(25.80), Close: n(22.14)}, + {Open: n(23.45), Low: n(23.07), High: n(24.59), Close: n(23.45)}, + } + ind = HaramiCross(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestHaramiCross Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/harami_test.go b/pkg/indicator/v2/pattern/harami_test.go new file mode 100644 index 0000000000..5bbcf8a5f5 --- /dev/null +++ b/pkg/indicator/v2/pattern/harami_test.go @@ -0,0 +1,42 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestHarami(t *testing.T) { + ts := []types.KLine{ + {Open: 100, Low: 95, High: 125, Close: 120}, + {Open: 110, Low: 100, High: 115, Close: 105}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Harami(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestHarami Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 120, Low: 95, High: 125, Close: 100}, + {Open: 105, Low: 100, High: 115, Close: 110}, + } + ind = Harami(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestHarami Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/kicking.go b/pkg/indicator/v2/pattern/kicking.go new file mode 100644 index 0000000000..40e4573e48 --- /dev/null +++ b/pkg/indicator/v2/pattern/kicking.go @@ -0,0 +1,70 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type KickingStream struct { + *types.Float64Series + + window int +} + +func Kicking(source v2.KLineSubscription, maxDiff float64) *KickingStream { + s := &KickingStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + ) + + // BEAR + if two.Open < two.Close { + if one.Open > one.Close { + if two.Open > one.Open { + if fixedpoint.ApproxEqual(two.Open, two.Low, maxDiff) && + fixedpoint.ApproxEqual(two.Close, two.High, maxDiff) { + if fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) && + fixedpoint.ApproxEqual(one.Close, one.Low, maxDiff) { + output = Bear + } + } + } + } + } + + // BULL + if two.Open > two.Close { + if one.Open < one.Close { + if two.Open < one.Open { + if fixedpoint.ApproxEqual(two.Open, two.High, maxDiff) && + fixedpoint.ApproxEqual(two.Close, two.Low, maxDiff) { + if fixedpoint.ApproxEqual(one.Open, one.Low, maxDiff) && + fixedpoint.ApproxEqual(one.Close, one.High, maxDiff) { + output = Bull + } + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/kicking_test.go b/pkg/indicator/v2/pattern/kicking_test.go new file mode 100644 index 0000000000..fe0348d164 --- /dev/null +++ b/pkg/indicator/v2/pattern/kicking_test.go @@ -0,0 +1,42 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestKicking(t *testing.T) { + ts := []types.KLine{ + {Open: 100, Low: 100, High: 120, Close: 120}, + {Open: 90, Low: 70, High: 90, Close: 70}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Kicking(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestKicking Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 90, Low: 70, High: 90, Close: 70}, + {Open: 100, Low: 100, High: 120, Close: 120}, + } + ind = Kicking(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestKicking Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/marubozu.go b/pkg/indicator/v2/pattern/marubozu.go new file mode 100644 index 0000000000..7f0a82c4ab --- /dev/null +++ b/pkg/indicator/v2/pattern/marubozu.go @@ -0,0 +1,47 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type MarubozuStream struct { + *types.Float64Series + + window int +} + +func Marubozu(source v2.KLineSubscription, maxDiff float64) *MarubozuStream { + s := &MarubozuStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + output = Neutral + one = source.Last(0) + ) + // BEAR + if one.Open > one.Close { + if fixedpoint.ApproxEqual(one.High, one.Open, maxDiff) && + fixedpoint.ApproxEqual(one.Low, one.Close, maxDiff) { + output = Bear + } + } + + // BULL + if one.Open < one.Close { + if fixedpoint.ApproxEqual(one.Low, one.Open, maxDiff) && + fixedpoint.ApproxEqual(one.High, one.Close, maxDiff) { + output = Bull + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/marubozu_test.go b/pkg/indicator/v2/pattern/marubozu_test.go new file mode 100644 index 0000000000..2cb241e1cd --- /dev/null +++ b/pkg/indicator/v2/pattern/marubozu_test.go @@ -0,0 +1,40 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestMarubozu(t *testing.T) { + ts := []types.KLine{ + {Open: 200, Low: 100, High: 200, Close: 100}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Marubozu(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestMarubozu Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 100, Low: 100, High: 200, Close: 200}, + } + ind = Marubozu(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestMarubozu Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/meeting_lines.go b/pkg/indicator/v2/pattern/meeting_lines.go new file mode 100644 index 0000000000..24f792eae4 --- /dev/null +++ b/pkg/indicator/v2/pattern/meeting_lines.go @@ -0,0 +1,62 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type MeetingLinesStream struct { + *types.Float64Series + + window int +} + +func MeetingLines(source v2.KLineSubscription) *MeetingLinesStream { + s := &MeetingLinesStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + + // BEAR + if three.Open < three.Close { + if two.Open < two.Close { + if one.Open > one.Close { + if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + output = Bear + } + } + } + } + + // BULL + if three.Open > three.Close { + if two.Open > two.Close { + if one.Open < one.Close { + if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + output = Bull + } + } + } + } + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/meeting_lines_test.go b/pkg/indicator/v2/pattern/meeting_lines_test.go new file mode 100644 index 0000000000..7d96097314 --- /dev/null +++ b/pkg/indicator/v2/pattern/meeting_lines_test.go @@ -0,0 +1,44 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestMeetingLines(t *testing.T) { + ts := []types.KLine{ + {Open: 85, Low: 85, High: 100, Close: 95}, + {Open: 95, Low: 90, High: 120, Close: 115}, + {Open: 130, Low: 105, High: 140, Close: 110}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := MeetingLines(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestMeetingLines Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 200, Low: 180, High: 210, Close: 190}, + {Open: 180, Low: 140, High: 195, Close: 150}, + {Open: 110, Low: 105, High: 160, Close: 155}, + } + ind = MeetingLines(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestMeetingLines Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/morning_evening_star.go b/pkg/indicator/v2/pattern/morning_evening_star.go new file mode 100644 index 0000000000..e3bd3dd1d5 --- /dev/null +++ b/pkg/indicator/v2/pattern/morning_evening_star.go @@ -0,0 +1,68 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type MorningOrEveningStarStream struct { + *types.Float64Series + + window int +} + +func MorningOrEveningStar(source v2.KLineSubscription) *MorningOrEveningStarStream { + s := &MorningOrEveningStarStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + firstMidpoint = (three.Open + three.Close) / 2 + isFirstBearish = three.Close < three.Open + hasSmallBody = three.Low > two.Low && + three.Low > two.High + isThirdBullish = one.Close > one.Open + gapExists = two.High < three.Low && + two.Low < three.Low && + one.Open > two.High && + two.Close < one.Open + doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + ) + if isFirstBearish && hasSmallBody && gapExists && isThirdBullish && doesCloseAboveFirstMidpoint { + output = Bull // morning star + } else { + var ( + isFirstBullish = three.Close > three.Open + isThirdBearish = one.Open > one.Close + doesCloseBelowFirstMidpoint = one.Close < firstMidpoint + ) + hasSmallBody = three.High < two.Low && + three.High < two.High + gapExists = two.High > three.High && + two.Low > three.High && + one.Open < two.Low && + two.Close > one.Open + if isFirstBullish && hasSmallBody && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { + output = Bear // evening star + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/morning_evening_star_test.go b/pkg/indicator/v2/pattern/morning_evening_star_test.go new file mode 100644 index 0000000000..c15269b324 --- /dev/null +++ b/pkg/indicator/v2/pattern/morning_evening_star_test.go @@ -0,0 +1,44 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestMorningOrEveningStar(t *testing.T) { + ts := []types.KLine{ + {Open: n(22.20), Low: n(20.65), High: n(22.50), Close: n(20.80)}, + {Open: n(20.30), Low: n(19.60), High: n(20.45), Close: n(19.60)}, + {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(20.40)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := MorningOrEveningStar(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestMorningOrEveningStar Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(18.35), Low: n(18.13), High: n(21.60), Close: n(21.30)}, + {Open: n(22.20), Low: n(21.87), High: n(22.70), Close: n(22.52)}, + {Open: n(21.60), Low: n(19.30), High: n(22.05), Close: n(19.45)}, + } + ind = MorningOrEveningStar(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestMorningOrEveningStar Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/pattern.go b/pkg/indicator/v2/pattern/pattern.go new file mode 100644 index 0000000000..64e39028a4 --- /dev/null +++ b/pkg/indicator/v2/pattern/pattern.go @@ -0,0 +1,15 @@ +package pattern + +import "github.com/c9s/bbgo/pkg/fixedpoint" + +var ( + Neutral = .0 + Bull = 1.0 + Bear = -1.0 + threshold = fixedpoint.NewFromFloat(0.1) + limit = fixedpoint.NewFromFloat(0.2) +) + +func n(n float64) fixedpoint.Value { + return fixedpoint.NewFromFloat(n) +} diff --git a/pkg/indicator/v2/pattern/piercing_line.go b/pkg/indicator/v2/pattern/piercing_line.go new file mode 100644 index 0000000000..80eb0e226f --- /dev/null +++ b/pkg/indicator/v2/pattern/piercing_line.go @@ -0,0 +1,48 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type PiercingLineStream struct { + *types.Float64Series + + window int +} + +func PiercingLine(source v2.KLineSubscription) *PiercingLineStream { + s := &PiercingLineStream{ + Float64Series: types.NewFloat64Series(), + window: 2, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + two = source.Last(1) + one = source.Last(0) + firstMidpoint = (two.Open + two.Close) / 2 + isDowntrend = one.Close < two.Low + isFirstBearish = two.Close < two.Open + isSecondBullish = one.Close > one.Open + isPiercingLine = two.Low > one.Open && + one.Close > firstMidpoint + ) + if isDowntrend && isFirstBearish && isSecondBullish && isPiercingLine { + output = Bull + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/piercing_line_test.go b/pkg/indicator/v2/pattern/piercing_line_test.go new file mode 100644 index 0000000000..c42553e8ba --- /dev/null +++ b/pkg/indicator/v2/pattern/piercing_line_test.go @@ -0,0 +1,27 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestPiercingLine(t *testing.T) { + ts := []types.KLine{ + {Open: n(42.70), Low: n(41.45), High: n(42.82), Close: n(41.60)}, + {Open: n(41.33), Low: n(41.15), High: n(42.50), Close: n(42.34)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := PiercingLine(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestPiercingLine Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } +} diff --git a/pkg/indicator/v2/pattern/separating_lines.go b/pkg/indicator/v2/pattern/separating_lines.go new file mode 100644 index 0000000000..5f402c8628 --- /dev/null +++ b/pkg/indicator/v2/pattern/separating_lines.go @@ -0,0 +1,67 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type SeparatingLinesStream struct { + *types.Float64Series + + window int +} + +func SeparatingLines(source v2.KLineSubscription, maxDiff float64) *SeparatingLinesStream { + s := &SeparatingLinesStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + // BEAR + if three.Open > three.Close { + if two.Open < two.Close { + if one.Open > one.Close { + if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) { + output = Bear + } + } + } + } + } + + // BULL + if three.Open < three.Close { + if two.Open > two.Close { + if one.Open < one.Close { + if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if fixedpoint.ApproxEqual(one.Open, one.Low, maxDiff) { + output = Bull + } + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/separating_lines_test.go b/pkg/indicator/v2/pattern/separating_lines_test.go new file mode 100644 index 0000000000..11ee59649a --- /dev/null +++ b/pkg/indicator/v2/pattern/separating_lines_test.go @@ -0,0 +1,44 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestSeparatingLines(t *testing.T) { + ts := []types.KLine{ + {Open: 200, Low: 160, High: 210, Close: 170}, + {Open: 150, Low: 140, High: 190, Close: 180}, + {Open: 152, Low: 120, High: 152, Close: 130}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := SeparatingLines(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestSeparatingLines Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 50, Low: 40, High: 80, Close: 70}, + {Open: 100, Low: 70, High: 110, Close: 80}, + {Open: 102, Low: 102, High: 130, Close: 120}, + } + ind = SeparatingLines(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestSeparatingLines Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines.go b/pkg/indicator/v2/pattern/side_by_side_whitelines.go new file mode 100644 index 0000000000..b3e92d7e4d --- /dev/null +++ b/pkg/indicator/v2/pattern/side_by_side_whitelines.go @@ -0,0 +1,80 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type SideBySideWhiteLinesStream struct { + *types.Float64Series + + window int +} + +func SideBySideWhiteLines(source v2.KLineSubscription, maxDiff float64) *SideBySideWhiteLinesStream { + s := &SideBySideWhiteLinesStream{ + Float64Series: types.NewFloat64Series(), + window: 4, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + four = source.Last(3) + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + + // BEAR + if four.Open > four.Close { + if three.Open > three.Close { + if three.Low > two.High { + if two.Open < two.Close { + if one.Open < one.Close { + if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if fixedpoint.ApproxEqual(two.Open, one.Open, maxDiff) { + output = Bear + } + } + } + } + } + } + } + } + + // BULL + if four.Open < four.Close { + if three.Open < three.Close { + if three.Low < two.High { + if two.Open < two.Close { + if one.Open < one.Close { + if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if fixedpoint.ApproxEqual(two.Open, one.Open, maxDiff) { + output = Bull + } + } + } + } + } + } + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go b/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go new file mode 100644 index 0000000000..0f01e53e3b --- /dev/null +++ b/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go @@ -0,0 +1,46 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestSideBySideWhiteLines(t *testing.T) { + ts := []types.KLine{ + {Open: 130, Low: 110, High: 140, Close: 120}, + {Open: 110, Low: 85, High: 115, Close: 90}, + {Open: 50, Low: 45, High: 75, Close: 70}, + {Open: 50, Low: 42, High: 77, Close: 68}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := SideBySideWhiteLines(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestSideBySideWhiteLines Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 70, Low: 60, High: 90, Close: 80}, + {Open: 100, Low: 90, High: 130, Close: 120}, + {Open: 150, Low: 140, High: 210, Close: 185}, + {Open: 150, Low: 135, High: 200, Close: 190}, + } + ind = SideBySideWhiteLines(kLines, 0.01) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestSideBySideWhiteLines Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/spinning_top.go b/pkg/indicator/v2/pattern/spinning_top.go new file mode 100644 index 0000000000..ebd2db6771 --- /dev/null +++ b/pkg/indicator/v2/pattern/spinning_top.go @@ -0,0 +1,46 @@ +package pattern + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type SpinningTopStream struct { + *types.Float64Series +} + +func SpinningTop(source v2.KLineSubscription) *SpinningTopStream { + s := &SpinningTopStream{ + Float64Series: types.NewFloat64Series(), + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + output = Neutral + one = source.Last(0) + bodyLength = fixedpoint.Abs(one.Close - one.Open) + upperShadowLength = fixedpoint.Abs(one.High - one.Close) + lowerShadowLength = fixedpoint.Abs(one.Open - one.Low) + isSpinningTop = bodyLength < upperShadowLength && + bodyLength < lowerShadowLength + ) + + if isSpinningTop { + output = Bull + } else { + upperShadowLength = fixedpoint.Abs(one.High - one.Open) + lowerShadowLength = fixedpoint.Abs(one.High - one.Low) + var isBearishSpinningTop = bodyLength < upperShadowLength && + bodyLength < lowerShadowLength + if isBearishSpinningTop { + output = Bear + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/spinning_top_test.go b/pkg/indicator/v2/pattern/spinning_top_test.go new file mode 100644 index 0000000000..a9bd598ca5 --- /dev/null +++ b/pkg/indicator/v2/pattern/spinning_top_test.go @@ -0,0 +1,40 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestSpinningTop(t *testing.T) { + ts := []types.KLine{ + {Open: n(20.50), Low: n(20.23), High: n(20.87), Close: n(20.62)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := SpinningTop(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestSpinningTop Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: n(20.62), Low: n(20.34), High: n(20.75), Close: n(20.50)}, + } + ind = SpinningTop(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestSpinningTop Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/three_crows.go b/pkg/indicator/v2/pattern/three_crows.go new file mode 100644 index 0000000000..e379133c8d --- /dev/null +++ b/pkg/indicator/v2/pattern/three_crows.go @@ -0,0 +1,56 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// https://www.candlescanner.com/candlestick-patterns/two-crows/ +// The Two Crows is a three-line bearish reversal candlestick pattern. +// The pattern requires confirmation, that is, the following candles should break +// a trendline or the nearest support area which may be formed by the first candle’s line. +// If the pattern is not confirmed it may act only as a temporary pause within an uptrend. +// Although the pattern name suggest that two lines form it, in fact, it contains three lines +type ThreeCrowsStream struct { + *types.Float64Series + + window int +} + +func ThreeCrows(source v2.KLineSubscription) *ThreeCrowsStream { + s := &ThreeCrowsStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + isDownTrend = three.Low > two.Low && two.Low > three.Low + isAllBearish = three.Open > three.Close && + two.Open > two.Close && one.Open > one.Close + opensWithinPreviousBody = three.Open > two.Open && + two.Open > three.Close && one.Open > two.Open + ) + + if isDownTrend && isAllBearish && opensWithinPreviousBody { + output = Bear + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/three_crows_test.go b/pkg/indicator/v2/pattern/three_crows_test.go new file mode 100644 index 0000000000..17b7f645f4 --- /dev/null +++ b/pkg/indicator/v2/pattern/three_crows_test.go @@ -0,0 +1,31 @@ +package pattern + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestThreeCrows(t *testing.T) { + ts := []types.KLine{ + {Open: n(21.65), Low: n(21.25), High: n(21.82), Close: n(21.32)}, + {Open: n(21.48), Low: n(20.97), High: n(21.57), Close: n(21.10)}, + {Open: n(21.25), Low: n(20.60), High: n(21.35), Close: n(20.70)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ThreeCrows(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + spew.Dump(ind) + if ind.Last(0) != expectedBear { + t.Errorf("TestThreeCrows Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } +} diff --git a/pkg/indicator/v2/pattern/three_line_strike.go b/pkg/indicator/v2/pattern/three_line_strike.go new file mode 100644 index 0000000000..6eaa3a68b9 --- /dev/null +++ b/pkg/indicator/v2/pattern/three_line_strike.go @@ -0,0 +1,73 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type ThreeLineStrikeStream struct { + *types.Float64Series + + window int +} + +func ThreeLineStrike(source v2.KLineSubscription) *ThreeLineStrikeStream { + s := &ThreeLineStrikeStream{ + Float64Series: types.NewFloat64Series(), + window: 4, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + + var ( + four = source.Last(3) + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + ) + // BEAR + if three.Close < four.Close { + if two.Close < three.Close { + if four.Close < three.Open && three.Open < four.Open { + if three.Close < two.Open && two.Open < three.Open { + if one.Open < two.Close { + if one.Close > four.Open { + output = Bear + } + } + } + } + + } + } + + // BULL + if three.Close > four.Close { + if two.Close > three.Close { + if four.Close > three.Open && three.Open > four.Open { + if three.Close > two.Open && two.Open > three.Open { + if one.Open > two.Close { + if one.Close < four.Open { + output = Bull + } + } + } + } + + } + } + + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/three_line_strike_test.go b/pkg/indicator/v2/pattern/three_line_strike_test.go new file mode 100644 index 0000000000..40573d475b --- /dev/null +++ b/pkg/indicator/v2/pattern/three_line_strike_test.go @@ -0,0 +1,47 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestThreeLineStrike(t *testing.T) { + ts := []types.KLine{ + {Open: 98, Low: 77, High: 100, Close: 80}, + {Open: 90, Low: 68, High: 95, Close: 73}, + {Open: 82, Low: 65, High: 86, Close: 67}, + {Open: 62, Low: 59, High: 103, Close: 101}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ThreeLineStrike(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(0) != expectedBear { + t.Errorf("TestThreeLineStrike Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + } + + ts = []types.KLine{ + {Open: 70, Low: 60, High: 100, Close: 90}, + {Open: 80, Low: 75, High: 110, Close: 105}, + {Open: 95, Low: 93, High: 120, Close: 115}, + {Open: 125, Low: 50, High: 130, Close: 55}, + } + ind = ThreeLineStrike(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestThreeLineStrike Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } + +} diff --git a/pkg/indicator/v2/pattern/three_white_soldiers.go b/pkg/indicator/v2/pattern/three_white_soldiers.go new file mode 100644 index 0000000000..33ec9fc797 --- /dev/null +++ b/pkg/indicator/v2/pattern/three_white_soldiers.go @@ -0,0 +1,51 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type ThreeWhiteSoldiersStream struct { + *types.Float64Series + + window int +} + +func ThreeWhiteSoldiers(source v2.KLineSubscription) *ThreeWhiteSoldiersStream { + s := &ThreeWhiteSoldiersStream{ + Float64Series: types.NewFloat64Series(), + window: 3, + } + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + var ( + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + isUpTrend = two.High > three.High && + one.High > two.High + isAllBullish = three.Open < three.Close && + two.Open < two.Close && + one.Open < one.Close + doesOpenWithinPreviousBody = three.Close > two.Open && + two.Open < three.High && + two.High > one.Open && + one.Open < two.Close + ) + if isUpTrend && isAllBullish && doesOpenWithinPreviousBody { + output = Bull + } + s.PushAndEmit(output) + + }) + + return s +} diff --git a/pkg/indicator/v2/pattern/three_white_soldiers_test.go b/pkg/indicator/v2/pattern/three_white_soldiers_test.go new file mode 100644 index 0000000000..92902eb807 --- /dev/null +++ b/pkg/indicator/v2/pattern/three_white_soldiers_test.go @@ -0,0 +1,28 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestThreeWhiteSoldiers(t *testing.T) { + ts := []types.KLine{ + {Open: n(21.12), Low: n(20.85), High: n(21.83), Close: n(21.65)}, + {Open: n(21.48), Low: n(21.36), High: n(21.36), Close: n(22.20)}, + {Open: n(21.80), Low: n(21.66), High: n(21.66), Close: n(22.65)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ThreeWhiteSoldiers(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBull := 1.0 + + if ind.Last(0) != expectedBull { + t.Errorf("TestThreeWhiteSoldiers Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + } +} diff --git a/pkg/indicator/v2/subtract_test.go b/pkg/indicator/v2/subtract_test.go index 1ef3aace3a..e9fab879b6 100644 --- a/pkg/indicator/v2/subtract_test.go +++ b/pkg/indicator/v2/subtract_test.go @@ -13,18 +13,33 @@ func Test_v2_Subtract(t *testing.T) { stream := &types.StandardStream{} kLines := KLines(stream, "", "") closePrices := ClosePrices(kLines) - fastEMA := EWMA2(closePrices, 10) - slowEMA := EWMA2(closePrices, 25) - subtract := Subtract(fastEMA, slowEMA) + toDiff := []DiffValue{ + { + Minuend: dec.New(10), + Subtrahend: dec.New(8), + }, + { + Minuend: dec.New(9), + Subtrahend: dec.New(9), + }, + { + Minuend: dec.New(8), + Subtrahend: dec.New(10), + }, + } + + diff := Subtract(fastEMA, slowEMA) for i := .0; i < 50.0; i++ { stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(19_000.0 + i)}) } - t.Logf("fastEMA: %+v", fastEMA.Slice) - t.Logf("slowEMA: %+v", slowEMA.Slice) + assert.Equal(t, []float64{2, 0, -2}, dec.FloatSlice(2, diff.Series()...)) + + // t.Logf("fastEMA: %+v", fastEMA.Slice) + // t.Logf("slowEMA: %+v", slowEMA.Slice) - assert.Equal(t, len(subtract.a), len(subtract.b)) - assert.Equal(t, len(subtract.a), len(subtract.Slice)) - assert.InDelta(t, subtract.Slice[0], subtract.a[0]-subtract.b[0], 0.0001) + // assert.Equal(t, len(subtract.a), len(subtract.b)) + // assert.Equal(t, len(subtract.a), len(subtract.Slice)) + // assert.InDelta(t, subtract.Slice[0], subtract.a[0]-subtract.b[0], 0.0001) } diff --git a/pkg/indicator/v2/trend/alma.go b/pkg/indicator/v2/trend/alma.go new file mode 100644 index 0000000000..17a9820df5 --- /dev/null +++ b/pkg/indicator/v2/trend/alma.go @@ -0,0 +1,74 @@ +// Copyright 2022 The Coln Group Ltd +// SPDX-License-Identifier: MIT + +package trend + +import ( + "github.com/thecolngroup/gou/dec" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +const ( + // DefaultALMAOffset is the default offset for the ALMA indicator. + DefaultALMAOffset = 0.85 + + // DefaultALMASigma is the default sigma for the ALMA indicator. + DefaultALMASigma = 6 +) + +type ALMAStream struct { + // embedded struct + *types.Float64Series + + sample *types.Float64Series + offset fixedpoint.Value + sigma fixedpoint.Value + window int +} + +// ALMA is a modern low lag moving average. +// Ported from https://www.tradingview.com/pine-script-reference/#fun_alma +// NewALMA creates a new ALMA indicator with default parameters. +func ALMA(source types.Float64Source, window int) *ALMAStream { + return ALMAWithSigma(window, DefaultALMAOffset, DefaultALMASigma) +} + +// NewALMAWithSigma creates a new ALMA indicator with the given offset and sigma. +func ALMAWithSigma(window int, offset, sigma float64) *ALMAStream { + return &ALMAStream{ + window: window, + offset: fixedpoint.NewFromFloat(offset), + sigma: fixedpoint.NewFromFloat(sigma), + } +} + +func (s *ALMAStream) Calculate(v float64) float64 { + + s.sample = v2.WindowAppend(s.sample, s.window-1, v) + + if s.window < 1 { + return v + } + var ( + length = fixedpoint.NewFromInt(int64(s.window)) + two = fixedpoint.Two + norm, sum fixedpoint.Value + offset = s.offset.Mul(length.Sub(fixedpoint.One)) + m = offset.Floor() + sig = length.Div(s.sigma) + ) + for i := 0; i < s.sample.Length(); i++ { + index := fixedpoint.NewFromInt(int64(i)) + pow := index.Sub(m).Pow(two).Div(sig.Pow(two).Mul(two)) + weight := fixedpoint.Exp(dec.New(-1).Mul(pow)) + norm = norm.Add(weight) + sum = fixedpoint.NewFromFloat(s.sample.Last(i)) + sum = sum.Mul(weight).Add(sum) + } + ma := sum.Div(norm) + + return ma.Float64() +} diff --git a/pkg/indicator/v2/trend/alma_test.go b/pkg/indicator/v2/trend/alma_test.go new file mode 100644 index 0000000000..9bf32227c1 --- /dev/null +++ b/pkg/indicator/v2/trend/alma_test.go @@ -0,0 +1,47 @@ +// Copyright 2022 The Coln Group Ltd +// SPDX-License-Identifier: MIT + +package trend + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestALMA(t *testing.T) { + + tests := []struct { + name string + giveV []float64 + giveLength int + want float64 + }{ + { + name: "Valid sample", + giveV: []float64{10, 89, 20, 43, 44, 33, 19}, + giveLength: 3, + want: 32.680479063242394, + }, + { + name: "0 length window", + giveV: []float64{10, 89, 20, 43, 44, 33, 19}, + giveLength: 0, + want: 19, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + source := types.NewFloat64Series() + alma := ALMA(source, tt.giveLength) + + for _, d := range tt.giveV { + source.PushAndEmit(d) + } + assert.Equal(t, tt.want, alma.Last(0)) + }) + } + +} diff --git a/pkg/indicator/v2/trend/aroon.go b/pkg/indicator/v2/trend/aroon.go new file mode 100644 index 0000000000..48cc9e452f --- /dev/null +++ b/pkg/indicator/v2/trend/aroon.go @@ -0,0 +1,100 @@ +package trend + +import ( + "math" + + "github.com/c9s/bbgo/pkg/types" +) + +// Aroon Indicator + +// The [Aroon](https://pkg.go.dev/github.com/cinar/indicator#Aroon) function calculates +// a technical indicator that is used to identify trend changes in the price of a stock, +// as well as the strength of that trend. It consists of two lines, Aroon Up, and Aroon Down. +// The Aroon Up line measures the strength of the uptrend, and the Aroon Down measures +// the strength of the downtrend. When Aroon Up is above Aroon Down, it indicates bullish price, +// and when Aroon Down is above Aroon Up, it indicates bearish price. + +// ``` +// +// Aroon Up = ((25 - Period Since Last 25 Period High) / 25) * 100 +// Aroon Down = ((25 - Period Since Last 25 Period Low) / 25) * 100 +// +// ``` +type AroonStream struct { + *types.Float64Series + + window, lowIndex int + direction float64 +} + +// AroonUpIndicator returns a derivative indicator that will return a value based on +// the number of ticks since the highest price in the window +// https://www.investopedia.com/terms/a/aroon.asp +// +// Note: this indicator should be constructed with a either a HighPriceIndicator or a derivative thereof +func AroonUpIndicator(source types.Float64Source, window int) *AroonStream { + s := &AroonStream{ + Float64Series: types.NewFloat64Series(), + window: window, + lowIndex: -1, + direction: -1.0, + } + s.Bind(source, s) + return s +} + +// AroonDownIndicator returns a derivative indicator that will return a value based on +// the number of ticks since the lowest price in the window +// https://www.investopedia.com/terms/a/aroon.asp +// +// Note: this indicator should be constructed with a either a LowPriceIndicator or a derivative thereof +func AroonDownIndicator(source types.Float64Source, window int) *AroonStream { + s := &AroonStream{ + Float64Series: types.NewFloat64Series(), + window: window, + lowIndex: -1, + direction: 1.0, + } + s.Bind(source, s) + return s +} + +func (s *AroonStream) Calculate(v float64) float64 { + if s.Length() < s.window-1 { + return 0 + } + + var ( + index = s.Length() - 1 + pSince = index - s.findLowIndex(index) + aroon = float64(s.window-pSince) / float64(s.window*100) + ) + + return aroon +} + +func (s *AroonStream) findLowIndex(index int) int { + if s.lowIndex < 1 || s.lowIndex < index-s.window { + lv := math.MaxFloat64 + lowIndex := -1 + for i := (index + 1) - s.window; i <= index; i++ { + value := s.Last(i) * s.direction + if value < lv { + lv = value + lowIndex = i + } + } + + return lowIndex + } + + v1 := s.Last(0) * s.direction + v2 := s.Last(s.lowIndex) * s.direction + + if v1 < v2 { + return index + } + + return s.lowIndex +} diff --git a/pkg/indicator/v2/trend/aroon_test.go b/pkg/indicator/v2/trend/aroon_test.go new file mode 100644 index 0000000000..9e3c633b8b --- /dev/null +++ b/pkg/indicator/v2/trend/aroon_test.go @@ -0,0 +1,61 @@ +package trend + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestAroonUpIndicator(t *testing.T) { + t.Run("with < window periods", func(t *testing.T) { + source := types.NewFloat64Series() + aroonUp := AroonUpIndicator(source, 10) + + data := []float64{1} + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 0.0, aroonUp.Last(0)) + }) + + t.Run("with > window periods", func(t *testing.T) { + source := types.NewFloat64Series() + aroonUp := AroonUpIndicator(source, 4) + + data := []float64{1, 2, 3, 4, 3, 2, 1} + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 100.0, aroonUp.Last(3)) + assert.Equal(t, 75.0, aroonUp.Last(4)) + assert.Equal(t, 50.0, aroonUp.Last(5)) + }) +} + +func TestAroonDownIndicator(t *testing.T) { + t.Run("with < window periods", func(t *testing.T) { + source := types.NewFloat64Series() + aroonDown := AroonDownIndicator(source, 10) + + data := []float64{1} + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 0.0, aroonDown.Last(0)) + }) + + t.Run("with > window periods", func(t *testing.T) { + source := types.NewFloat64Series() + aroonDown := AroonDownIndicator(source, 4) + + data := []float64{5, 4, 3, 2, 3, 4, 5} + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 100.0, aroonDown.Last(3)) + assert.Equal(t, 75.0, aroonDown.Last(4)) + assert.Equal(t, 50.0, aroonDown.Last(5)) + }) +} diff --git a/pkg/indicator/v2/cma.go b/pkg/indicator/v2/trend/cma.go similarity index 96% rename from pkg/indicator/v2/cma.go rename to pkg/indicator/v2/trend/cma.go index 9d0cbea648..ffccf295eb 100644 --- a/pkg/indicator/v2/cma.go +++ b/pkg/indicator/v2/trend/cma.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "github.com/c9s/bbgo/pkg/indicator" diff --git a/pkg/indicator/v2/trend/dema.go b/pkg/indicator/v2/trend/dema.go new file mode 100644 index 0000000000..d3f5517561 --- /dev/null +++ b/pkg/indicator/v2/trend/dema.go @@ -0,0 +1,43 @@ +package trend + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +// Double Exponential Moving Average (DEMA) + +// The [Dema](https://pkg.go.dev/github.com/cinar/indicator#Dema) function calculates +// the Double Exponential Moving Average (DEMA) for a given period. + +// The double exponential moving average (DEMA) is a technical indicator introduced by Patrick Mulloy. +// The purpose is to reduce the amount of noise present in price charts used by technical traders. +// The DEMA uses two exponential moving averages (EMAs) to eliminate lag. +// It helps confirm uptrends when the price is above the average, and helps confirm downtrends +// when the price is below the average. When the price crosses the average that may signal a trend change. + +// ``` +// +// DEMA = (2 * EMA(values)) - EMA(EMA(values)) +// +// ``` + +type DEMAStream struct { + // embedded struct + *types.Float64Series + + ema1 *EWMAStream + ema2 *EWMAStream +} + +func DEMA(source types.Float64Source, window int) *DEMAStream { + ema1 := EWMA2(source, window) + ema2 := EWMA2(source, window) + return &DEMAStream{ema1: ema1, ema2: ema2} +} + +func (s *DEMAStream) Calculate(v float64) float64 { + e1 := s.ema1.Last(0) + e2 := s.ema2.Last(0) + dema := e1*2 - e2 + return dema +} diff --git a/pkg/indicator/v2/ewma.go b/pkg/indicator/v2/trend/ewma.go similarity index 96% rename from pkg/indicator/v2/ewma.go rename to pkg/indicator/v2/trend/ewma.go index fdd9745f0d..e67d5363d7 100644 --- a/pkg/indicator/v2/ewma.go +++ b/pkg/indicator/v2/trend/ewma.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/macd.go b/pkg/indicator/v2/trend/macd.go similarity index 76% rename from pkg/indicator/v2/macd.go rename to pkg/indicator/v2/trend/macd.go index 1679cf6c09..dc862b8937 100644 --- a/pkg/indicator/v2/macd.go +++ b/pkg/indicator/v2/trend/macd.go @@ -1,25 +1,26 @@ -package indicatorv2 +package trend import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) type MACDStream struct { - *SubtractStream + *v2.SubtractStream shortWindow, longWindow, signalWindow int FastEWMA, SlowEWMA, Signal *EWMAStream - Histogram *SubtractStream + Histogram *v2.SubtractStream } func MACD2(source types.Float64Source, shortWindow, longWindow, signalWindow int) *MACDStream { // bind and calculate these first fastEWMA := EWMA2(source, shortWindow) slowEWMA := EWMA2(source, longWindow) - macd := Subtract(fastEWMA, slowEWMA) + macd := v2.Subtract(fastEWMA, slowEWMA) signal := EWMA2(macd, signalWindow) - histogram := Subtract(macd, signal) + histogram := v2.Subtract(macd, signal) return &MACDStream{ SubtractStream: macd, shortWindow: shortWindow, diff --git a/pkg/indicator/v2/macd_test.go b/pkg/indicator/v2/trend/macd_test.go similarity index 94% rename from pkg/indicator/v2/macd_test.go rename to pkg/indicator/v2/trend/macd_test.go index 3b6b72405c..4d20e46fdb 100644 --- a/pkg/indicator/v2/macd_test.go +++ b/pkg/indicator/v2/trend/macd_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "encoding/json" @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -49,7 +50,7 @@ func Test_MACD2(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - prices := ClosePrices(nil) + prices := v2.ClosePrices(nil) macd := MACD2(prices, 12, 26, 9) for _, k := range tt.kLines { prices.EmitUpdate(k.Close.Float64()) diff --git a/pkg/indicator/v2/rma.go b/pkg/indicator/v2/trend/rma.go similarity index 98% rename from pkg/indicator/v2/rma.go rename to pkg/indicator/v2/trend/rma.go index 1aa08ccdc0..6e3d7289fc 100644 --- a/pkg/indicator/v2/rma.go +++ b/pkg/indicator/v2/trend/rma.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/sma.go b/pkg/indicator/v2/trend/sma.go similarity index 96% rename from pkg/indicator/v2/sma.go rename to pkg/indicator/v2/trend/sma.go index 5afd4f8250..9e0257b161 100644 --- a/pkg/indicator/v2/sma.go +++ b/pkg/indicator/v2/trend/sma.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/sma_test.go b/pkg/indicator/v2/trend/sma_test.go similarity index 94% rename from pkg/indicator/v2/sma_test.go rename to pkg/indicator/v2/trend/sma_test.go index 384964ba39..59c836a6bd 100644 --- a/pkg/indicator/v2/sma_test.go +++ b/pkg/indicator/v2/trend/sma_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "testing" diff --git a/pkg/indicator/v2/volatility/atr.go b/pkg/indicator/v2/volatility/atr.go new file mode 100644 index 0000000000..564bc752dd --- /dev/null +++ b/pkg/indicator/v2/volatility/atr.go @@ -0,0 +1,17 @@ +package volatility + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" +) + +type ATRStream struct { + // embedded struct + *trend.RMAStream +} + +func ATR2(source v2.KLineSubscription, window int) *ATRStream { + tr := TR2(source) + rma := trend.RMA2(tr, window, true) + return &ATRStream{RMAStream: rma} +} diff --git a/pkg/indicator/v2/atr_test.go b/pkg/indicator/v2/volatility/atr_test.go similarity index 96% rename from pkg/indicator/v2/atr_test.go rename to pkg/indicator/v2/volatility/atr_test.go index 7beb2be4c0..b103b589a9 100644 --- a/pkg/indicator/v2/atr_test.go +++ b/pkg/indicator/v2/volatility/atr_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package volatility import ( "encoding/json" @@ -6,6 +6,7 @@ import ( "testing" "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -64,7 +65,7 @@ func Test_ATR2(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := KLines(stream, "", "") + kLines := v2.KLines(stream, "", "") atr := ATR2(kLines, tt.window) for _, k := range tt.kLines { diff --git a/pkg/indicator/v2/atrp.go b/pkg/indicator/v2/volatility/atrp.go similarity index 54% rename from pkg/indicator/v2/atrp.go rename to pkg/indicator/v2/volatility/atrp.go index e22810ff78..8466e782bd 100644 --- a/pkg/indicator/v2/atrp.go +++ b/pkg/indicator/v2/volatility/atrp.go @@ -1,17 +1,21 @@ -package indicatorv2 +package volatility -import "github.com/c9s/bbgo/pkg/types" +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/types" +) type ATRPStream struct { *types.Float64Series } -func ATRP2(source KLineSubscription, window int) *ATRPStream { +func ATRP2(source v2.KLineSubscription, window int) *ATRPStream { s := &ATRPStream{ Float64Series: types.NewFloat64Series(), } tr := TR2(source) - atr := RMA2(tr, window, true) + atr := trend.RMA2(tr, window, true) atr.OnUpdate(func(x float64) { // x is the last rma k := source.Last(0) diff --git a/pkg/indicator/v2/boll.go b/pkg/indicator/v2/volatility/boll.go similarity index 82% rename from pkg/indicator/v2/boll.go rename to pkg/indicator/v2/volatility/boll.go index 611f0ea346..4f7a861e03 100644 --- a/pkg/indicator/v2/boll.go +++ b/pkg/indicator/v2/volatility/boll.go @@ -1,6 +1,8 @@ -package indicatorv2 +package volatility import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -13,8 +15,8 @@ type BOLLStream struct { window int k float64 - SMA *SMAStream - StdDev *StdDevStream + SMA *trend.SMAStream + StdDev *v2.StdDevStream } // BOOL2 is bollinger indicator @@ -26,8 +28,8 @@ type BOLLStream struct { // -> calculate stdDev -> calculate bandWidth -> get latest SMA -> upBand, downBand func BOLL(source types.Float64Source, window int, k float64) *BOLLStream { // bind these indicators before our main calculator - sma := SMA(source, window) - stdDev := StdDev(source, window) + sma := trend.SMA(source, window) + stdDev := v2.StdDev(source, window) s := &BOLLStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/tr.go b/pkg/indicator/v2/volatility/tr.go similarity index 87% rename from pkg/indicator/v2/tr.go rename to pkg/indicator/v2/volatility/tr.go index 66d7cec5df..1ec8b2638d 100644 --- a/pkg/indicator/v2/tr.go +++ b/pkg/indicator/v2/volatility/tr.go @@ -1,8 +1,9 @@ -package indicatorv2 +package volatility import ( "math" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +16,7 @@ type TRStream struct { previousClose float64 } -func TR2(source KLineSubscription) *TRStream { +func TR2(source v2.KLineSubscription) *TRStream { s := &TRStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/tr_test.go b/pkg/indicator/v2/volatility/tr_test.go similarity index 93% rename from pkg/indicator/v2/tr_test.go rename to pkg/indicator/v2/volatility/tr_test.go index 82afd8269e..adc3eb911f 100644 --- a/pkg/indicator/v2/tr_test.go +++ b/pkg/indicator/v2/volatility/tr_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package volatility import ( "encoding/json" @@ -6,6 +6,8 @@ import ( "testing" "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -64,9 +66,9 @@ func Test_TR_and_RMA(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := KLines(stream, "", "") + kLines := v2.KLines(stream, "", "") atr := TR2(kLines) - rma := RMA2(atr, tt.window, true) + rma := trend.RMA2(atr, tt.window, true) for _, k := range tt.kLines { stream.EmitKLineClosed(k) diff --git a/pkg/indicator/v2/volume/accumulation_distiribution.go b/pkg/indicator/v2/volume/accumulation_distiribution.go new file mode 100644 index 0000000000..932d33d494 --- /dev/null +++ b/pkg/indicator/v2/volume/accumulation_distiribution.go @@ -0,0 +1,41 @@ +package volume + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// Accumulation/Distribution Indicator (A/D). Cumulative indicator +// that uses volume and price to assess whether a stock is +// being accumulated or distributed. +// +// MFM = ((Closing - Low) - (High - Closing)) / (High - Low) +// MFV = MFM * Period Volume +// AD = Previous AD + CMFV +type AccumulationDistributionStream struct { + *types.Float64Series +} + +func AccumulationDistribution(source v2.KLineSubscription) *AccumulationDistributionStream { + s := &AccumulationDistributionStream{ + Float64Series: types.NewFloat64Series(), + } + + source.AddSubscriber(func(v types.KLine) { + var ( + i = s.Slice.Length() + output = fixedpoint.NewFromInt(0) + ) + + if i > 0 { + output = fixedpoint.NewFromFloat(s.Slice.Last(0)) + } + + output += v.Volume * ((v.Close - v.Low) - (v.High-v.Close)/(v.High-v.Low)) + + s.PushAndEmit(output.Float64()) + }) + + return s +} diff --git a/pkg/indicator/v2/volume/accumulation_distiribution_test.go b/pkg/indicator/v2/volume/accumulation_distiribution_test.go new file mode 100644 index 0000000000..4389129a8a --- /dev/null +++ b/pkg/indicator/v2/volume/accumulation_distiribution_test.go @@ -0,0 +1,20 @@ +package volume + +import ( + "testing" +) + +func TestAccumulationDistribution(t *testing.T) { + // ts := []types.KLine{ + // {Open: 90, Low: 85, High: 105, Close: 100}, + // } + + // stream := &types.StandardStream{} + // kLines := v2.KLines(stream, "", "") + // ind := AccumulationDistribution(kLines) + + // for _, candle := range ts { + // stream.EmitKLineClosed(candle) + // } + // expected := []float64{} +} diff --git a/pkg/indicator/v2/volume/negative_volume_index.go b/pkg/indicator/v2/volume/negative_volume_index.go new file mode 100644 index 0000000000..3eef117443 --- /dev/null +++ b/pkg/indicator/v2/volume/negative_volume_index.go @@ -0,0 +1,49 @@ +package volume + +import ( + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// Starting value for NVI. +const NVI_STARTING_VALUE = 1000 + +// Negative Volume Index (NVI) +type NVIStream struct { + *types.Float64Series +} + +// The [NegativeVolumeIndex](https://pkg.go.dev/github.com/cinar/indicator#NegativeVolumeIndex) +// function calculates a cumulative indicator using the change in volume to decide when the smart money is active. +// +// If Volume is greather than Previous Volume: +// NVI = Previous NVI +// Otherwise: +// NVI = Previous NVI + (((Closing - Previous Closing) / Previous Closing) * Previous NVI) +func NegativeVolumeIndex(source v2.KLineSubscription) *NVIStream { + s := &NVIStream{ + Float64Series: types.NewFloat64Series(), + } + + source.AddSubscriber(func(v types.KLine) { + var nvi = fixedpoint.Zero + + if s.Slice.Length() == 0 { + nvi = NVI_STARTING_VALUE + } else { + closing := source.Last(0).Close + prevClose := source.Last(1).Close + lastNVI := fixedpoint.NewFromFloat(s.Slice.Last(0)) + if source.Last(1).Volume < source.Last(0).Volume { + nvi = lastNVI + } else { + nvi += ((closing - prevClose) / prevClose) * lastNVI + } + } + + s.PushAndEmit(nvi.Float64()) + }) + + return s +} diff --git a/pkg/indicator/v2/volume/negative_volume_index_test.go b/pkg/indicator/v2/volume/negative_volume_index_test.go new file mode 100644 index 0000000000..09c1740d15 --- /dev/null +++ b/pkg/indicator/v2/volume/negative_volume_index_test.go @@ -0,0 +1,34 @@ +package volume + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestNegativeVolumeIndex(t *testing.T) { + ts := []types.KLine{ + {Volume: 100, Close: 9}, + {Volume: 110, Close: 11}, + {Volume: 80, Close: 7}, + {Volume: 120, Close: 10}, + {Volume: 90, Close: 8}, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := NegativeVolumeIndex(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + assert.InDelta(t, 509.09, ind.Last(0), 0.001) + assert.InDelta(t, 636.36, ind.Last(1), 0.001) + assert.InDelta(t, 636.36, ind.Last(2), 0.001) + assert.InDelta(t, 1000.0, ind.Last(3), 0.001) + assert.InDelta(t, 1000.0, ind.Last(4), 0.001) + +} diff --git a/pkg/risk/riskcontrol/circuit_break.go b/pkg/risk/riskcontrol/circuit_break.go index e8e8ad3b09..a73eb4d103 100644 --- a/pkg/risk/riskcontrol/circuit_break.go +++ b/pkg/risk/riskcontrol/circuit_break.go @@ -6,14 +6,14 @@ import ( log "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/fixedpoint" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) type CircuitBreakRiskControl struct { // Since price could be fluctuated large, // use an EWMA to smooth it in running time - price *indicatorv2.EWMAStream + price *trend.EWMAStream position *types.Position profitStats *types.ProfitStats lossThreshold fixedpoint.Value @@ -24,7 +24,7 @@ type CircuitBreakRiskControl struct { func NewCircuitBreakRiskControl( position *types.Position, - price *indicatorv2.EWMAStream, + price *trend.EWMAStream, lossThreshold fixedpoint.Value, profitStats *types.ProfitStats, haltedDuration time.Duration, diff --git a/pkg/risk/riskcontrol/circuit_break_test.go b/pkg/risk/riskcontrol/circuit_break_test.go index 54f523d4b1..33c9eb1184 100644 --- a/pkg/risk/riskcontrol/circuit_break_test.go +++ b/pkg/risk/riskcontrol/circuit_break_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -19,7 +19,7 @@ func Test_IsHalted(t *testing.T) { ) window := types.IntervalWindow{Window: 30, Interval: types.Interval1m} - priceEWMA := indicatorv2.EWMA2(nil, window.Window) + priceEWMA := trend.EWMA2(nil, window.Window) priceEWMA.PushAndEmit(price) cases := []struct { diff --git a/pkg/strategy/scmaker/intensity.go b/pkg/strategy/scmaker/intensity.go index 0472241230..57393f7c5c 100644 --- a/pkg/strategy/scmaker/intensity.go +++ b/pkg/strategy/scmaker/intensity.go @@ -3,13 +3,14 @@ package scmaker import ( "github.com/c9s/bbgo/pkg/fixedpoint" indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) type IntensityStream struct { *types.Float64Series - Buy, Sell *indicatorv2.RMAStream + Buy, Sell *trend.RMAStream window int } @@ -18,8 +19,8 @@ func Intensity(source indicatorv2.KLineSubscription, window int) *IntensityStrea Float64Series: types.NewFloat64Series(), window: window, - Buy: indicatorv2.RMA2(types.NewFloat64Series(), window, false), - Sell: indicatorv2.RMA2(types.NewFloat64Series(), window, false), + Buy: trend.RMA2(types.NewFloat64Series(), window, false), + Sell: trend.RMA2(types.NewFloat64Series(), window, false), } threshold := fixedpoint.NewFromFloat(100.0) diff --git a/pkg/strategy/scmaker/strategy.go b/pkg/strategy/scmaker/strategy.go index ecccefc8b0..389a54b080 100644 --- a/pkg/strategy/scmaker/strategy.go +++ b/pkg/strategy/scmaker/strategy.go @@ -12,6 +12,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/fixedpoint" . "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/risk/riskcontrol" "github.com/c9s/bbgo/pkg/strategy/common" "github.com/c9s/bbgo/pkg/types" @@ -74,7 +75,7 @@ type Strategy struct { liquidityScale bbgo.Scale // indicators - ewma *EWMAStream + ewma *trend.EWMAStream boll *BOLLStream intensity *IntensityStream @@ -186,7 +187,7 @@ func (s *Strategy) preloadKLines(inc *KLineStream, session *bbgo.ExchangeSession func (s *Strategy) initializeMidPriceEMA(session *bbgo.ExchangeSession) { kLines := KLines(session.MarketDataStream, s.Symbol, s.MidPriceEMA.Interval) - s.ewma = EWMA2(ClosePrices(kLines), s.MidPriceEMA.Window) + s.ewma = trend.EWMA2(ClosePrices(kLines), s.MidPriceEMA.Window) s.preloadKLines(kLines, session, s.Symbol, s.MidPriceEMA.Interval) } diff --git a/pkg/strategy/xfixedmaker/order_price_risk.go b/pkg/strategy/xfixedmaker/order_price_risk.go index e7ec81b1c9..bbd8a1d745 100644 --- a/pkg/strategy/xfixedmaker/order_price_risk.go +++ b/pkg/strategy/xfixedmaker/order_price_risk.go @@ -2,16 +2,16 @@ package xfixedmaker import ( "github.com/c9s/bbgo/pkg/fixedpoint" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) type OrderPriceRiskControl struct { - referencePrice *indicatorv2.EWMAStream + referencePrice *trend.EWMAStream lossThreshold fixedpoint.Value } -func NewOrderPriceRiskControl(referencePrice *indicatorv2.EWMAStream, threshold fixedpoint.Value) *OrderPriceRiskControl { +func NewOrderPriceRiskControl(referencePrice *trend.EWMAStream, threshold fixedpoint.Value) *OrderPriceRiskControl { return &OrderPriceRiskControl{ referencePrice: referencePrice, lossThreshold: threshold, diff --git a/pkg/strategy/xfixedmaker/order_price_risk_test.go b/pkg/strategy/xfixedmaker/order_price_risk_test.go index da023c733e..d18fc2d647 100644 --- a/pkg/strategy/xfixedmaker/order_price_risk_test.go +++ b/pkg/strategy/xfixedmaker/order_price_risk_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +15,7 @@ func Test_OrderPriceRiskControl_IsSafe(t *testing.T) { lossThreshold := fixedpoint.NewFromFloat(-100) window := types.IntervalWindow{Window: 30, Interval: types.Interval1m} - refPriceEWMA := indicatorv2.EWMA2(nil, window.Window) + refPriceEWMA := trend.EWMA2(nil, window.Window) refPriceEWMA.PushAndEmit(refPrice) cases := []struct { From 834629793a1b51a0a0487383c97ba24892aa414f Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Thu, 26 Oct 2023 05:21:03 +0200 Subject: [PATCH 02/17] extend v2 indicators --- pkg/bbgo/indicator_set.go | 13 +- pkg/datatype/floats/slice.go | 12 + pkg/exchange/bitget/bitgetapi/types.go | 1 + pkg/indicator/v2/bst/bst.go | 94 ++++++ pkg/indicator/v2/bst/bst_test.go | 57 ++++ pkg/indicator/v2/bst/compare.go | 115 +++++++ pkg/indicator/v2/ichimoku/builder.go | 79 ----- pkg/indicator/v2/ichimoku/ichimoku.go | 220 ------------- pkg/indicator/v2/ichimoku/indicator.go | 77 ----- pkg/indicator/v2/ichimoku/line-value.go | 30 -- pkg/indicator/v2/ichimoku/line_helper.go | 159 ---------- pkg/indicator/v2/ichimoku/status.go | 150 --------- pkg/indicator/v2/ichimoku/types.go | 70 ----- .../v2/ichimoku1/.vscode/launch.json | 15 - pkg/indicator/v2/ichimoku1/README.md | 36 --- pkg/indicator/v2/ichimoku1/builder.go | 81 ----- pkg/indicator/v2/ichimoku1/example/main.go | 242 --------------- pkg/indicator/v2/ichimoku1/images/demo.png | Bin 131507 -> 0 bytes pkg/indicator/v2/ichimoku1/indicator.go | 293 ------------------ pkg/indicator/v2/ichimoku1/line-value.go | 28 -- pkg/indicator/v2/ichimoku1/line_helper.go | 163 ---------- pkg/indicator/v2/ichimoku1/status.go | 150 --------- .../v2/ichimoku1/tests/analyse_test.go | 115 ------- .../v2/ichimoku1/tests/cloud_test.go | 157 ---------- pkg/indicator/v2/ichimoku1/types.go | 70 ----- pkg/indicator/v2/lookback.go | 40 --- pkg/indicator/v2/maxval.go | 41 +++ pkg/indicator/v2/maxval_test.go | 24 ++ pkg/indicator/v2/minval.go | 41 +++ pkg/indicator/v2/minval_test.go | 24 ++ pkg/indicator/v2/momentum/awesome_osc_test.go | 55 ++++ pkg/indicator/v2/momentum/awseome_osc.go | 79 +++++ pkg/indicator/v2/momentum/chaikin_osc.go | 41 +++ pkg/indicator/v2/momentum/chaikin_osc_test.go | 41 +++ pkg/indicator/v2/{ => momentum}/stoch.go | 11 +- pkg/indicator/v2/{ => momentum}/stoch_test.go | 5 +- .../{ => momentum}/stochstream_callbacks.go | 2 +- pkg/indicator/v2/momentum/williams_r.go | 55 ++++ pkg/indicator/v2/momentum/williams_r_test.go | 60 ++++ pkg/indicator/v2/pattern/abondoned_baby.go | 7 +- .../v2/pattern/abondoned_baby_test.go | 8 +- pkg/indicator/v2/pattern/belthold.go | 4 + pkg/indicator/v2/pattern/belthold_test.go | 8 +- pkg/indicator/v2/pattern/breakaway.go | 4 + pkg/indicator/v2/pattern/breakaway_test.go | 20 +- pkg/indicator/v2/pattern/dark_cloud.go | 4 + pkg/indicator/v2/pattern/doji.go | 6 +- pkg/indicator/v2/pattern/doji_dragon_fly.go | 26 +- .../v2/pattern/doji_dragon_fly_test.go | 20 +- pkg/indicator/v2/pattern/doji_gravestone.go | 27 +- .../v2/pattern/doji_gravestone_test.go | 20 +- pkg/indicator/v2/pattern/doji_long_legged.go | 16 +- .../v2/pattern/doji_long_legged_test.go | 16 +- pkg/indicator/v2/pattern/doji_star.go | 55 ++-- pkg/indicator/v2/pattern/doji_star_test.go | 7 +- pkg/indicator/v2/pattern/doji_test.go | 17 +- .../v2/pattern/downside_tazuki_gap.go | 6 +- .../v2/pattern/downside_tazuki_gap_test.go | 2 +- pkg/indicator/v2/pattern/engulfing.go | 4 + pkg/indicator/v2/pattern/engulfing_test.go | 8 +- pkg/indicator/v2/pattern/hammerstick.go | 65 ---- pkg/indicator/v2/pattern/hammerstick_test.go | 72 ----- pkg/indicator/v2/pattern/harami.go | 4 + pkg/indicator/v2/pattern/harami_cross.go | 38 ++- pkg/indicator/v2/pattern/harami_cross_test.go | 5 +- pkg/indicator/v2/pattern/harami_test.go | 8 +- pkg/indicator/v2/pattern/head_shoulders.go | 59 ++++ .../v2/pattern/head_shoulders_test.go | 56 ++++ pkg/indicator/v2/pattern/kicking.go | 4 + pkg/indicator/v2/pattern/kicking_test.go | 8 +- pkg/indicator/v2/pattern/marubozu.go | 4 + pkg/indicator/v2/pattern/marubozu_test.go | 4 +- pkg/indicator/v2/pattern/meeting_lines.go | 4 + .../v2/pattern/meeting_lines_test.go | 12 +- .../v2/pattern/morning_evening_star.go | 57 ++-- .../v2/pattern/morning_evening_star_test.go | 23 +- pkg/indicator/v2/pattern/pattern.go | 11 +- pkg/indicator/v2/pattern/piercing_line.go | 6 +- .../v2/pattern/piercing_line_test.go | 7 +- pkg/indicator/v2/pattern/separating_lines.go | 4 + .../v2/pattern/separating_lines_test.go | 12 +- .../v2/pattern/side_by_side_whitelines.go | 4 + .../pattern/side_by_side_whitelines_test.go | 16 +- pkg/indicator/v2/pattern/spinning_top.go | 40 ++- pkg/indicator/v2/pattern/spinning_top_test.go | 4 +- pkg/indicator/v2/pattern/three_crows.go | 10 +- pkg/indicator/v2/pattern/three_crows_test.go | 3 - pkg/indicator/v2/pattern/three_line_strike.go | 4 + .../v2/pattern/three_line_strike_test.go | 16 +- .../v2/pattern/three_white_soldiers.go | 6 + .../v2/pattern/three_white_soldiers_test.go | 5 +- pkg/indicator/v2/price.go | 3 + pkg/indicator/v2/squared_average.go | 37 +++ pkg/indicator/v2/subtract_test.go | 55 ++-- pkg/indicator/v2/trend/alma.go | 55 ++-- pkg/indicator/v2/trend/alma_test.go | 2 +- pkg/indicator/v2/trend/aroon.go | 100 ------ pkg/indicator/v2/trend/aroon_test.go | 61 ---- pkg/indicator/v2/{ => trend}/cci.go | 2 +- pkg/indicator/v2/{ => trend}/cci_test.go | 6 +- pkg/indicator/v2/trend/sma.go | 4 +- .../v2/volatility/chandelier_exit.go | 62 ++++ pkg/indicator/v2/volatility/ulcer_index.go | 48 +++ .../v2/volatility/ulcer_index_test.go | 23 ++ .../v2/volume/accumulation_distiribution.go | 9 +- .../volume/accumulation_distiribution_test.go | 44 ++- .../v2/volume/negative_volume_index.go | 22 +- .../v2/volume/negative_volume_index_test.go | 26 +- pkg/indicator/v2/window.go | 24 ++ .../v2/{lookback_test.go => window_test.go} | 43 --- pkg/report/profit_report.go | 9 +- pkg/strategy/bollmaker/dynamic_spread.go | 8 +- pkg/strategy/bollmaker/strategy.go | 9 +- pkg/strategy/bollmaker/trend.go | 6 +- pkg/strategy/scmaker/strategy.go | 5 +- pkg/types/kline.go | 4 + pkg/types/series_float64.go | 16 + 117 files changed, 1601 insertions(+), 2884 deletions(-) create mode 100644 pkg/indicator/v2/bst/bst.go create mode 100644 pkg/indicator/v2/bst/bst_test.go create mode 100644 pkg/indicator/v2/bst/compare.go delete mode 100644 pkg/indicator/v2/ichimoku/builder.go delete mode 100644 pkg/indicator/v2/ichimoku/ichimoku.go delete mode 100644 pkg/indicator/v2/ichimoku/indicator.go delete mode 100644 pkg/indicator/v2/ichimoku/line-value.go delete mode 100644 pkg/indicator/v2/ichimoku/line_helper.go delete mode 100644 pkg/indicator/v2/ichimoku/status.go delete mode 100644 pkg/indicator/v2/ichimoku/types.go delete mode 100644 pkg/indicator/v2/ichimoku1/.vscode/launch.json delete mode 100644 pkg/indicator/v2/ichimoku1/README.md delete mode 100644 pkg/indicator/v2/ichimoku1/builder.go delete mode 100644 pkg/indicator/v2/ichimoku1/example/main.go delete mode 100644 pkg/indicator/v2/ichimoku1/images/demo.png delete mode 100644 pkg/indicator/v2/ichimoku1/indicator.go delete mode 100644 pkg/indicator/v2/ichimoku1/line-value.go delete mode 100644 pkg/indicator/v2/ichimoku1/line_helper.go delete mode 100644 pkg/indicator/v2/ichimoku1/status.go delete mode 100644 pkg/indicator/v2/ichimoku1/tests/analyse_test.go delete mode 100644 pkg/indicator/v2/ichimoku1/tests/cloud_test.go delete mode 100644 pkg/indicator/v2/ichimoku1/types.go delete mode 100644 pkg/indicator/v2/lookback.go create mode 100644 pkg/indicator/v2/maxval.go create mode 100644 pkg/indicator/v2/maxval_test.go create mode 100644 pkg/indicator/v2/minval.go create mode 100644 pkg/indicator/v2/minval_test.go create mode 100644 pkg/indicator/v2/momentum/awesome_osc_test.go create mode 100644 pkg/indicator/v2/momentum/awseome_osc.go create mode 100644 pkg/indicator/v2/momentum/chaikin_osc.go create mode 100644 pkg/indicator/v2/momentum/chaikin_osc_test.go rename pkg/indicator/v2/{ => momentum}/stoch.go (87%) rename pkg/indicator/v2/{ => momentum}/stoch_test.go (99%) rename pkg/indicator/v2/{ => momentum}/stochstream_callbacks.go (93%) create mode 100644 pkg/indicator/v2/momentum/williams_r.go create mode 100644 pkg/indicator/v2/momentum/williams_r_test.go delete mode 100644 pkg/indicator/v2/pattern/hammerstick.go delete mode 100644 pkg/indicator/v2/pattern/hammerstick_test.go create mode 100644 pkg/indicator/v2/pattern/head_shoulders.go create mode 100644 pkg/indicator/v2/pattern/head_shoulders_test.go create mode 100644 pkg/indicator/v2/squared_average.go delete mode 100644 pkg/indicator/v2/trend/aroon.go delete mode 100644 pkg/indicator/v2/trend/aroon_test.go rename pkg/indicator/v2/{ => trend}/cci.go (99%) rename pkg/indicator/v2/{ => trend}/cci_test.go (91%) create mode 100644 pkg/indicator/v2/volatility/chandelier_exit.go create mode 100644 pkg/indicator/v2/volatility/ulcer_index.go create mode 100644 pkg/indicator/v2/volatility/ulcer_index_test.go create mode 100644 pkg/indicator/v2/window.go rename pkg/indicator/v2/{lookback_test.go => window_test.go} (68%) diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index e4cf118096..a1697fefb5 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -6,6 +6,7 @@ import ( indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/indicator/v2/momentum" "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/indicator/v2/volatility" "github.com/c9s/bbgo/pkg/types" ) @@ -91,18 +92,18 @@ func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *indicatorv2. return indicatorv2.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) } -func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BOLLStream { - return indicatorv2.BOLL(i.CLOSE(iw.Interval), iw.Window, k) +func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *volatility.BOLLStream { + return volatility.BOLL(i.CLOSE(iw.Interval), iw.Window, k) } func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *trend.MACDStream { return trend.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) } -func (i *IndicatorSet) ATR(interval types.Interval, window int) *trend.ATRStream { - return trend.ATR2(i.KLines(interval), window) +func (i *IndicatorSet) ATR(interval types.Interval, window int) *volatility.ATRStream { + return volatility.ATR2(i.KLines(interval), window) } -func (i *IndicatorSet) ATRP(interval types.Interval, window int) *trend.ATRPStream { - return trend.ATRP2(i.KLines(interval), window) +func (i *IndicatorSet) ATRP(interval types.Interval, window int) *volatility.ATRPStream { + return volatility.ATRP2(i.KLines(interval), window) } diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go index 1d610a4f53..5a01a982ad 100644 --- a/pkg/datatype/floats/slice.go +++ b/pkg/datatype/floats/slice.go @@ -36,6 +36,18 @@ func (s Slice) Max() float64 { return floats.Max(s) } +func (s Slice) MaxIndex() int { + maxIdx := 0 + maxVal := s[0] + for i, val := range s { + if val > maxVal { + maxVal = val + maxIdx = i + } + } + return maxIdx +} + func (s Slice) Min() float64 { return floats.Min(s) } diff --git a/pkg/exchange/bitget/bitgetapi/types.go b/pkg/exchange/bitget/bitgetapi/types.go index 1aa6280f77..30442e13b0 100644 --- a/pkg/exchange/bitget/bitgetapi/types.go +++ b/pkg/exchange/bitget/bitgetapi/types.go @@ -14,6 +14,7 @@ const ( OrderTypeMarket OrderType = "market" ) +// OrderSide represents the side of an order: Buy (long) or Sell (short). type OrderSide string const ( diff --git a/pkg/indicator/v2/bst/bst.go b/pkg/indicator/v2/bst/bst.go new file mode 100644 index 0000000000..fbfc6fe8be --- /dev/null +++ b/pkg/indicator/v2/bst/bst.go @@ -0,0 +1,94 @@ +package bst + +// BST node. +type Node struct { + value interface{} + left *Node + right *Node +} + +// BST type. +type Tree struct { + root *Node +} + +// New binary search tree. +func New() *Tree { + return &Tree{} +} + +// Inserts the given value. +func (t *Tree) Insert(value interface{}) { + newNode := &Node{ + value: value, + } + + if t.root == nil { + t.root = newNode + return + } + + curNode := t.root + + for { + if Compare(newNode.value, curNode.value) <= 0 { + if curNode.left == nil { + curNode.left = newNode + return + } else { + curNode = curNode.left + } + } else { + if curNode.right == nil { + curNode.right = newNode + return + } else { + curNode = curNode.right + } + } + } +} + +// Removes the given value. +func (t *Tree) Remove(value interface{}) bool { + var parent *Node + node := t.root + + for node != nil { + switch Compare(value, node.value) { + case 0: + t.removeNode(parent, node) + return true + + case -1: + parent = node + node = node.left + + case 1: + parent = node + node = node.right + } + } + + return false +} + +// Min value. +func (t *Tree) Min() interface{} { + node, _ := minNode(t.root) + if node == nil { + return nil + } + + return node.value +} + +// Max value. +func (t *Tree) Max() interface{} { + node, _ := maxNode(t.root) + if node == nil { + return nil + } + + return node.value +} diff --git a/pkg/indicator/v2/bst/bst_test.go b/pkg/indicator/v2/bst/bst_test.go new file mode 100644 index 0000000000..6b5855fe6d --- /dev/null +++ b/pkg/indicator/v2/bst/bst_test.go @@ -0,0 +1,57 @@ +package bst + +import ( + "testing" +) + +func TestInsertAndRemove(t *testing.T) { + values := []float64{2, 1, 3, 4, 0, 6, 6, 10, -1, 9} + + tree := New() + + for _, value := range values { + tree.Insert(value) + } + + for _, value := range values { + if !tree.Remove(value) { + t.Fatalf("unable to remove %f", value) + } + } +} + +func TestMinAndMax(t *testing.T) { + values := []float64{2, 1, 3, 4, 0, 6, 6, 10, -1, 9} + mins := []float64{2, 1, 1, 1, 0, 0, 0, 0, -1, -1} + maxs := []float64{2, 2, 3, 4, 4, 6, 6, 10, 10, 10} + + tree := New() + + for i := 0; i < len(values); i++ { + tree.Insert(values[i]) + + min := tree.Min() + if min != mins[i] { + t.Fatalf("at %d actual %f expected %f", i, min, mins[i]) + } + + max := tree.Max() + if max != maxs[i] { + t.Fatalf("at %d actual %f expected %f", i, max, maxs[i]) + } + } + + for i := len(values) - 1; i > 0; i-- { + tree.Remove(values[i]) + + min := tree.Min() + if min != mins[i-1] { + t.Fatalf("at %d actual %f expected %f", i, min, mins[i-1]) + } + + max := tree.Max() + if max != maxs[i-1] { + t.Fatalf("at %d actual %f expected %f", i, max, maxs[i-1]) + } + } +} diff --git a/pkg/indicator/v2/bst/compare.go b/pkg/indicator/v2/bst/compare.go new file mode 100644 index 0000000000..5f3053cd2f --- /dev/null +++ b/pkg/indicator/v2/bst/compare.go @@ -0,0 +1,115 @@ +package bst + +// Comparable interface. +type Comparable interface { + // Compare with other value. Returns -1 if less than, 0 if + // equals, and 1 if greather than the other value. + Compare(other Comparable) int +} + +// Compares first and second values. The given values must be +// numeric or must implement Comparable interface. +// +// Returns -1 if less than, 0 if equals, 1 if greather than. +func Compare(first, second interface{}) int { + if _, ok := first.(Comparable); ok { + return first.(Comparable).Compare(second.(Comparable)) + } + + switch first.(type) { + + case float64: + return compareFloat64(first.(float64), second.(float64)) + + case int64: + return compareInt64(first.(int64), second.(int64)) + } + + panic("not comparable") +} + +func compareFloat64(first, second float64) int { + if first < second { + return -1 + } + + if first > second { + return 1 + } + + return 0 +} + +func compareInt64(first, second int64) int { + if first < second { + return -1 + } + + if first > second { + return 1 + } + + return 0 +} + +// Remove node. +func (t *Tree) removeNode(parent, node *Node) { + if node.left != nil && node.right != nil { + min, minParent := minNode(node.right) + if minParent == nil { + minParent = node + } + + t.removeNode(minParent, min) + node.value = min.value + } else { + var child *Node + if node.left != nil { + child = node.left + } else { + child = node.right + } + + if node == t.root { + t.root = child + } else if parent.left == node { + parent.left = child + } else { + parent.right = child + } + } +} + +// Min node. Returns min node and its parent. +func minNode(root *Node) (*Node, *Node) { + if root == nil { + return nil, nil + } + + var parent *Node + node := root + + for node.left != nil { + parent = node + node = node.left + } + + return node, parent +} + +// Max node. Returns max node and its parent. +func maxNode(root *Node) (*Node, *Node) { + if root == nil { + return nil, nil + } + + var parent *Node + node := root + + for node.right != nil { + parent = node + node = node.right + } + + return node, parent +} diff --git a/pkg/indicator/v2/ichimoku/builder.go b/pkg/indicator/v2/ichimoku/builder.go deleted file mode 100644 index c2c3953ba2..0000000000 --- a/pkg/indicator/v2/ichimoku/builder.go +++ /dev/null @@ -1,79 +0,0 @@ -package ichimoku - -import ( - "github.com/c9s/bbgo/pkg/types" -) - -func BuildIchimokuStatus(bars []types.KLine) (*IchimokuStatus, error) { - if len(bars) == 0 { - return nil, ErrDataNotFill - } - - if len(bars) < 52 { - return nil, ErrNotEnoughData - } - - tenkenLine := calcLine(Line_Tenkan_sen, bars) - kijonLine := calcLine(Line_kijon_sen, bars) - - span_a := calculate_span_a(tenkenLine, kijonLine) - span_b := calcLine(Line_spanPeriod, bars) - chiko_index := (len(bars) - int(Line_chikoPeriod)) - 1 - cheko_span := bars[chiko_index] - - var latestPrice types.KLine - latestPriceIndex := (len(bars) - 1) - if (len(bars) - 1) >= latestPriceIndex { - latestPrice = bars[latestPriceIndex] - } - - if !tenkenLine.isNil && !kijonLine.isNil && !span_a.isNil && !span_b.isNil { - ichi := NewIchimokuStatus(tenkenLine, kijonLine, span_a, span_b, cheko_span, latestPrice) - return ichi, nil - } - - return nil, ErrBuildFailed -} - -func calcLine(line_type ELine, bars []types.KLine) ValueLine { - high := NewValueLineNil() - low := NewValueLineNil() - l := len(bars) - from := l - 1 - int(line_type) - if from == -1 { - from = 0 - } - bars_tmp := bars[from : l-1] - if len(bars) < int(line_type) { - return NewValueLineNil() - } - for _, v := range bars_tmp { - - if high.isNil { - high.SetValue(v.High) - } - if low.isNil { - low.SetValue(v.Low) - } - - if v.High > high.valLine { - high.SetValue(v.High) - } - - if v.Low < low.valLine { - low.SetValue(v.Low) - } - - } - line := low.valLine + (high.valLine / 2) - return NewValue(line) -} - -func calculate_span_a(tenken ValueLine, kijon ValueLine) ValueLine { - if !tenken.isNil && !kijon.isNil { - v := tenken.valLine + (kijon.valLine / 2) - return NewValue(v) - } - - return NewValueLineNil() -} diff --git a/pkg/indicator/v2/ichimoku/ichimoku.go b/pkg/indicator/v2/ichimoku/ichimoku.go deleted file mode 100644 index 698bd01d55..0000000000 --- a/pkg/indicator/v2/ichimoku/ichimoku.go +++ /dev/null @@ -1,220 +0,0 @@ -package ichimoku - -import ( - "github.com/algo-boyz/decimal" - "github.com/thecolngroup/gou/dec" - - "github.com/c9s/bbgo/pkg/types" -) - -// type IIchimokuIndicator interface { -// // out result array sort: [new day -to- old day] -// // one call per asset -// MakeIchimokuInPast(bars []types.KLine, numberOfRead int) error - -// //one call per asset -// PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) - -// //Analyse Trigger Cross tenken & kijon sen -// AnalyseTriggerCross(previous *IchimokuStatus, bars_only_25_bars_latest []types.KLine) (*IchimokuStatus, error) - -// GetLast() *IchimokuStatus -// GetList() []*IchimokuStatus -// } - -func (s *IchimokuStream) GetList() []*IchimokuStatus { - return s.Ichimokus -} - -// analyse with two days -func (s *IchimokuStream) FindStatusin26BarPast() { - - for i := 0; i < s.NumberOfIchimokus(); i++ { - item := s.Ichimokus[i] - sen_a, sen_b := s.calc_Cloud_InPast(i) - item.Set_SenCo_A_Past(sen_a) - item.Set_SenCo_B_Past(sen_b) - } - -} - -// Analyse Trigger Cross tenken & kijon sen -// bars : contain with new bar -func (s *IchimokuStream) AnalyseTriggerCross(previous *IchimokuStatus, _52_bars_latest []types.KLine) (*IchimokuStatus, error) { - - if len(_52_bars_latest) == 0 { - return nil, ErrDataNotFill - } - - if len(_52_bars_latest) < 52 { - return nil, ErrNotEnoughData - } - - newIchi, e := BuildIchimokuStatus(_52_bars_latest) - - if e != nil { - return nil, e - } - sen_a_in_26_past, sen_b_in_26_past := s.calc_Cloud_InPast(0) - - if sen_a_in_26_past.isNil || sen_b_in_26_past.isNil { - return nil, ErrChikoStatus26InPastNotMade - } - - newIchi.Set_SenCo_A_Past(sen_a_in_26_past) - newIchi.Set_SenCo_B_Past(sen_b_in_26_past) - - if newIchi.SencoA_Past.isNil || newIchi.SencoB_Past.isNil { - return nil, ErrChikoStatus26InPastNotMade - } - - if !newIchi.bar.StartTime.After(previous.bar.StartTime.Time()) { - return nil, ErrDateNotGreaterThanPrevious - } - has_collision1, intersection := s.CrossCheck(previous, newIchi) - if has_collision1 == EInterSectionStatus_Find { - newIchi.SetStatus(newIchi.CloudStatus(intersection)) - newIchi.SetCloudSwitching(s.isSwitchCloud(previous, newIchi)) - - return newIchi, nil - } - return nil, nil - -} - -// analyse with two days -func (s *IchimokuStream) PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) { - - if len(data) != 2 { - return nil, ErrNotEnoughData - } - - current := data[0] - previous := data[1] - - line1_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.TenkenSen.valLine) - line1_point_b := NewPoint(dec.New(current.bar.StartTime.Unix()), current.TenkenSen.valLine) - - line2_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.KijonSen.valLine) - line2_point_b := NewPoint(dec.New(current.bar.StartTime.Unix()), current.KijonSen.valLine) - - has_collision1, intersection := s.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) - - if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { - return nil, nil - } - - Line_Eq_A := s.getLineEquation(line1_point_a, line1_point_b) // tenken - Line_Eq_B := s.getLineEquation(line2_point_a, line2_point_b) //kijon - - if line1_point_a == line2_point_a { - return nil, nil //paraller - - } - - if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { - return nil, nil - - } - - if has_collision1 == EInterSectionStatus_Find { - - current.SetStatus(current.CloudStatus(intersection)) - - current.SetCloudSwitching(o.isSwitchCloud(previous, current)) - return current, nil - } - return nil, nil -} - -func (s *IchimokuStream) NumberOfIchimokus() int { - return len(s.Ichimokus) -} - -func (s *IchimokuStream) GetLast() *IchimokuStatus { - - if s.Ichimokus != nil && len(s.Ichimokus) == 0 { - return nil - } - - latest := s.Ichimokus[0] - - return latest -} - -func (s *IchimokuStream) Put(v *IchimokuStatus) { - o.Ichimokus = append(o.Ichimokus, v) -} - -// -------------------------------------------------------------------------------------------------------- -func (s *IchimokuStream) CrossCheck(previous, newIchi *IchimokuStatus) (EInterSectionStatus, decimal.Decimal) { - line1_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.TenkenSen.valLine) - line1_point_b := NewPoint(dec.New(newIchi.bar.StartTime.Unix()), newIchi.TenkenSen.valLine) - - line2_point_a := NewPoint(dec.New(previous.bar.StartTime.Unix()), previous.KijonSen.valLine) - line2_point_b := NewPoint(dec.New(newIchi.bar.StartTime.Unix()), newIchi.KijonSen.valLine) - - has_collision1, intersection := s.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) - - if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { - return EInterSectionStatus_NAN, decimal.Zero - } - - Line_Eq_A := s.getLineEquation(line1_point_a, line1_point_b) // tenken - Line_Eq_B := s.getLineEquation(line2_point_a, line2_point_b) //kijon - - if line1_point_a == line2_point_a { - return EInterSectionStatus_NAN, intersection //paraller - - } - - if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { - return EInterSectionStatus_NAN, intersection - - } - return has_collision1, intersection -} - -// analyse with two days -func (s *IchimokuStream) isSwitchCloud(previous, current *IchimokuStatus) bool { - - if previous.SenKoA_Shifted26.valLine >= previous.SenKoB_Shifted26.valLine && - current.SenKoA_Shifted26.valLine > current.SenKoB_Shifted26.valLine || - previous.SenKoA_Shifted26.valLine < previous.SenKoB_Shifted26.valLine && - current.SenKoA_Shifted26.valLine >= current.SenKoB_Shifted26.valLine { - if current.TenkenSen.valLine >= current.KijonSen.valLine { - return true - } - } - return false -} - -// find cloud Span A,B in Past (26 day ) -func (s *IchimokuStream) calc_Cloud_InPast(current int) (Point, Point) { - - if s.NumberOfIchimokus() < 26 { - return NewNilPoint(), NewNilPoint() - } - - rem := s.NumberOfIchimokus() - current - max := 26 //from 26 bar in past (find Shift index) - - if rem < max { - return NewNilPoint(), NewNilPoint() - } - - index := current + 25 - c := s.Ichimokus[index] - buff_senco_a := NewPoint(dec.New(c.bar.StartTime.Unix()/1000), c.SenKoA_Shifted26.valLine) - buff_senco_b := NewPoint(dec.New(c.bar.StartTime.Unix()/1000), c.SenKoB_Shifted26.valLine) - - return buff_senco_a, buff_senco_b -} - -func (s *IchimokuStream) getLineEquation(p1 Point, p2 Point) *Equation { - eq := Equation{} - eq.Slope = (p2.Y.Sub(p1.Y)).Mul(p2.X.Sub(p1.X)) - //eq.Intercept = (-1 * eq.Slope * p1.X) + p1.Y - eq.Intercept = p1.Y.Sub(eq.Slope).Mul(p1.X) - return &eq -} diff --git a/pkg/indicator/v2/ichimoku/indicator.go b/pkg/indicator/v2/ichimoku/indicator.go deleted file mode 100644 index 11190fbc8d..0000000000 --- a/pkg/indicator/v2/ichimoku/indicator.go +++ /dev/null @@ -1,77 +0,0 @@ -package ichimoku - -import ( - "fmt" - - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/types" -) - -type IchimokuStream struct { - *types.KLineSeries - line_helper lineHelper - Ichimokus []*IchimokuStatus - ConversionLine *types.Float64Series - BaseLine *types.Float64Series - LeadingSpanA *types.Float64Series - LeadingSpanB *types.Float64Series - laggingSpan *types.Float64Series - window int -} - -func Ichimoku(source v2.KLineSubscription, window int) *IchimokuStream { - s := &IchimokuStream{ - KLineSeries: v2.KlineSeries(), - window: window, - } - s.Bind(source, s) - return s -} - -func (s *IchimokuStream) Calculate(v float64) float64 { - bars_len := s.Length() - - if bars_len < numberOfRead || bars_len < 52 { - return ErrNotEnoughData - } - - fmt.Printf("Calc ichi from Last %v days on %d total candles\r\n", numberOfRead, len(series)) - - // descending - for day := 0; day < numberOfRead; day++ { - - from := bars_len - 52 - day - to := bars_len - day - - ic, err := BuildIchimokuStatus(s.loadbars(from, to)) - if err != nil { - return err - } - s.Put(ic) - - } - - for day_index := 0; day_index < s.NumberOfIchimokus(); day_index++ { - item := s.Ichimokus[day_index] - sen_a, sen_b := s.Calc_Cloud_InPast(day_index) - item.Set_SenCo_A_Past(sen_a) - item.Set_SenCo_B_Past(sen_b) - } - - return sma -} - -func (s *IchimokuStream) loadbars(from int, to int) []types.KLine { - if s.Length() == 0 { - return nil - } - if from < 0 { - from = 0 - } - if to > s.Length() { - to = s.Length() - } - - return s.Last(0) // (from:to) - -} diff --git a/pkg/indicator/v2/ichimoku/line-value.go b/pkg/indicator/v2/ichimoku/line-value.go deleted file mode 100644 index 720e609daf..0000000000 --- a/pkg/indicator/v2/ichimoku/line-value.go +++ /dev/null @@ -1,30 +0,0 @@ -package ichimoku - -import ( - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -type ValueLine struct { - valLine fixedpoint.Value - isNil bool -} - -func (n *ValueLine) Value() interface{} { - if n.isNil { - return nil - } - return n.valLine -} - -func (n *ValueLine) SetValue(v fixedpoint.Value) { - n.valLine = v - n.isNil = false -} - -func NewValue(x fixedpoint.Value) ValueLine { - return ValueLine{x, false} -} - -func NewValueLineNil() ValueLine { - return ValueLine{fixedpoint.Zero, true} -} diff --git a/pkg/indicator/v2/ichimoku/line_helper.go b/pkg/indicator/v2/ichimoku/line_helper.go deleted file mode 100644 index 2833d91709..0000000000 --- a/pkg/indicator/v2/ichimoku/line_helper.go +++ /dev/null @@ -1,159 +0,0 @@ -package ichimoku - -import ( - "fmt" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -type lineHelper struct { -} -type EPointLocation int - -const ( - EPointLocation_NAN EPointLocation = 0 - EPointLocation_above EPointLocation = 1 - EPointLocation_below EPointLocation = 2 - EPointLocation_overlap EPointLocation = 3 -) - -func NewLineHelper() lineHelper { - f := lineHelper{} - return f -} - -// check Point above or below line -func (n *lineHelper) isAboveLine(point Point, line []Point) EPointLocation { - zero := fixedpoint.Zero - if len(line) < 2 { - return EPointLocation_NAN - } - - checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) EPointLocation { - //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) - // v := (p.X-line_p_a.X)*(line_p_b.Y-line_p_a.Y) - (p.Y-line_p_a.Y)*(line_p_b.X-line_p_a.X) - yOverX := p.Y.Sub(line_p_a.Y).Mul(line_p_b.X.Sub(line_p_a.X)) - xOverY := p.X.Sub(line_p_a.X).Mul(line_p_b.Y.Sub(line_p_a.Y)) - v := xOverY.Sub(yOverX) - - if v.Compare(zero) == 0 { - return EPointLocation_overlap - } else if v > zero { - return EPointLocation_above - } else { - return EPointLocation_below - } - } - - return checkAboveOrBelow(point, line[0], line[1]) - -} - -func (n *lineHelper) positionPointInline(point Point, line []Point) fixedpoint.Value { - zero := fixedpoint.Zero - - if len(line) < 2 { - return zero - } - - checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) fixedpoint.Value { - //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) - return (p.X.Sub(line_p_a.X)).Mul(line_p_b.Y.Sub(line_p_a.Y)).Sub(p.Y.Sub(line_p_a.Y)).Mul(line_p_b.X.Sub(line_p_a.X)) - } - - res := checkAboveOrBelow(point, line[0], line[1]) - - return res - -} - -func (o *lineHelper) GetCollisionDetection(a Point, b Point, c Point, d Point) (EInterSectionStatus, fixedpoint.Value) { - - denominator := ((b.X.Sub(a.X)).Mul(d.Y.Sub(c.Y))).Sub((b.Y.Sub(a.Y)).Mul(d.X.Sub(c.X))) - numerator1 := ((a.Y.Sub(c.Y)).Mul(d.X.Sub(c.X))).Sub((a.X.Sub(c.X)).Mul(d.Y.Sub(c.Y))) - numerator2 := ((a.Y.Sub(c.Y)).Mul(b.X.Sub(a.X))).Sub((a.X.Sub(c.X)).Mul(b.Y.Sub(a.Y))) - - // Detect coincident lines (has a problem, read below) - if denominator.Compare(fixedpoint.Zero) == 0 { - return EInterSectionStatus_NAN, fixedpoint.Zero - } - r := numerator1.Div(denominator) - s := numerator2.Div(denominator) - zero := fixedpoint.Zero - one := fixedpoint.One - if r >= zero && r <= one && - s >= zero && s <= one { - // fmt.Printf("collision detec : a:%v , b:%v, c:%v ,d:%v ,r %v s %v\r\n", a, b, c, d, r, s) - intersection := o.get_intersection_point(a, b, c, d) - - return EInterSectionStatus_Collision_Find, intersection - } - return EInterSectionStatus_NAN, fixedpoint.Zero -} - -//line senco A or B -func (o *lineHelper) GetCollisionWithLine(price_point Point, line_clouds []Point) (EPointLocation, error) { - zero := fixedpoint.Zero - - len_line_clouds := len(line_clouds) - if len_line_clouds < 1 { - return EPointLocation_NAN, ErrNotEnoughData - } - // Create a point at infinity, y is same as point p - //x := time.Now().AddDate(0, -1, 0).Unix() - //line1_a := NewPoint(decimal.NewFromInt(x), price_point.Y) - // line1_b := price_point - // line_b := NewPoint(0,price_point) - //var ps EPointLocation = EPointLocation_NaN - below := 0 - above := 0 - fmt.Println("___") - fmt.Printf("Cloud : check point :x:%.0f y:%.0f \r\n", price_point.X.Float64(), price_point.Y.Float64()) - sum := fixedpoint.Zero - for i := 1; i < len_line_clouds; i++ { - line2_a := line_clouds[i-1] - line2_b := line_clouds[i] - //fmt.Printf("Cloud :x:%.0f y:%.0f ,\r\n", line2_a.X, line2_a.Y) - fmt.Printf("%.0f,%.0f,\r\n", line2_a.X.Float64(), line2_a.Y.Float64()) - //res := o.GetCollisionDetection(line1_a, line1_b, line2_a, line2_b) - buff := []Point{line2_a, line2_b} - // res := o.isAboveLine(price_point, buff) - c := o.positionPointInline(price_point, buff) - if c > zero { //below - below++ - } else { - above++ - } - - sum = sum.Add(c) - - } - v := sum.Div(fixedpoint.NewFromInt(int64(len_line_clouds))) - - if v > zero { - return EPointLocation_below, nil // above - } else { - return EPointLocation_above, nil //below - } - -} -func (o *lineHelper) getLineEquation(p1 Point, p2 Point) *Equation { - eq := Equation{} - x := p1.X.Sub(p2.X) - y := p1.Y.Sub(p2.Y) - eq.Slope = y.Div(x) - eq.Intercept = fixedpoint.One.Neg().Mul(eq.Slope).Mul(p1.X).Add(p1.Y) - return &eq -} - -func (o *lineHelper) get_intersection_point(line1_pointA Point, line1_pointB Point, line2_pointA Point, line2_pointB Point) fixedpoint.Value { - - tenken := o.getLineEquation(line1_pointA, line1_pointB) - kijon := o.getLineEquation(line2_pointA, line2_pointB) - intercept := kijon.Intercept.Sub(tenken.Intercept) - slope := tenken.Slope.Sub(kijon.Slope) - x_intersection := intercept.Div(slope) - x := kijon.Slope.Mul(x_intersection) - y_intersection := x.Add(kijon.Intercept) - return y_intersection -} diff --git a/pkg/indicator/v2/ichimoku/status.go b/pkg/indicator/v2/ichimoku/status.go deleted file mode 100644 index 8474f38383..0000000000 --- a/pkg/indicator/v2/ichimoku/status.go +++ /dev/null @@ -1,150 +0,0 @@ -package ichimoku - -import ( - "fmt" - "time" - - "github.com/algo-boyz/alphakit/market" - decimal "github.com/algo-boyz/decimal128" - - "github.com/c9s/bbgo/pkg/types" -) - -type IchimokuStatus struct { - TenkenSen ValueLine - - //_______________ - - KijonSen ValueLine - - //in the future - SenKoA_Shifted26 ValueLine - - //in the future - SenKoB_Shifted26 ValueLine - - //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) - //SencoA 26 candle in the past (for check) - SencoA_Past Point - //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) - //SencoB 26 candle in the past (for check) - SencoB_Past Point - - ChikoSpan *types.KLine //close bar - - bar *types.KLine - //----- - Status EIchimokuStatus - cloudSwitching bool - - line_helper lineHelper -} - -func NewIchimokuStatus(tenken ValueLine, kijon ValueLine, senKoA_Shifted26 ValueLine, senKoB_Shifted52 ValueLine, chiko_span, bar *market.Kline) *IchimokuStatus { - - o := IchimokuStatus{} - - o.TenkenSen = tenken - - o.KijonSen = kijon - - o.SenKoA_Shifted26 = senKoA_Shifted26 - o.SenKoB_Shifted26 = senKoB_Shifted52 - - o.ChikoSpan = chiko_span - o.bar = bar - o.Status = IchimokuStatus_NAN - o.line_helper = NewLineHelper() - - return &o -} - -func (o *IchimokuStatus) SetChikoSpan(v *market.Kline) { - o.ChikoSpan = v -} - -func (o *IchimokuStatus) Set_SenCo_A_Past(p Point) { - o.SencoA_Past = p -} - -func (o *IchimokuStatus) Set_SenCo_B_Past(p Point) { - o.SencoB_Past = p -} - -func (o *IchimokuStatus) SetStatus(status EIchimokuStatus) { - o.Status = status -} - -func (o *IchimokuStatus) GetStatus() EIchimokuStatus { - return o.Status -} - -func (o *IchimokuStatus) SetCloudSwitching(v bool) { - o.cloudSwitching = v -} - -func (o *IchimokuStatus) GetCloudSwitching() bool { - return o.cloudSwitching -} - -func (o *IchimokuStatus) Is_cloud_green() bool { - return o.SenKoA_Shifted26.valLine > o.SenKoB_Shifted26.valLine -} - -func (o *IchimokuStatus) IsChikoAbovePrice() bool { - return o.ChikoSpan.High > o.bar.Close -} - -func (o *IchimokuStatus) CloudStatus(intersection decimal.Decimal) EIchimokuStatus { - if o.SenKoA_Shifted26.isNil || o.SenKoB_Shifted26.isNil { - return IchimokuStatus_NAN - } - if o.SencoA_Past.isNil || o.SencoB_Past.isNil { - return IchimokuStatus_NAN - } - - sen_B := o.SencoB_Past //Senko B in_26_candle_pass - sen_A := o.SencoA_Past //Senko A in_26_candle_pass - if sen_A.Y > intersection && sen_B.Y > intersection { - return IchimokuStatus_Cross_Below - } else if sen_A.Y < intersection && sen_B.Y < intersection { - return IchimokuStatus_Cross_Above - } else if sen_A.Y < intersection && sen_B.Y > intersection || sen_A.Y > intersection && sen_B.Y < intersection { - return IchimokuStatus_Cross_Inside - } - - return IchimokuStatus_NAN - -} - -func (o *IchimokuStatus) GetStatusString() string { - result := "" - switch o.Status { - case IchimokuStatus_NAN: - result = "nan" - - case IchimokuStatus_Cross_Below: - result = "cross below" - case IchimokuStatus_Cross_Above: - result = "cross above" - case IchimokuStatus_Cross_Inside: - result = "cross inside" - } - - return result -} - -func (o *IchimokuStatus) Print() string { - return fmt.Sprintf("ichimoku cloud %v|%v|%v|%v|%v| Green: %v, Chiko UP: %v | status: %v | %v\n", - o.TenkenSen.Value(), - o.KijonSen.Value(), - o.SenKoA_Shifted26.Value(), - o.SenKoB_Shifted26.Value(), - o.ChikoSpan.Close, - o.Is_cloud_green(), - o.IsChikoAbovePrice(), - o.GetStatusString(), - o.bar.StartTime.Time().Format(time.DateTime), - ) - -} diff --git a/pkg/indicator/v2/ichimoku/types.go b/pkg/indicator/v2/ichimoku/types.go deleted file mode 100644 index 97e7171e08..0000000000 --- a/pkg/indicator/v2/ichimoku/types.go +++ /dev/null @@ -1,70 +0,0 @@ -package ichimoku - -import ( - "errors" - - decimal "github.com/algo-boyz/decimal128" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -var ( - ErrBuildFailed = errors.New("build failed") - ErrNotEnoughData = errors.New("not enough data") - ErrDataNotFill = errors.New("data not fill") - ErrChikoStatus26InPastNotMade = errors.New("chiko status 26 in past not reached") - ErrDateNotGreaterThanPrevious = errors.New("date is not greater than previous") -) - -type Point struct { - X, Y fixedpoint.Value - isNil bool -} - -func NewPoint(x, y fixedpoint.Value) Point { - p := Point{} - p.X = x - p.Y = y - p.isNil = false - return p -} -func NewNilPoint() Point { - p := Point{} - p.X = fixedpoint.NewFromInt(-1) - p.Y = fixedpoint.NewFromInt(-1) - p.isNil = true - return p -} - -type Equation struct { - Slope decimal.Decimal - Intercept decimal.Decimal -} - -type EInterSectionStatus int - -const ( - EInterSectionStatus_NAN EInterSectionStatus = 0 - EInterSectionStatus_Find EInterSectionStatus = 1 - EInterSectionStatus_Parallel EInterSectionStatus = 2 - EInterSectionStatus_Collision_Find EInterSectionStatus = 1 -) - -type ELine int - -const ( - Line_Tenkan_sen ELine = 9 - Line_kijon_sen ELine = 26 - Line_spanPeriod ELine = 52 - Line_chikoPeriod ELine = 26 //-26 -) - -type EIchimokuStatus int - -const ( - IchimokuStatus_NAN EIchimokuStatus = 0 - IchimokuStatus_Cross_Inside EIchimokuStatus = 1 - IchimokuStatus_Cross_Below EIchimokuStatus = 2 - IchimokuStatus_Cross_Above EIchimokuStatus = 3 - IchimokuStatus_overLab EIchimokuStatus = 4 -) diff --git a/pkg/indicator/v2/ichimoku1/.vscode/launch.json b/pkg/indicator/v2/ichimoku1/.vscode/launch.json deleted file mode 100644 index 3e7cd5fe07..0000000000 --- a/pkg/indicator/v2/ichimoku1/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Package", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "example/main.go" - } - ] -} \ No newline at end of file diff --git a/pkg/indicator/v2/ichimoku1/README.md b/pkg/indicator/v2/ichimoku1/README.md deleted file mode 100644 index 7e9bcf04db..0000000000 --- a/pkg/indicator/v2/ichimoku1/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# (Ichimoku indicator)[https://www.investopedia.com/terms/i/ichimoku-cloud.asp] - -- (Intersection Point Of Two Lines)[https://web.archive.org/web/20060911055655/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d] - -## Calculation - -``` -There are five plots that make up the Ichimoku Cloud indicator. Their names and calculations are: - -TenkanSen (Conversion Line): (High + Low) / 2 default period = 9 -KijunSen (Base Line): (High + Low) / 2 default period = 26 -Chiku Span (Lagging Span): Price Close shifted back 26 bars -Senkou A (Leading Span A): (TenkanSen + KijunSen) / 2 (Senkou A is shifted forward 26 bars) -Senkou B (Leading Span B): (High + Low) / 2 using period = 52 (Senkou B is shifted forward 26 bars) -``` - -![alt text](images/demo.png) - -```console -➜ Ichimoku git:(main) ✗ go run example/main.go - -Calc ichi from Last 135 days -____ - Find ichi 8705|8710|8707.5|8930|8870|G:false,Chiko UP :true |status : nan |2022 Sun Oct 2 10:30:00 |1664699400000 -.____ - Find ichi 8630|8630|8630|8710|8430|G:false,Chiko UP :false |status : cross below |2022 Tue Oct 11 08:30:00 |1665469800000 -.____ - Find ichi 8685|8690|8687.5|8695|8550|G:false,Chiko UP :false |status : cross inside |2022 Tue Oct 18 08:30:00 |1666074600000 -.____ - Find ichi 8135|8135|8135|8295|8450|G:false,Chiko UP :true |status : cross below |2022 Tue Nov 1 07:30:00 |1667284200000 -.____ - Find ichi 9485|9525|9505|8790|9430|G:true,Chiko UP :false |status : cross above |2022 Tue Nov 15 08:30:00 |1668497400000 -.____ - Find ichi 9570|9545|9557.5|8980|9470|G:true,Chiko UP :false |status : cross above |2022 Wed Nov 16 09:30:00 |1668587400000 -.190 -``` \ No newline at end of file diff --git a/pkg/indicator/v2/ichimoku1/builder.go b/pkg/indicator/v2/ichimoku1/builder.go deleted file mode 100644 index a36e331245..0000000000 --- a/pkg/indicator/v2/ichimoku1/builder.go +++ /dev/null @@ -1,81 +0,0 @@ -package ichimoku - -import ( - "github.com/algo-boyz/alphakit/market" - - "github.com/algo-boyz/alphakit/ta/dec" -) - -func BuildIchimokuStatus(bars []*market.Kline) (*IchimokuStatus, error) { - if len(bars) == 0 { - return nil, ErrDataNotFill - } - - if len(bars) < 52 { - return nil, ErrNotEnoughData - } - - tenkenLine := calcLine(Line_Tenkan_sen, bars) - kijonLine := calcLine(Line_kijon_sen, bars) - - span_a := calculate_span_a(tenkenLine, kijonLine) - span_b := calcLine(Line_spanPeriod, bars) - chiko_index := (len(bars) - int(Line_chikoPeriod)) - 1 - cheko_span := bars[chiko_index] - - var latestPrice *market.Kline - latestPriceIndex := (len(bars) - 1) - if (len(bars) - 1) >= latestPriceIndex { - latestPrice = bars[latestPriceIndex] - } - - if !tenkenLine.isNil && !kijonLine.isNil && !span_a.isNil && !span_b.isNil { - ichi := NewIchimokuStatus(tenkenLine, kijonLine, span_a, span_b, cheko_span, latestPrice) - return ichi, nil - } - - return nil, ErrBuildFailed -} - -func calcLine(line_type ELine, bars []*market.Kline) ValueLine { - high := NewValueLineNil() - low := NewValueLineNil() - l := len(bars) - from := l - 1 - int(line_type) - if from == -1 { - from = 0 - } - bars_tmp := bars[from : l-1] - if len(bars) < int(line_type) { - return NewValueLineNil() - } - for _, v := range bars_tmp { - - if high.isNil { - high.SetValue(v.H) - } - if low.isNil { - low.SetValue(v.L) - } - - if v.H.GreaterThan(high.valLine) { - high.SetValue(v.H) - } - - if v.L.LessThan(low.valLine) { - low.SetValue(v.L) - } - - } - line := low.valLine.Add(high.valLine).Quo(dec.New(2)) - return NewValue(line) -} - -func calculate_span_a(tenken ValueLine, kijon ValueLine) ValueLine { - if !tenken.isNil && !kijon.isNil { - v := tenken.valLine.Add(kijon.valLine).Quo(dec.New(2)) - return NewValue(v) - } - - return NewValueLineNil() -} diff --git a/pkg/indicator/v2/ichimoku1/example/main.go b/pkg/indicator/v2/ichimoku1/example/main.go deleted file mode 100644 index a8dfc19898..0000000000 --- a/pkg/indicator/v2/ichimoku1/example/main.go +++ /dev/null @@ -1,242 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "github.com/algo-boyz/alphakit/market" - decimal "github.com/algo-boyz/decimal128" - - "github.com/algo-boyz/alphakit/ta/dec" - "github.com/algo-boyz/alphakit/ta/ichimoku" -) - -var interval = time.Minute * 30 - -func d(v float64) decimal.Decimal { - return dec.New(v) -} - -func p(v int64) time.Time { - return time.UnixMilli(v).UTC() -} - -func main() { - - // sort ts [old date to new date] ascending - ts := []*market.Kline{ - {L: d(9450.00), H: d(9570.00), C: d(9490.00), O: d(9530.00), Volume: d(1158096.00), Start: p(1662525000000)}, - {L: d(9450.00), H: d(9550.00), C: d(9480.00), O: d(9530.00), Volume: d(1041077.00), Start: p(1662528600000)}, - {L: d(9420.00), H: d(9520.00), C: d(9500.00), O: d(9500.00), Volume: d(1966815.00), Start: p(1662532200000)}, - {L: d(9480.00), H: d(9520.00), C: d(9510.00), O: d(9480.00), Volume: d(748430.00), Start: p(1662535800000)}, - {L: d(9250.00), H: d(9500.00), C: d(9390.00), O: d(9500.00), Volume: d(1961310.00), Start: p(1662784200000)}, - {L: d(9340.00), H: d(9570.00), C: d(9520.00), O: d(9350.00), Volume: d(1881148.00), Start: p(1662787800000)}, - {L: d(9300.00), H: d(9520.00), C: d(9320.00), O: d(9520.00), Volume: d(2174744.00), Start: p(1662791400000)}, - {L: d(9320.00), H: d(9440.00), C: d(9440.00), O: d(9320.00), Volume: d(428193.00), Start: p(1662795000000)}, - {L: d(9280.00), H: d(9500.00), C: d(9470.00), O: d(9440.00), Volume: d(1174617.00), Start: p(1662870600000)}, - {L: d(9300.00), H: d(9490.00), C: d(9330.00), O: d(9480.00), Volume: d(564590.00), Start: p(1662874200000)}, - {L: d(9260.00), H: d(9360.00), C: d(9300.00), O: d(9330.00), Volume: d(1325195.00), Start: p(1662877800000)}, - {L: d(9280.00), H: d(9360.00), C: d(9360.00), O: d(9290.00), Volume: d(725716.00), Start: p(1662881400000)}, - {L: d(9290.00), H: d(9470.00), C: d(9310.00), O: d(9310.00), Volume: d(1156762.00), Start: p(1662957000000)}, - {L: d(9210.00), H: d(9330.00), C: d(9250.00), O: d(9310.00), Volume: d(1463096.00), Start: p(1662960600000)}, - {L: d(9240.00), H: d(9440.00), C: d(9380.00), O: d(9240.00), Volume: d(1350073.00), Start: p(1662964200000)}, - {L: d(9360.00), H: d(9400.00), C: d(9390.00), O: d(9380.00), Volume: d(526677.00), Start: p(1662967800000)}, - {L: d(9260.00), H: d(9450.00), C: d(9280.00), O: d(9300.00), Volume: d(685445.00), Start: p(1663043400000)}, - {L: d(9270.00), H: d(9450.00), C: d(9440.00), O: d(9280.00), Volume: d(957947.00), Start: p(1663047000000)}, - {L: d(9340.00), H: d(9440.00), C: d(9340.00), O: d(9440.00), Volume: d(716902.00), Start: p(1663050600000)}, - {L: d(9300.00), H: d(9380.00), C: d(9380.00), O: d(9350.00), Volume: d(860525.00), Start: p(1663054200000)}, - {L: d(9230.00), H: d(9360.00), C: d(9250.00), O: d(9300.00), Volume: d(1844161.00), Start: p(1663129800000)}, - {L: d(9230.00), H: d(9290.00), C: d(9240.00), O: d(9250.00), Volume: d(876713.00), Start: p(1663133400000)}, - {L: d(9210.00), H: d(9280.00), C: d(9260.00), O: d(9240.00), Volume: d(909086.00), Start: p(1663137000000)}, - {L: d(9200.00), H: d(9270.00), C: d(9240.00), O: d(9260.00), Volume: d(1347750.00), Start: p(1663140600000)}, - {L: d(9060.00), H: d(9240.00), C: d(9100.00), O: d(9240.00), Volume: d(1513067.00), Start: p(1663475400000)}, - {L: d(9060.00), H: d(9150.00), C: d(9080.00), O: d(9080.00), Volume: d(1770320.00), Start: p(1663479000000)}, - {L: d(8950.00), H: d(9100.00), C: d(8970.00), O: d(9080.00), Volume: d(2172300.00), Start: p(1663482600000)}, - {L: d(8950.00), H: d(9120.00), C: d(9070.00), O: d(8980.00), Volume: d(2417598.00), Start: p(1663486200000)}, - {L: d(8960.00), H: d(9160.00), C: d(9040.00), O: d(8960.00), Volume: d(1154404.00), Start: p(1663561800000)}, - {L: d(8980.00), H: d(9070.00), C: d(8990.00), O: d(9040.00), Volume: d(544846.00), Start: p(1663565400000)}, - {L: d(8930.00), H: d(9020.00), C: d(8960.00), O: d(8990.00), Volume: d(901781.00), Start: p(1663569000000)}, - {L: d(8910.00), H: d(8970.00), C: d(8920.00), O: d(8970.00), Volume: d(1021775.00), Start: p(1663572600000)}, - {L: d(8900.00), H: d(9060.00), C: d(8960.00), O: d(8900.00), Volume: d(1163197.00), Start: p(1663648200000)}, - {L: d(8860.00), H: d(9000.00), C: d(8870.00), O: d(8950.00), Volume: d(932584.00), Start: p(1663651800000)}, - {L: d(8820.00), H: d(8880.00), C: d(8830.00), O: d(8880.00), Volume: d(1458995.00), Start: p(1663655400000)}, - {L: d(8840.00), H: d(8880.00), C: d(8880.00), O: d(8840.00), Volume: d(462403.00), Start: p(1663659000000)}, - {L: d(8800.00), H: d(8900.00), C: d(8820.00), O: d(8810.00), Volume: d(787614.00), Start: p(1663734600000)}, - {L: d(8800.00), H: d(8870.00), C: d(8810.00), O: d(8810.00), Volume: d(677890.00), Start: p(1663738200000)}, - {L: d(8800.00), H: d(8850.00), C: d(8810.00), O: d(8810.00), Volume: d(1599221.00), Start: p(1663741800000)}, - {L: d(8800.00), H: d(8950.00), C: d(8930.00), O: d(8810.00), Volume: d(1817537.00), Start: p(1663745400000)}, - {L: d(8560.00), H: d(8920.00), C: d(8590.00), O: d(8850.00), Volume: d(1956165.00), Start: p(1663997400000)}, - {L: d(8530.00), H: d(8630.00), C: d(8570.00), O: d(8580.00), Volume: d(963507.00), Start: p(1664001000000)}, - {L: d(8560.00), H: d(8650.00), C: d(8560.00), O: d(8570.00), Volume: d(1202470.00), Start: p(1664004600000)}, - {L: d(8470.00), H: d(8570.00), C: d(8490.00), O: d(8560.00), Volume: d(1795527.00), Start: p(1664008200000)}, - {L: d(8360.00), H: d(8900.00), C: d(8860.00), O: d(8360.00), Volume: d(2232707.00), Start: p(1664170200000)}, - {L: d(8700.00), H: d(8850.00), C: d(8710.00), O: d(8850.00), Volume: d(804025.00), Start: p(1664173800000)}, - {L: d(8710.00), H: d(8750.00), C: d(8740.00), O: d(8720.00), Volume: d(490415.00), Start: p(1664177400000)}, - {L: d(8700.00), H: d(8740.00), C: d(8740.00), O: d(8710.00), Volume: d(354268.00), Start: p(1664181000000)}, - {L: d(8720.00), H: d(9000.00), C: d(8960.00), O: d(8720.00), Volume: d(1527278.00), Start: p(1664343000000)}, - {L: d(8910.00), H: d(9060.00), C: d(9000.00), O: d(8960.00), Volume: d(1085106.00), Start: p(1664346600000)}, - {L: d(8980.00), H: d(9030.00), C: d(9020.00), O: d(9000.00), Volume: d(473696.00), Start: p(1664350200000)}, - {L: d(8980.00), H: d(9020.00), C: d(8990.00), O: d(9010.00), Volume: d(699219.00), Start: p(1664353800000)}, - {L: d(8570.00), H: d(8990.00), C: d(8650.00), O: d(8950.00), Volume: d(2525245.00), Start: p(1664602200000)}, - {L: d(8540.00), H: d(8750.00), C: d(8580.00), O: d(8670.00), Volume: d(862745.00), Start: p(1664605800000)}, - {L: d(8400.00), H: d(8590.00), C: d(8450.00), O: d(8570.00), Volume: d(2648031.00), Start: p(1664609400000)}, - {L: d(8400.00), H: d(8490.00), C: d(8430.00), O: d(8470.00), Volume: d(880884.00), Start: p(1664613000000)}, - {L: d(8380.00), H: d(8610.00), C: d(8450.00), O: d(8460.00), Volume: d(2047200.00), Start: p(1664688600000)}, - {L: d(8410.00), H: d(8490.00), C: d(8460.00), O: d(8470.00), Volume: d(508220.00), Start: p(1664692200000)}, - {L: d(8430.00), H: d(8480.00), C: d(8450.00), O: d(8460.00), Volume: d(652416.00), Start: p(1664695800000)}, - {L: d(8400.00), H: d(8460.00), C: d(8440.00), O: d(8440.00), Volume: d(906352.00), Start: p(1664699400000)}, - {L: d(8420.00), H: d(8600.00), C: d(8480.00), O: d(8490.00), Volume: d(826543.00), Start: p(1664775000000)}, - {L: d(8430.00), H: d(8570.00), C: d(8450.00), O: d(8480.00), Volume: d(867974.00), Start: p(1664778600000)}, - {L: d(8430.00), H: d(8480.00), C: d(8450.00), O: d(8450.00), Volume: d(580218.00), Start: p(1664782200000)}, - {L: d(8440.00), H: d(8540.00), C: d(8500.00), O: d(8450.00), Volume: d(957990.00), Start: p(1664785800000)}, - {L: d(8400.00), H: d(8560.00), C: d(8500.00), O: d(8400.00), Volume: d(659743.00), Start: p(1664861400000)}, - {L: d(8450.00), H: d(8500.00), C: d(8480.00), O: d(8500.00), Volume: d(1096047.00), Start: p(1664865000000)}, - {L: d(8490.00), H: d(8520.00), C: d(8500.00), O: d(8490.00), Volume: d(390241.00), Start: p(1664868600000)}, - {L: d(8480.00), H: d(8530.00), C: d(8520.00), O: d(8510.00), Volume: d(1052288.00), Start: p(1664872200000)}, - {L: d(8400.00), H: d(8650.00), C: d(8620.00), O: d(8400.00), Volume: d(1420025.00), Start: p(1665207000000)}, - {L: d(8580.00), H: d(8630.00), C: d(8580.00), O: d(8630.00), Volume: d(664976.00), Start: p(1665210600000)}, - {L: d(8520.00), H: d(8580.00), C: d(8520.00), O: d(8570.00), Volume: d(811777.00), Start: p(1665214200000)}, - {L: d(8500.00), H: d(8640.00), C: d(8620.00), O: d(8520.00), Volume: d(1135548.00), Start: p(1665217800000)}, - {L: d(8360.00), H: d(8620.00), C: d(8400.00), O: d(8460.00), Volume: d(1757266.00), Start: p(1665293400000)}, - {L: d(8390.00), H: d(8540.00), C: d(8410.00), O: d(8400.00), Volume: d(2069165.00), Start: p(1665297000000)}, - {L: d(8370.00), H: d(8460.00), C: d(8450.00), O: d(8420.00), Volume: d(1283825.00), Start: p(1665300600000)}, - {L: d(8450.00), H: d(8550.00), C: d(8550.00), O: d(8450.00), Volume: d(1443903.00), Start: p(1665304200000)}, - {L: d(8460.00), H: d(8590.00), C: d(8500.00), O: d(8500.00), Volume: d(792803.00), Start: p(1665379800000)}, - {L: d(8420.00), H: d(8520.00), C: d(8470.00), O: d(8510.00), Volume: d(1158445.00), Start: p(1665383400000)}, - {L: d(8460.00), H: d(8500.00), C: d(8490.00), O: d(8480.00), Volume: d(806689.00), Start: p(1665387000000)}, - {L: d(8460.00), H: d(8540.00), C: d(8540.00), O: d(8490.00), Volume: d(1334939.00), Start: p(1665390600000)}, - {L: d(8490.00), H: d(8900.00), C: d(8800.00), O: d(8490.00), Volume: d(2464838.00), Start: p(1665466200000)}, - {L: d(8700.00), H: d(8900.00), C: d(8740.00), O: d(8810.00), Volume: d(2086815.00), Start: p(1665469800000)}, - {L: d(8730.00), H: d(8820.00), C: d(8750.00), O: d(8740.00), Volume: d(911276.00), Start: p(1665473400000)}, - {L: d(8740.00), H: d(8890.00), C: d(8890.00), O: d(8760.00), Volume: d(1329047.00), Start: p(1665477000000)}, - {L: d(8720.00), H: d(8960.00), C: d(8800.00), O: d(8900.00), Volume: d(1709787.00), Start: p(1665552600000)}, - {L: d(8790.00), H: d(8850.00), C: d(8840.00), O: d(8800.00), Volume: d(1069264.00), Start: p(1665556200000)}, - {L: d(8840.00), H: d(8930.00), C: d(8900.00), O: d(8840.00), Volume: d(1340324.00), Start: p(1665559800000)}, - {L: d(8880.00), H: d(8950.00), C: d(8950.00), O: d(8900.00), Volume: d(1694492.00), Start: p(1665563400000)}, - {L: d(8750.00), H: d(8960.00), C: d(8900.00), O: d(8750.00), Volume: d(1787429.00), Start: p(1665811800000)}, - {L: d(8780.00), H: d(8910.00), C: d(8780.00), O: d(8910.00), Volume: d(1494451.00), Start: p(1665815400000)}, - {L: d(8730.00), H: d(8880.00), C: d(8820.00), O: d(8780.00), Volume: d(924913.00), Start: p(1665819000000)}, - {L: d(8790.00), H: d(8900.00), C: d(8860.00), O: d(8820.00), Volume: d(1028523.00), Start: p(1665822600000)}, - {L: d(8640.00), H: d(8880.00), C: d(8650.00), O: d(8870.00), Volume: d(1524800.00), Start: p(1665898200000)}, - {L: d(8620.00), H: d(8700.00), C: d(8690.00), O: d(8680.00), Volume: d(1513406.00), Start: p(1665901800000)}, - {L: d(8570.00), H: d(8690.00), C: d(8600.00), O: d(8640.00), Volume: d(1445787.00), Start: p(1665905400000)}, - {L: d(8490.00), H: d(8690.00), C: d(8500.00), O: d(8590.00), Volume: d(1722207.00), Start: p(1665909000000)}, - {L: d(8500.00), H: d(8650.00), C: d(8500.00), O: d(8500.00), Volume: d(795140.00), Start: p(1665984600000)}, - {L: d(8510.00), H: d(8580.00), C: d(8550.00), O: d(8510.00), Volume: d(488220.00), Start: p(1665988200000)}, - {L: d(8530.00), H: d(8610.00), C: d(8600.00), O: d(8550.00), Volume: d(501777.00), Start: p(1665991800000)}, - {L: d(8540.00), H: d(8700.00), C: d(8690.00), O: d(8590.00), Volume: d(1029969.00), Start: p(1665995400000)}, - {L: d(8600.00), H: d(8750.00), C: d(8680.00), O: d(8600.00), Volume: d(911243.00), Start: p(1666071000000)}, - {L: d(8630.00), H: d(8700.00), C: d(8650.00), O: d(8680.00), Volume: d(757086.00), Start: p(1666074600000)}, - {L: d(8600.00), H: d(8700.00), C: d(8700.00), O: d(8640.00), Volume: d(425422.00), Start: p(1666078200000)}, - {L: d(8630.00), H: d(8730.00), C: d(8700.00), O: d(8640.00), Volume: d(660782.00), Start: p(1666081800000)}, - {L: d(8600.00), H: d(8720.00), C: d(8670.00), O: d(8620.00), Volume: d(469671.00), Start: p(1666157400000)}, - {L: d(8650.00), H: d(8700.00), C: d(8660.00), O: d(8670.00), Volume: d(546293.00), Start: p(1666161000000)}, - {L: d(8620.00), H: d(8670.00), C: d(8670.00), O: d(8650.00), Volume: d(804228.00), Start: p(1666164600000)}, - {L: d(8660.00), H: d(8730.00), C: d(8700.00), O: d(8670.00), Volume: d(1012749.00), Start: p(1666168200000)}, - {L: d(8580.00), H: d(8840.00), C: d(8720.00), O: d(8580.00), Volume: d(939987.00), Start: p(1666416600000)}, - {L: d(8700.00), H: d(8830.00), C: d(8720.00), O: d(8720.00), Volume: d(1003220.00), Start: p(1666420200000)}, - {L: d(8680.00), H: d(8780.00), C: d(8680.00), O: d(8730.00), Volume: d(767169.00), Start: p(1666423800000)}, - {L: d(8610.00), H: d(8770.00), C: d(8610.00), O: d(8680.00), Volume: d(472382.00), Start: p(1666427400000)}, - {L: d(8500.00), H: d(8610.00), C: d(8500.00), O: d(8610.00), Volume: d(785573.00), Start: p(1666503000000)}, - {L: d(8490.00), H: d(8540.00), C: d(8490.00), O: d(8500.00), Volume: d(1158605.00), Start: p(1666506600000)}, - {L: d(8450.00), H: d(8520.00), C: d(8520.00), O: d(8490.00), Volume: d(797369.00), Start: p(1666510200000)}, - {L: d(8450.00), H: d(8530.00), C: d(8450.00), O: d(8510.00), Volume: d(816922.00), Start: p(1666513800000)}, - {L: d(8490.00), H: d(8580.00), C: d(8520.00), O: d(8580.00), Volume: d(965156.00), Start: p(1666589400000)}, - {L: d(8380.00), H: d(8520.00), C: d(8380.00), O: d(8520.00), Volume: d(1881966.00), Start: p(1666593000000)}, - {L: d(8300.00), H: d(8430.00), C: d(8310.00), O: d(8380.00), Volume: d(1552299.00), Start: p(1666596600000)}, - {L: d(8290.00), H: d(8360.00), C: d(8340.00), O: d(8310.00), Volume: d(1326790.00), Start: p(1666600200000)}, - {L: d(8280.00), H: d(8450.00), C: d(8320.00), O: d(8450.00), Volume: d(1639128.00), Start: p(1666675800000)}, - {L: d(8160.00), H: d(8320.00), C: d(8180.00), O: d(8310.00), Volume: d(2019753.00), Start: p(1666679400000)}, - {L: d(8170.00), H: d(8320.00), C: d(8200.00), O: d(8180.00), Volume: d(1416805.00), Start: p(1666683000000)}, - {L: d(8150.00), H: d(8230.00), C: d(8190.00), O: d(8200.00), Volume: d(1475601.00), Start: p(1666686600000)}, - {L: d(8010.00), H: d(8260.00), C: d(8010.00), O: d(8150.00), Volume: d(1740023.00), Start: p(1666762200000)}, - {L: d(7920.00), H: d(8040.00), C: d(7940.00), O: d(8010.00), Volume: d(4274066.00), Start: p(1666765800000)}, - {L: d(7920.00), H: d(7950.00), C: d(7920.00), O: d(7940.00), Volume: d(3708253.00), Start: p(1666769400000)}, - {L: d(7920.00), H: d(8040.00), C: d(8020.00), O: d(7920.00), Volume: d(2467113.00), Start: p(1666773000000)}, - {L: d(7990.00), H: d(8230.00), C: d(7990.00), O: d(8230.00), Volume: d(3782570.00), Start: p(1667021400000)}, - {L: d(7900.00), H: d(8010.00), C: d(7900.00), O: d(7990.00), Volume: d(4110182.00), Start: p(1667025000000)}, - {L: d(7740.00), H: d(7970.00), C: d(7750.00), O: d(7910.00), Volume: d(1834825.00), Start: p(1667028600000)}, - {L: d(7690.00), H: d(7800.00), C: d(7760.00), O: d(7760.00), Volume: d(2606139.00), Start: p(1667032200000)}, - {L: d(7820.00), H: d(7990.00), C: d(7950.00), O: d(7950.00), Volume: d(4859163.00), Start: p(1667107800000)}, - {L: d(7920.00), H: d(8030.00), C: d(8010.00), O: d(7960.00), Volume: d(4220234.00), Start: p(1667111400000)}, - {L: d(8000.00), H: d(8080.00), C: d(8050.00), O: d(8010.00), Volume: d(1975520.00), Start: p(1667115000000)}, - {L: d(8030.00), H: d(8210.00), C: d(8200.00), O: d(8040.00), Volume: d(2780194.00), Start: p(1667118600000)}, - {L: d(8070.00), H: d(8250.00), C: d(8210.00), O: d(8070.00), Volume: d(1003287.00), Start: p(1667194200000)}, - {L: d(8100.00), H: d(8210.00), C: d(8110.00), O: d(8210.00), Volume: d(642473.00), Start: p(1667197800000)}, - {L: d(8110.00), H: d(8180.00), C: d(8160.00), O: d(8110.00), Volume: d(664372.00), Start: p(1667201400000)}, - {L: d(8100.00), H: d(8260.00), C: d(8200.00), O: d(8150.00), Volume: d(1241301.00), Start: p(1667205000000)}, - {L: d(8110.00), H: d(8450.00), C: d(8440.00), O: d(8170.00), Volume: d(2909458.00), Start: p(1667280600000)}, - {L: d(8310.00), H: d(8450.00), C: d(8360.00), O: d(8440.00), Volume: d(778238.00), Start: p(1667284200000)}, - {L: d(8240.00), H: d(8370.00), C: d(8260.00), O: d(8360.00), Volume: d(658420.00), Start: p(1667287800000)}, - {L: d(8240.00), H: d(8450.00), C: d(8440.00), O: d(8260.00), Volume: d(1814124.00), Start: p(1667291400000)}, - {L: d(8270.00), H: d(8440.00), C: d(8300.00), O: d(8440.00), Volume: d(1267103.00), Start: p(1667367000000)}, - {L: d(8270.00), H: d(8510.00), C: d(8510.00), O: d(8300.00), Volume: d(1821017.00), Start: p(1667370600000)}, - {L: d(8430.00), H: d(8540.00), C: d(8440.00), O: d(8510.00), Volume: d(559250.00), Start: p(1667374200000)}, - {L: d(8420.00), H: d(8470.00), C: d(8440.00), O: d(8440.00), Volume: d(544851.00), Start: p(1667377800000)}, - {L: d(8480.00), H: d(8730.00), C: d(8730.00), O: d(8550.00), Volume: d(4284720.00), Start: p(1667626200000)}, - {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(1382828.00), Start: p(1667629800000)}, - {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(1678201.00), Start: p(1667633400000)}, - {L: d(8730.00), H: d(8730.00), C: d(8730.00), O: d(8730.00), Volume: d(549277.00), Start: p(1667637000000)}, - {L: d(8800.00), H: d(9070.00), C: d(9060.00), O: d(8800.00), Volume: d(5342062.00), Start: p(1667712600000)}, - {L: d(9040.00), H: d(9070.00), C: d(9070.00), O: d(9060.00), Volume: d(8126959.00), Start: p(1667716200000)}, - {L: d(9070.00), H: d(9070.00), C: d(9070.00), O: d(9070.00), Volume: d(527101.00), Start: p(1667719800000)}, - {L: d(9070.00), H: d(9070.00), C: d(9070.00), O: d(9070.00), Volume: d(702521.00), Start: p(1667723400000)}, - {L: d(9160.00), H: d(9440.00), C: d(9430.00), O: d(9290.00), Volume: d(4409696.00), Start: p(1667799000000)}, - {L: d(9410.00), H: d(9490.00), C: d(9490.00), O: d(9420.00), Volume: d(7522839.00), Start: p(1667802600000)}, - {L: d(9490.00), H: d(9490.00), C: d(9490.00), O: d(9490.00), Volume: d(777299.00), Start: p(1667806200000)}, - {L: d(9490.00), H: d(9490.00), C: d(9490.00), O: d(9490.00), Volume: d(405416.00), Start: p(1667809800000)}, - {L: d(9300.00), H: d(9890.00), C: d(9530.00), O: d(9890.00), Volume: d(7097789.00), Start: p(1667885400000)}, - {L: d(9460.00), H: d(9570.00), C: d(9470.00), O: d(9520.00), Volume: d(3033312.00), Start: p(1667889000000)}, - {L: d(9380.00), H: d(9490.00), C: d(9410.00), O: d(9470.00), Volume: d(2714433.00), Start: p(1667892600000)}, - {L: d(9390.00), H: d(9490.00), C: d(9450.00), O: d(9420.00), Volume: d(3876877.00), Start: p(1667896200000)}, - {L: d(9250.00), H: d(9540.00), C: d(9410.00), O: d(9350.00), Volume: d(3448605.00), Start: p(1667971800000)}, - {L: d(9400.00), H: d(9840.00), C: d(9800.00), O: d(9410.00), Volume: d(6547559.00), Start: p(1667975400000)}, - {L: d(9640.00), H: d(9830.00), C: d(9650.00), O: d(9800.00), Volume: d(2416825.00), Start: p(1667979000000)}, - {L: d(9650.00), H: d(9860.00), C: d(9680.00), O: d(9700.00), Volume: d(2463503.00), Start: p(1667982600000)}, - {L: d(9640.00), H: d(9870.00), C: d(9800.00), O: d(9750.00), Volume: d(2000789.00), Start: p(1668231000000)}, - {L: d(9520.00), H: d(9800.00), C: d(9520.00), O: d(9780.00), Volume: d(3214849.00), Start: p(1668234600000)}, - {L: d(9520.00), H: d(9680.00), C: d(9620.00), O: d(9550.00), Volume: d(3019512.00), Start: p(1668238200000)}, - {L: d(9610.00), H: d(9810.00), C: d(9740.00), O: d(9640.00), Volume: d(2473212.00), Start: p(1668241800000)}, - {L: d(9450.00), H: d(9710.00), C: d(9530.00), O: d(9710.00), Volume: d(1455003.00), Start: p(1668317400000)}, - {L: d(9510.00), H: d(9700.00), C: d(9700.00), O: d(9520.00), Volume: d(1341450.00), Start: p(1668321000000)}, - {L: d(9520.00), H: d(9720.00), C: d(9650.00), O: d(9700.00), Volume: d(2922575.00), Start: p(1668324600000)}, - {L: d(9470.00), H: d(9650.00), C: d(9470.00), O: d(9650.00), Volume: d(907574.00), Start: p(1668328200000)}, - {L: d(9250.00), H: d(9620.00), C: d(9250.00), O: d(9510.00), Volume: d(1573592.00), Start: p(1668403800000)}, - {L: d(9220.00), H: d(9420.00), C: d(9380.00), O: d(9270.00), Volume: d(1372258.00), Start: p(1668407400000)}, - {L: d(9340.00), H: d(9530.00), C: d(9490.00), O: d(9380.00), Volume: d(3147032.00), Start: p(1668411000000)}, - {L: d(9370.00), H: d(9550.00), C: d(9370.00), O: d(9490.00), Volume: d(2153637.00), Start: p(1668414600000)}, - {L: d(9380.00), H: d(9750.00), C: d(9670.00), O: d(9450.00), Volume: d(1861478.00), Start: p(1668490200000)}, - {L: d(9580.00), H: d(9700.00), C: d(9650.00), O: d(9670.00), Volume: d(2890813.00), Start: p(1668493800000)}, - {L: d(9610.00), H: d(9700.00), C: d(9670.00), O: d(9610.00), Volume: d(1288957.00), Start: p(1668497400000)}, - {L: d(9630.00), H: d(9800.00), C: d(9730.00), O: d(9650.00), Volume: d(2413843.00), Start: p(1668501000000)}, - {L: d(9580.00), H: d(9780.00), C: d(9630.00), O: d(9750.00), Volume: d(803830.00), Start: p(1668576600000)}, - {L: d(9630.00), H: d(9720.00), C: d(9670.00), O: d(9650.00), Volume: d(699785.00), Start: p(1668580200000)}, - {L: d(9640.00), H: d(9700.00), C: d(9640.00), O: d(9700.00), Volume: d(393592.00), Start: p(1668583800000)}, - {L: d(9580.00), H: d(9660.00), C: d(9630.00), O: d(9640.00), Volume: d(1443871.00), Start: p(1668587400000)}, - {L: d(9300.00), H: d(9600.00), C: d(9370.00), O: d(9510.00), Volume: d(3845936.00), Start: p(1668835800000)}, - {L: d(9310.00), H: d(9380.00), C: d(9330.00), O: d(9380.00), Volume: d(1380628.00), Start: p(1668839400000)}, - } - - indicator := ichimoku.NewIndicator() - - err := indicator.MakeIchimokuInPast(ts, 135) - if err != nil { - fmt.Println("error :", err) - } - - lines_result := make([]*ichimoku.IchimokuStatus, 2) - arr := indicator.GetList() - for i := len(arr) - 2; i > 0; i-- { - lines_result[0] = arr[i] //current - lines_result[1] = arr[i+1] // previous - - a, e := indicator.PreAnalyseIchimoku(lines_result) - - if e != nil { - fmt.Println("err", e) - } - if a != nil { - fmt.Print(a.Print()) - } - } -} diff --git a/pkg/indicator/v2/ichimoku1/images/demo.png b/pkg/indicator/v2/ichimoku1/images/demo.png deleted file mode 100644 index 8162b8415c9ac0c706d70358e31ec8324b6f843f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131507 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%0Dl@deHxuq4VSFst+qfB33@ z0dez2(K9CX*aavLuVVM__9Zuu_gPYy0iS!6Gchy-{g6TYh21d_2VX=OOO(NE7jd@D zTyZ~~?+hng)}%21p#od<@6ce6Ne^bGAhj$aGMNid4ajwzZW3O?Jw5Y&vP_Po!Dfn3 zhVkd!?E%^1QdZ#Mog0s{c*=q3eETWb`DivmmKzlXCEf!?Dw;fMJZmX;YE@u3JTish z7eLcY;{KvXaJjN#kFd|f@69!yS%#pH#d=3-8TELZy$-;2090vMNH0Z*Y-(qST=}u z%+jFeYJtPNq9R6B6S38{-iduMrL#*NEj^8s4$z~>a#@cjwS_W$qOv+1s0P>8_WZqh z9R;wlx|0fT$1x>_!Ta|)vzsb2u97KT ze~jXXzI6EAe#)PIK>uR0k#D7Leb*UCQ`UkFJi@QysZ&;DK*FI{SB7tnq4w%^UXj1+ zDK-}Cq@)!TiX0+Fnm~{sov~^pGao_n`;Hx|ppiXS2dFa93gLL=+JE5G&YQ%`5HWui zcxl)jptC}_v!=1!?P+!B>%N5&uw_a3M0PCwdv`oAs6dEeopF)+QLZ5w-4+2RGcz>T zVq*ONvY$=fYnZ>?ovwy72z^Dwc4xGoTN@pw=j&BB+E;l~_8=F`mOs6N!_W1=I#iKj z*OH{cM_JD-7OKu54Pq=S?km2vI!khl!#0c1YRri^ZY=zuXhD{jzc?KGuA#K|d&$Mz zTun+u=L=TSx;?!dzfUp54V(9JBIiePx}-!~T(nzE!Asm9(SIvWVw|C0&#tuJ-WagI z=jx|hGi&j>W%uTO_(kiT`dOAV9^gq%$TUv{J;FJxcXQVnPdf%M6u^0N3hIoNq2dW_ zFT+g>MK=3869sQHzmKedTNcm z?BUywgmHqbx|jAfKt(mueBlQ=ZtK~p%L76ps+Z`&XPc!u#F!xc^LpWS3qJCcIZ&SF zKZy;AE6Iir*`W&~tyttX7^tWp?rd*+1D@&aug>=Q=f0m=KAur))XvYDu}-VXH6@~F z{P)ZNBeS)Y&)E#P zii*Ofhni1><%L!7Mcc&3<@V1Gyr-`z%!ejB9f*zz2U7=)ET1rZ1p_73F=X6{V*jbA zhI_52mH{iN0mRKe^dy1tSpJRVJ(W|(KXx99Z zkGGmWd$%y#OLd8&-R7=e*N{?deVM~dA6Yu}Zx@#zKV#h3Vid1ya}mdt*-yfl|_N@XX}|1@(mN=>9?)tgP;l`QkC))FBp z*I{~pTsl94ctBU~zW0c-Kd`LxV;1&42<sD@?sIyD% zT2I=?eQOEFbKmD}gK~rnVDDDyynh>%x91hAWJ2TO(9-wJ74dpl5BrQh)2i=l z!nO*m6~^YM{Jf*^+J#+JpBp^))BKQL?L31&!r*lZK`9Lj%7df8DE1E=!G*_y7YT^~ z!NCPGFy-fmy`g6qN$6y(7rxE5a=j4XZq&}D<-S~{IrYgFlyDsX=zGe@^)K@>`%Q)7 z6g&G5g4yvqY4CR(LUejK4dggV@xuTRIN$&zpT&h?X7;7h#}5bgdm;?7s4JY4JOA_(MV+Cevt)1wtjkzoPjmUO4tro_8aX0VtO?~1`ogD>)o zRhhEsg#+Vu(-Nhq*3scpxtIK&U0{})pO4TtE|?^-q5NtXJ2y-_e~fo5r?SX*4ld?x z(~YJh>jiMM(GBhxKxT()gV@go9R7<>o9jI$+D*c8h{zs$>cdXjFyCto;Oz~h98ljXdmZL<%77zcxQuriywQBh z33+*qnSI}qQuq<~-X{QUmAEnf)ss9wnr*bQOGt-te;%5UwRxc;e7t#E`RuI+0cj{C z?VI(3MCAV!YVC+$yrgQ|9DgLiPiId$E*E2D{r_79RG-L7h ze80GA@%*pi1pE$dVB9E`h|Ue&mBv`#i@#}Xy-cMRNxeZ9C~_dMamVrM7gMk_)nLU3 zd=GwnN6Q>a+~+847Xs)?s_Cq3{L5qKyCg)9Xi8lCFTJxr5ePXuKnIQx%}RBnl?Ua$ zt0oLGhkBjVzotr0HH&}z(>)Zk;;A+ok=Wm!z}y_CtSt)kOO95g!_IW=^$339UoJso zNw==s33_)(kV7JkIsn&jXNY|u1dcuYXSzAMp!JzOy_FHoV;cb$8|toth|;SIX#G~z zw}O^%|3}a}0ad}34ivT+KZJ#vlJ<%CSRFc%;Sa%Pp3^qV4NozL4Z626sT>~6l4uz) zE}vR0;4ZO6N)vyu`!c(upHKDW;w^q1J;rbkkVPo&xFY2fdZCP3cz<@ZXEi)B;t=}w zyA@JEx_EHD@`r5l?AW-I?IS%FSg>0 z(e|`Z5@r17tov$>H3(V73G;iZUskt|ul3u1a*WYG~RO^~E(I~$#U>}&mbOhqvzd*|~^>0JaDWDdT@;Bdy@3B~sMYAj3)VD)< z9o4heaft9@Fu9lqDv2WPccP9nhL_1W*WmLoBk4BT-WgZ_mkZFd2-E*%)zR&M>$p9C zzgB^s!=E#tJTOkvyk}^_@?1;lZ}h!HI|l;;ka3=LWr=D;yFJ;m4o0&y7%XLb3&I%M zp$^t`A#Gj}4Y{H7Qh@~Sgo(0ARgG7W`}jj+hikWgfo+zm#Z~HVQAEB~Rvbdq8!^7s zd}t3K6@W{gq(u~|Lz%ZODGm_LgAok}Q-y;?>%hG*JMA#NFj(T)uuv-VP|dOEV+1Nl zZ=$HZiy`8;Pll*ee`a-<9TBC-aPxu8Z}(K-J|IU_JPGqB025wp6#&oRSO!_Gi>UeA zhG8@yk7_y}@}qDm3O~Y$7~g%a5+!smQUOorfm9VW0fI>~{&NK|Us^r3k?jox;`3qG zTN>=>gG@!PMR~zEhrWU!sl32Q4y?*Fwl}F5iE+%iH!Bk4YTF1xd9Ul%WwVMM z#nz1Y_s?~P-M*uM%Y=^UTM#d{#^)r`V@XaC(;4M0ea4W1ExlNB$rf%BX3dY1K}7h8 z2y_L=_(2GCIG5?RkF@({!@T7?y5aAE=t`-f!W>HN4CYAYm5nmEx>_}kU}GQ zDRQ@7=1RRH9!WZZ9eKvKy>>&}Lf51B=MaMQI#q00{(I)NuC;;BEC0m4Ir)5BHdP-= zJeF}#X^ehZSSW3O?&#kbtMH{9zRb$l)I0)k32;sw;rr2jSGV!z2Er@k;h)n*D%9zq z!D+cDA0UvPuyHa@%Rk~4jcyl7xJZ~k9rnUVrD8_n9Oqon^bBctncKv`*dPSUJ83cw zqBxMt4@7#d94VRdKdr)6Tv+xW0AI0;mOA>#1q{5~ek zuUB^4)4^3>sGo4EC7wK*_&|kCCANj9;QGt;2sw|NY*VGYEekf3R8s4>AMvyT%uWf$FF=se zG4Iv}Zp!|h14p---C=2*z##egrCJ(e)N0=p6sKPg!(-Pkt3uUPO_%fij#%lKU;I5g zHLG(gh&w{XleaDA4hP`M?`8(}&?@F>8MCoij+2jfOokgQiiydZ57SL2ctee4~ z^N$f>;nr-WtoefqHCzXca3GlNm#BybDj-`&kt!}d))`vB!!^$N_=N}I)1CI7GoAp^ zUR^BUY;MjSU7as?qR$66(+K(PnVogW5Ha^-k;wM~EF>>(llfT@zyT8evq!P)e9pYS z$z%@rU2;24Kl^Br&xWOsP(?~VyqzVUN*i)gZku@V8(!h&^UMX{+4c*RUcU)lc;y2d>qH!oUD?%Jy$e+c;e{>1?gSo=PIWMvv zYO75_l;~CA!Wm+9af6Y03he9d3(TRy@swL&uA0>TE95U+rLg(wp?NfN(WpZD661_* zt-szzNQul#0|M!gigzOeD#;5QTZ|1$LG#Yu-VjJ1u|Je_Z3O-HprZxk>T4}e;aA$g=bdtf|J!X|-Iond6dr0b3*`ELvgnE5*?;$q*HsJ`S#)`R>f0(1 z#N?ttO3!qVS=mJ=iC!YMt4FhJ?lFPGcq*AsDkFIfT@Xu66F~0l0TOoO-?=uQ4spq>sAj5 zND+}L95?^?Tn7w77`|7Hev3oqH!~p#E+?+0Kaf%=I@YCZ{3A}4XU(z6C!ui!dZ5K? zwIDOZx$!8O67Q~mO){A6E_O^_2X%p}eB#|Qa1=gmaEA-N5dwY`&eIA16kla(#6;2D zoEfW7R#gp&@1yIsx$((P`yQIF~=hXY*JoiD-XA%|IZ`|u=7rV`zH&W+Q zp}H-|-551`$dqpT=|AiU7<=fuN zU_8WobfpG;}nHfV@U4I_7F{PCzoX6vk%$;cc<(WwQ zfBeB{;Wkc2`c6ZTO_l4Z9TIZ*HeJRrO~pSmb}rk|_WE!5wY=2eS2inmRZzmitfWml z$TFg_bJr#o#}v72Ks_1*`Ssr;gqk(>@WB6gb!Pn ztc{0ugTMwBZvq$l-#?8UUo)5X=Wy(DD^T|nd&`D#@jiQ=Nq(d*-teZIy!#~$bxr9} z|2i1IL-fv?)SB+tGA3Jl;)N0vZbsGL6eFxR#30@b3e{$6Gm&Agr95@SsyRKA$VFHqBuqp;#_mk`$ zV7JG0V$>k|1+s1XIVEuOx(L8p?kfbFo0em{;Ilh|4@$!`3fHS*rCa@=F& z#VGG46Ff^yV54x;FOW8=clP7}QL3~s#D*63z?Lq3z^JqB#nKca99WQxclrVL*hNuE zRo$dOP5Dj(#|qpSai~TKjQ^;C!N0l8_jGWaSlYFgh>AIUu`C(QSTyvnmJiP_ly(r# zJ=vUpRI?wrO=}WIC@`YL@aUT!2$Q?A&l45|We}(yN<*sWmHC5n_&WtYFWc!)AJu#6 zztYt%+;L6PLozGFj96!Qz*6sJX&EsUfq&bN?CK~B?=JJXZ|GO;enCy`W2{d{)P!yz zmB_Fz(|~?vw)-0&Yu8J;ko-D!j3D*MR=G_6_9WqcVFcn1g0GDp9*%;J&37l~5JN0z zI(m65v_1dqR(I(0^u=zmPztO3dr5eHd0>|@-_X1LkN^g2<@9D^@T9bq@c@9dgeaf! zz{i@|byP}}js*OwgV+SJhk%ZUb0Sw@OX_GWE2_@+T-YF!M~@8fjVZm_BOHl}q1)pu z79BJd2YpuvA`JOP3@7Qoi67TKS_#leVq#IkRRb0mXU&sEN2drTQN+ zPOA*UN^-o(i)hXIhyLfLnNTYB)B$5_!w-+Xz$=Ba44h7z_=^5+o=M`yEtorrFrQAN zNZ$NYNtL6xxP$<)ii5vpIf}AIns(SvQO~Kyqm_c^e>E>99C|;&*9GP<(bED8q?;^r z(v?qtkFSL0J8ne6Q5Oi9UIVrb)>#AP?1(Z!`vpOs;;eKMGG|k7!9u6M@aCp+KN{wD zNzY0-I%h3`HTge@sU7;@HZMt%FkDemZ4VUu`hmo~VFIi(kJlsg4rdf`!v>OA{Np_^6T=5B9`_VizpE83(Ao1?E$Q?h{%`%1jkaK)48np%|N^*g4M~(B2D6#}0?@g;*oyhrHLC{lh zjxYmL27KUYa^6X=^6;VD*C-Z&!oD=$A6*~AWEM#fAo1$ZM*^jb#7I5ed=;u61!#04{_L>25=pt24XgI{MQZ>dzws$U+bM(BrIxA}U)?y5PvQ z={v_vik?dX-)ZY1^H-wugAiJ|-~~w@iDPt2Q!c!RVHvEDmDJzpK;_4}G4K>K$gj&K zvpV&*iGn|3q2hIs8r%7w@BizBAaL3Al(@)swvUpdsV|7*S)J?mFy5oo$fAOp%G`y2 zWkgC-s%g0h6s5ec>jX1ODcn67bX z_Y7NB=|Hs3;gXLQ8K2is+KgApgeXiCLF#~MfUA(G)`2=rXr{lETDX5KI4m-D0KoOw zz4zd8@$es|HJ6J-0>N%aodfms2zgd!v3~{it@*)%OS)%w-kFVbh+=nZKWmmQ@WT8{ z>A%H^hkxxD(~Ac+I(jOI1Ml*#bE zCj|!H)rCo5tlA9WM~tfTi??i_CkqOWv*mEU0uUy+3PliWQS}b+weQ*Ay5r>ZUMy)7 zvX|aOf#>f@9OYZMnn4~*-dzq?S-I|sl(W_bQmID$0k?{E)gRDl;KaKf08`-|k1@xF zJ%ET?`vb>%b$kosxw3$s2z0|IW_=A7P$?6TQ?OdnpCQHYHACDNKCJaJA*9rlb~GXt zLMGZuAz|rGbMOJIFlTbh}v3Z=1*7Tunw@mg7skHsp!v?QVC3cZKe9LP9!@c~o zA{GoRPYOlG3JgmR>gYOA@UFj>db&CMN?$oSD+|alrL&G2AVEtVXBp9pV`O(hOVbr4 zHl=R7LPi5d?dAv-{OIp${kt99Apvf4GeR=W8Xnlr+P^85{u>VS|B0B^*Wgp%?lym2 z^5?BjUcV|c{TH&4ehO8SXROGxAU(ZjLMIl5De~uGW zHKS&ZNBJnm$Fu{Ivjao((}VMt8Z_@bc3`#9XdZY~Ez*Gt;q_9Yp0&ilx=VpM2Im(E z!#`yRFEz2ebGi|4b6gGn^?FpjS88flJ75m3!H?g3^wl_4S;!;XrV5m)a+hK<1NYar zx;0@fe^8^qLCEl&z#Gw4!0I?pa>8`7sB7)^ku7G5?#2Bm z!~UZ?JEOkc2te{O?!BykB7vgT0|9#QyXV>2z-c4G65rwdBet-aDO%(58P{R|XLxw* z+&RO#INFH)($wd>uNfQYfy&KgRe2iL_U4Cp1g7$IVK7*qUtyxALQ7Jt(hz^+MV%x& z&*VigEY*4mykx8gipmt0cFX719Bg}^KTD{pQ-_C}gpMnNP*y?2Je%U$R zG>ThKV2D(m<4Fxvk28wTBboh3&X>AmyywH~iM@PWoBLsXGWh#ACEhnIJ;ck|A?`!h z>+8lE8!X&98tfm)7Mei19DGMk_YtpJTyk13IoWzDZYw?9 zixjYz|0;ORjzj^4Yz5P$QNbBVuVQlNd-j=VjmtZ7_f=%JQn%(46Vpq=!3s}=)i)r z{%L;~RDU8Vas!xMOYm!4LKEhX^J)%o=cW>oHO9M zRbuI2Nze>wTTJVUi-|lhw4e4gh6>Sy9zb}LYzti_G+gy!XE4o|I71N^@nHlNq6BrvYY|?LKh3BfrYAcJ)I1LM(8jwWeb+vdh-~Xn(O7iQw z+O&ZrB|AH;%i)}4=RMMdP>|W8eF#tn@B^0-Blz|WYMSc5|+Bb`NQmy z;|yYNnec-I`nKIF!lF-8~W?FTMD`bNn% zJR<%RfyxC^*zuDBC|;|4JK`Z6-+)_F>J{x^;7yl;hXLZFU;d!8SYdZ}Lcymy{Yt%a zh+-ChXeD#o_f$WPa$YJRKh|LJg3mc{1$!`Mq!k5C>965p22Wfk$>p4>-B!I57piL5 zNodT&MfljDxNWAIkt=9qKZ2;>DgY~pDymP{2<@@#-e*bC%i;O-syDAdpAA($taz^Z ztFs1r$URX{=9}S+>b@g;L*avHj^p!wtP5r3f2L-)!-8V$u=XJi)M%63;dH@V@DOVl z@)B1^)=Fx7Du;e}CI93@kl@!A(eOMgzMMupqer#Q08B?pD|H$6 z>Zmz|f&6Ga0HC1P{ChLI6q+(uM+RUvO++4!P;QWDG}`%M%0I4jaY4DE0c}1pv4R>rFv)ZwX9^+@Kb=21r4rWrt z$i&Je6V1${9}>@%grm+O3S88g(&q8wRk?U|2U|ct~4}b$;hk)Uaz1`0v<-Hr06!9wJ=(!6utuxmj4@IGDjF< z1qj?XV3gk|41XuJKKDB@9&nqnT)sVB>kL#Gz%Sp!hYQ{uVL|zcwec*xE?0XkE`;j% z&ZMeE&zQPotoyK5m5ic!ZLQd+S6R=??-;cok1U!I-C;AxrcEysu+6Z46Ho2Uf} zSTSplwB*w_VDO^jF_JL>uUVrXW!L;1W$5>kIANq}!wJL{VTN)+fWr__W5(EK6{{E~ zh@%_%OTbSqiNnbZzD_Q!jK@2j+g#4oJ0R)r<7?%k`GF!Tu-hcH`i)9&*b@>lFJ3_4i$Y1(w=Cv>%2?7mL2xPRY@D zq;fUYIP|)7#fH6V#q$Y@3ZCU2);+XRTK2|;La`x;HhTeLB;%B~ z@&N+-liI+PdauAGK`)Kk|N8GyJ2?5%T+YMQ{$Zm;Wo6~z)6a};UtR(Bn&2Kc5lgpK zY@2V#JzgWH_Xsf-Q=m5pme*2fg~-O*qxgr>#%7^c{E-R04g|1*D5B+s;N=hPEUx2% zFr9z)s%L+)0?7&&kUEIVK|z460x8M*lseTqBHS@wLvNIpL4U54RC^C!+SO}Z&o7eJ zi3u3gc`+z+SYHOv&!qZ|K~U+#a20h880)X^SzQ|x0i`O*iKli(y()#c7J}_=!|B{?$`zp_; zE70o_1JfFDfF*vsTzpQ;d60%+ zQa3>TGK}m80;cseb#c?X+h(dh9oxiYh=79bAg}Y*?j?Oce4Ups*)$x~64-r+Y9Q%& zAz|}!MWU5TO+xy*A8+>D?0;&B3@^n*hKs>#p3@(R@QR+si!wNMflP-vMRUvoS^Lm@ zijjFU<`{$|e1h(-ady%y@9023)m8Z$I!OKxQ*YrA9fO>3>^>PDB91J z)Elz@7ylLk>vx?~``?W$-ncKCi0HGV!V4ikSu=wD$<$;!~<8&>B8*^f#XwYv`3{`vDw z4oHD|1Gns;#}Cr9T`GwdpWjh-1tWr56eA7_LNp~Snz@AcmUMws7vt%m*=~qlAF+=8 zw<=hQ3=A;G=`WcfoNS<{3h|#|4Qx#Go5s(-RpqPIAo1+7Q<$)=8=;W?eiTmA76e%| zN%VMyokh-eF`wt8A_=&J)}Ch0m_Zl-Ww^Ya-G|vR1;9D)M#})BtX?MDddK z&N!@aqmfnGaZ|pX2p)tFoOjM$;{{PM$moY6TJ}CWcPC zAEBQ&l(L+}WKN1ze8NSHqA7)csiuM*1_gv*qcZRMnl@Rd-NG(TVP~7*n4)0f{yzGCNN1zVeB~&xhAX-)Ic!t3O zO(VMc9U4dA8_;$cis9qOIh);p&k74e4tA5X$-I*>umnfOZWd@c^b|$Vo0TSrTU3o0 zsN{lWkt*ZfTui6+Iif-$sNI_@W1(S?pG@Utv)fo%1TGwX$y^@syt^9E;XKnCz;w@8 z1|l2*V=|hnhpSU-$O?Ko_1dJ!hSD+mW1+!jMFOU=80lQuv_1v2xo7K{G@ zg42JBh)IMY-^l>d2|X%$ZCO)FwuOegFeN3>Ng7tu$MwZ^FouA|J_PzL~jQxy%2 zzp24S+(YTr3ufC`)!Rq&+Ib4f=C#i_0i{YFWuFMt&acObD%Gf)5^Cy=+sl==tIlNC zC@^^UjdXCYVAHR4KB?X!$x;{Ph90CG#^~*B?e)vpjcQ;~#b7`q3}`G}b7Ty|NI2dJ zxE2^iS%++iYR5Bg&npf(!1`7t7Yq#}Y!oDqDBnj3Q_wZ(yJ|5GDkozPF%p}yFnxdV z9k{~tfqfnUfVa+2d7bCak~CLCvmUrFgzbMpPKG^K{NePn^|k-=m-h81fTNHgey@`r zjGDH-QTL1!(A4Tf)^e#GJ$kZR@i-8e$QghoL?cil`QyVK8e?T5_djkeX5E|f&G4xT zHx}{9b!#ELOe3|_&=3}WlbT6MWKcw&PXvEEA-rUvfLw%lsqQOS6C>vjR_zz)I;OBQv3czho#Ot)+Zd&d>vS!&>{ ziDvc>o5lJugalcaQOj=8*l$7*0MxA}w8IYQM@+OiG3U!LByKM(?N%9qfflawLy1R- z*t0QP16Eoz-@(`VfasBsGs;%HfNlZ#%AoMi%fZOMDR@?YSPb7xHdqy^ME+GK%x?#1 zN+_69$VWDeFf_m}{IRZv6=g3$^m(#-PgS8Tcwx3-mU57$8PJ^fD zZbqDqnCjw)?p+j;{y^FV(|(cR10!yh9PVi8mJVjm(-PwHJOh+nn8PekJL8$yY0QgE za9z59(l#$-IX}Msu1mZOY(SgpMuH{AjO2vj4X_L`s8Noz;l9^{vS~zdIe$@=*7Czw z>%(g@o%5&7K9a@*@oZBXi7Q^bJtHHe_mw~%ZnP}T7*>-KxV4Yn0&q|fW8BzFeF_G! z&=*3Sfq}2za0rJK7Y}}9rU%SAj_c3Qd(82X(+Ph}=EUu0t0hVluEKh4#~SygX2ofK z!!JEh>iA@P$M$y;js4Enu1xjgN+JHt&*%Bl#{xajKf&b0c_7JW_jE&Jt4O4Z z7go@J%=hKRI@&>-w15oB1#=<3#DK+s$d4}LWOMy2%=xpDJb5YY(d!Dh7V2@*{*PG= zHI(QlrG!(Xk(+=%H(vz*mJOYzRuW?e=?IZO{E|tnSo8fzx_9d6`HK0VOoWxDQV9W^3){Ik|2|90C zWm7~001A*q3xLvqZyZ*9ISrZ#BJrqMg#VAHB=P+Jxkl)LDJP@Y4ej&QFMze9#g3f` z4I-FDAha!b_LA&iAV_yBiDlzfL@pZ_CcDv-+M~NC`6VR0uHyzjqrBiulk`MBF&}SP zstBQ&6_J=F{s~oRIWvBV1Ai6R@k?0WQsrUod;f}eG?cYN3uK1X0-Y7L{1dgR^WZOI z!R&^--}XsXzC1cttF8!#oE(U??XQVLmaJg#A5p9+7<|mgp`11#P7+7LQ_f^EHWkOeHWE87RfsrA<)^I+qi?tG%fR ziWJ{rmLFazp?IYh?9x(C;(n51%^?ZPsb}8ghAQE6%clH$pX{n9Sf{bS_3(1BU}U}~ zAr_4Q2nSRlE6Yn1&FL;#& zuHuIX_QRv1Vx&3JY|7_hsTo+GxJh9}pKshXs>lGvpX)C;HXz#4)YX0D@|f&bbO)fS za=PhudBXNuJG47#{+y&61fW>I(UI!}!KyPP;s*!4v30rjaFaj>9zrxowFrk_Rgzk} z|KV*kW93QQ3n1!Y!Rn?F1W!!yq9rYo{R$9B1DhkhtDR`D+_*clc|9>{vY|;9MfFVK z#z3(py9nV<7+j2?wZQfXYH1s_o!=NoNd1SG`b6bGGYocJv#1)9{AstQ5-VKUV7IOo z*)L8UfH=vdnw-w901W~8+|nOkKLmA+BQHSDCiGFz-h9%`C7EuXXcx_ z#X=PIc@rTUX?=6-g34`z>58sfr;PIOp&L2C*P`1ppyCDm;5_iZ?mq&^KY^1$)Gta{ z&eH!lP9m_as7yZ$#jIoREAADX*)C)B81N0(8lxC7J*QN=)h_O%t1sb&a|Ai}C+soR zY0Jb|ILrW+;)4`NCdmE*Z)&vYJVpC36-ogAvT5mi4fH$Y(BUr%NZv|%5d}vU#Re#u zR0Qz?7B(Em<(FDb`=p zpvZj0SK6M>92~dNTiS7SsFD>vJ;OaAHm)Ij?fdN8sTO8*z9}?_+uQQXpMC1H=A44= z|Ao~nuxmJ-_S3p(gEv2hwb)P5r!k@3yiywI)m-o(0iqs$=9~0H+xmCsp_~*OBRN5| z%ArZL0C?jo@WVG3`ZHl&eal8*Fpcz6ibDKU3Dlc`6{+N{xB@dy&E~q_{K1nF+uen( zEP+`qrohG%8Jt=gwXj^@YH{id7xX~a5(#m-um!in_sh)JNDAr|N3AM+voX@1o3kBF zqgJ&Sk-yjxfGbC^naG1zj8i%3cV&71uhB|@V81VwZ$6vRY!^k!vTUB{Ru|*-;{S_6 zT6R>RI?WlWhG_}PZQ`Qj5I^G%G;d~b*n&!S{PD0SmnzkAqLtVG zspzjmb&=SN1pTHnif*Mr9Bt=4vGngvV7s!5<>07eGAZqfIM zr8Yk;d}UCC$HI)Q(*bcPV~aSyLg;i5N-Bu}@C?hevS|Wu5xzw%>b|^14*rO%QLn%9 zZ-QtGi#TsLe~1Du2Q2GN6fuX+%|Qw{L&(Qd7yRYT{rdIi^YLN&)kW3#l(J&)$9ScO zTEne6T2FpC6#umDD_W_+uk|E5a~S(B$`?8c>#3yA_y!3rN!wj5Ifc0BD=eE+A;+yGI_!T!%kvYS38x zgQ=8H6@e_@&O`XqHtxT&H@E{O2Ol1~gY0(No3PY&L8kKkkeSc#$E-K~CTB?UPkC=9 z4odd{b|+2ki(2=evY}uMm{1jq0-YtzOKNh<`kE}qV?uSbh6Tszu6C5MU2|{6&#ioE zhxmf_Fhu4~&EQZNzHY^4M!2FB1k8bMg zp_Qex5}?{%c^)Xk6fp6@52K;{?OgD>{eR&@M<{C#Q8e)QNkKrrTya#rSlH|Rc+LI< z%uoZzo*rNO%?AhVNu?x97skyvx;bBc2Dq^Hc6S>~2jBacEReTQNar#?=frq7k`~!Q z3l!U86Nre#blS!n)WU6VohsFYg?|w{P{q%iNH@K6pFgg|7H`*1k8~t~48jKs)oH0o zCa0jVcEn?0xcR?cP{t{!Rmjr|6PDH~-mthCcFmEkmq1P$D;sJ5E$Qn5_y-Wz1MVe* z{Z6~EQcQAwKaOak={`q#M~EvINV4iMVgMjgi6kRl^G*asht`!4$@>W^(WDO9bMEGV zmQ=g7ph}D++XZQBt|#|I#gBctbdD~af_b1Dq!76xL{nSSA74 za2?aal5eg$-;bqo`~3t>!Z@LQ^>UXusH7$KQMLux&YUI5=yOSrAF_Z}A#X1wN>X0{k6|_(17>#Zzrb}8u&iTV7JvDwLB*+ zeiy1grR@`*qCknRLFf(4gfzQu@k^~~yY;8hoc`AbI1D$^HE;w$nntd6I=WBAkO^0H zVoFUF4IcCT#7PHUH2y!Q^qq80+>U#d^SBqo@YWs|2otyjnOfPA{|v$pXx>m-BMrIq z+wA0_KmdZlse6UOvYL*uWdXBrTPbRey_>N%yNgw0h)D~rDyrViAT@gX{CX8&S|0T- z8D_EgPFD2$f2!2_Yobj$-Oq`~B`OZ~TWkh}sZ4jdu<`Q`czcCohGa}+>Sm+wA;;lE zYL!UPmwJC)9Ose1GlR1jtPG`;hr(kKz2A9LVPeSx)ge1FKuE?g{xDZHdmQwtxt(=*`^&2qw^K$)Z`n@_Py9>hK~Vqffh0YuS5AblTx@ zUp+xBg)&zlSmCzau*Mp?>@RtJBrLO6BxXyEmfymAuDn+^jgt?2I8jbjx_TfZsOuQ8 z@$=6H0)Moss}MH=%la2wLd_qp>k`4Sx%)rw7Z?4=y-Up8Zk9O3Lw{vHg4T zt^YqXw1o)XdiZg>EmW+WSQ1-2Bu{`hUMgB`BnnBJ0G~rotK!p!qj?jp-L&++Z#ha}u_CC+x~z2ZRGd82`~`i5Ui+0}hKZ$0TA)#~041fC zmcn>eT4EBIkfe(|LBO_TUgJK$iHO?cCrIEU*jyNDSF7J8M}jp9kqMEBa!Mxq@f0Ix zPmfU*%Q$>@-Gv4J<+bn1P%QSxS>Ch~q!A#1r~1>?tDWc*T}4K}5zU<8Pf znc3`i6qW354vUqIn~6>e_8&g+K^1EE&LBvl_&Dmm&(;mIq;EhpDivlGWD=3e7M?Q* zn~V--K>0-smwN@FG5A4U*3|;PkQGa4F8&|CHWjxLtGU_9f8)uTInBuXg-f5wKePz`OEiv;Msc=Kg#V)~mI zQ_Ui^qw}p*QnlR!Q&gc*BQNMzqf7(U3z%_UrF3|9F z-eBiZ@h6zwJP#_|=%{g{7EEE4?ZmKR)rX3>p~)}E#4Q93y?HdvdlS4m;o%YSjDfG_=8|BSNF z^8#K>+A5<@f~LMgEmBFY2ZF`*D7mxh9!2!hFF;o=Ued|vRnmI#EbUErWC}6hl~}{Z zKhj2DU|&BZp$O2=bhX7~p2o+CH_SSMZ3MTI^do3XLT{!swM_rT7a5js8pD?XE~ z9e3sDy;vB5m|V!+Sa0ROm#Zll6X8KqfEIk!FK;u$~OXNSub0c`R2 z`=3hu2T7cm-MIF2|1$4hXjG8@V%Ni6v0u=R%#}9n<8UuL+fpQs=V|d?ijs61bj5#h zdm)8H$Q&P`#MoO`;@H9C9n-AvU&?j^Tx4EkaNBI1Uoep>QB4ccR`ZApM|LhnC3AFK zG*$aAzV9RwBLJJABKn~eO!w1WWG?~`wp8dJBOI*b|G{QKyk)wbW336&LImU3Rn0Ts zQ}A3+Ach@p$ykAU(ZXKa1pO(?0)f$|QET1&-q~?b=LP)BJG|!aBp>3Kbxlh*sWL;| z&)?1%s%_?R=#%pu%xC!wkCB>BwkxHky81E3j7S2-re7FZtI+YTeme_uKW<)ubPLie_a=|C+*+1UW;wfkd6rn($01(N`@ebJ5p;Q3v z^V`|}Rr`N}PQ%P-g%*bk?fEUnK;R3TRTI5oe~Q8XC{gnY`HoR`Rk4( zIoSLY0yWQo;bU2+0sO*xu08MBpUXfs#BlbH%K3Lk^!y2X;y-6+Mk;aMG?($gi}0V@ zCn+T7OA0lWslfn9qnmtxr*stu1E9KAMJ)(io+NWPKzl#r96Y@%20b8o8FyC9k6uv4 zhK8e7Yv)iNe^;vSltB#;ojqqOVQ|%UKHH>5l;H*3VRV4zBo4rSP~up-@MiWjzw$Q7dZPHgfJ18gLz!H5WjK*cvhh*F zLh^w=nS%lJS=x^#F7E|Efp|HN@-nevu2?}&-cShtzG^O`GIddwJ&knS8P=MLdHtUm zaC-QO9ziVeNEdAcYfwL_= zM&Zldr?!b^eYV|MT8w5jFoBAkl5Yh~za-(Or(1UJK)(U*JOGS}JJyg`?)0LuoWrwl zI>0RdeXzE3a4zhJS}>}%O!?sqzDI-dk@!ZT6R%4-u?MsQ+v+F9oGz(Ho3&Ng@?{q> z++X5eSAmwldysKvi^w3}wzLQDp~=6ylCH;FpOSlpEa|&yN*TP5BJ`j01Dv99$iEj= ziq&t)q%3$9a6cY&f&B&Dfm1iscoxsAE@I{rX~_RRz~{wi_A^|%`3i!sGezE2;Fg_C z)G{DbsG!`)2Ln^^!0>~lsbi!xsoSEO?;CrXZ0j@&CH(;{b>C;QM;b8$1hdE@i_cSo zDTnd?+Hj@mFmb}2&?8N16-jxI2K)_D_+A%z2;m1J|MHt~Ayb=AWvGzBG6ba65|@ac z?2{y!sOnw6bK7pVOb2kp$#0#6{Xrs&zob1&S6p6gPD`O3I$(>v_q=xJuk2|iW#hKY z8#Ou4{7)J7hS#yhTCY_?b3Wszaiz0n}Tkb8YFA+T23GfQkf-4eL-QFwUd(|e{(r+>%3WsX8 z@u`1`O52`3643B<_rJ^d@p-8Pqq|KdZAZb58L0g|@m=45F+rFzJ7tvg94gUW>3PAO z=!hPMC7N`it9d}PsmKrs9d_aZ52A^0P@Il$k!we&Ze(RMj)6Da{J2-v?q>J z+)A0mfzj$D?$Iu`f8|Pq>&DsfU-g(WFW)e7lC*u_v2uMM3MNzn=#P5UzjS=ryrK;x z+|kGqG#kye;bbpb!N1$)!bf(qjA8#7zY~U3lgYKH)4KyVBp!9z#6RzFbgNen+%|Tn zI{?!D9gnF?&A<0O9HQLHJrAFz#IW>cj6&192J|0Ivy&3rt4GED14e8ymI&aCn0$Ag zK_UqOp14_xEiLLV-}3DYU#fb;2*QGpb|*{K{sI86nQ}K9RH^Di!A#VkQkv@d^@}0% zxd$(*@_!v}2fn6M++BW1);}CRZULD`1Dt*3Bk_m-b&bUIKgaYIpm)JW1_xstDNcXa zBvnQJwgunqDhhYE-7g3XkYrYmR|xDJ-pk(V3(iJ?FgJl?e=Iw-hELv7E-vlfeUuB) zDtHq5kUlal>L!Z%cTdsmFKONnrhbKA<^qH1o0iA#h1>1oya>H*Z;x;Mt`VK?Z6du` zU^5%f;{7*7i*+K~Ez@Z?%D!*`vKfZd@;27-qbL0g?1QRhsXvnjHP1nj&P){?b4nJz zP(-nPt@pGQXRX(Pc3f?$*fH&!Gav)B2hs$t`rucCtkY)NuZzio12{B#irXH8Qk@lq zVfC!!AN2A=J1-``sr#q^V3w6362?Zh%FzBOuZyg+8jeZgG5!5i-OA{KhWAC z`ccqw+j(XwhcJ8K(A4+7gJt=!5kkxw2X(T4tCeTj`2#O7U}^+v=*1BVLvP>IqlW^h z6Y$ELQaD()cl)hct^|Zu7A@nG`?Z`t=gG$ZdmDaBV&b|K1PI|On0v#&a%t*E;vTTB ze($*pG6zA*;#U4w3y^(1-*oBiIKoaP;X0oG{VLW7AZ26u7c;E{WT_w0x=?Tm6^b{}Fl5|{@_*@HM_o^{*3sO;0VwX^f!c+}J)Ew8FhT?i zHWfgL9IgRxksqV}BAgGHLP%9aX{M1dLKjEEr^iUzt?y|FoIV_@1*^^3yR5Ih`YE0G zEY00;VhN`bKqsQEC17B(N0fHhA` zqz$*wC;#&AwBAx^q(|5AvWBWC1JXZqj3q9RyfBVzZh^Wh zdkJ>r!jDc8aXQVodsAohA3bVDtGa)miytb(7dlHzXC%;r1tG9C?!cGr^GwnP^0I*h zW7NZPZ}ZqTf#b$1Hj-*e+QIG=oFv*5+aXZZS(Zg~`)wXmxZLRVR~!C8kwHoUwOWqHoIffX8~{n^IpF5!nJ1E^6 zmNE_=>nesEqXhhMa_R8BJ`5S60hU+9XW5);Q=Fnc>#joS#lRLx1_@z4V`sk8`!`0N zD~MPp`2?%RF$$CnbeI**)C~uCINWiQku5ow)uShPA0)tt=%7_#qmMmt0`8PZpG);G zukJd>(gq>BnxD%;f*7B%gwVhJZDq!)10cbaV6*NRi07jz_o)&7VYsHs4oMgFUvL0olb7{8QAUy4Dlpm& zpx?-MX%q7-Wh+hrCN@2ijqB^qQ7l{d@;~nEL0@eL6uEUJ^HtCTEC0^ zU&Z95n(Vuei1k!pQqovAo&+QiSFZSuJ@~;iCr!L5nxy8i`o~Gd>)p+ zZT;%h>`>5dD1mkvS9?JEul1{1>zu~8J`=&dj$pD)-mmx)C7R*)RC^C8565PU^XyAOM$JP%Hx_jQvyT77mS)Oa=|# z)4GJ`UpEYZ1fA?R5X-;|)kK#i@I5kw^pHi9%C39Kzwumg&7iYdqi$fwQcN7HacUW* zSfu-HOjglCX*;lZN>&Cn>j&1$i!!#Dc}Z2}m{n`;l)Lynf*6rdzNMO}sNjB35zM^Q zqqJIluYvte(6e(&)u#pg<0Cso#$aP2Y#(F7?N_~(6;+D?{GA>RUnK)rR|EtwvcsXp znsUPs9W;a|VV3VChXs=}pU&Q4yqhGV7imFYrj|}re&1ClFc?ppaN2c0Z`}NLsl)%A z9has!;`>|li4bJqN+wtK!j-LVi$~i z7ja-_hk!i3MCl6bc}QfCPyHFCT(;k=`iy2sUdmxGzl?>wSq@UnS|YhTzm6PS0|N1}gJRsS$Av{Ze)Cs74j8{47`-7%em7hplEoKa zVXZlj74gL+N{5BLS=(W)Bh|eL++ypp;dXc+?(Vrx_)Qf^kmrN~)^}VR_w|h!l!BP;`ww&;tX||&Iu9W~LpIKjYz>Jx<@zqSK!+x7TEU;k zoh0dX+YQIQin5VCGfY6K2I!R#DSbD)k5X8h`zPYd$4`Y6U-4M9(osnd|0A@?oygiF zM5OOd2p&R(FmonrqeSQ263AA7WjTo<+qXjyf=oJ+%*qYa@}*`*p<}SCFgdgb5rj=3 z%T6F;#Vc#q@QBd@F-11E5u5w*lXYsAUX3Ou9VffMpned5_%ZqUPdIBp;V_Sr@3>_e zIq#2I)>UG$f8)eYD{p`+FB}*sU%w?6a31t7R~@VMomYHYd+MT) zrAoe>;1v3XnjtBu1cgLIWI8=usUYqZ-Mt(l_fvXIMapds9iY=hYU_AvdiRQxM8h^6 zcaWhK_kc!<+9qU3xMU?xEt?LuGm)GmQhp<&l3_0QC&gzv=elZ)%ZXV9ISSz~^wl0} zxdr9=AU!bM-P*N`)-}F_SD*Lsnle7#*FT60wKD98Ze#GYKwAxPQKOf^gwXOxiOBgqvF$l7jp+mboPTckPjb#zM{*+db_r7e} z<~E;ZMg1qBy-8$6P`!jX%?L=BJ#(B4Q(^ZG1PqR#zx8h-1ZHAl{9~EVC zOKR7nGX8j_D{im?tmlhRO$JMetDhb5eto7}PAo3(pY~9jaAi_>=;?5)Zm#PtqHswg ze)edZ-S;WD+=`@bGXiTC=NLgkM;TFXe)rV|4Jc0rOMYe>9KJB}z$^I&%^?nlb0)Z`bOl@r)=)7{^k!Jn!f6EC@|lb!avrZ1nPs7kbXFAIDPQhcNMlWxm^!%VflOFzwy|N zT_dXIYT)tRJ$j-rY@#%*&+@~%5_UW;5-K4*H6EMZX#sB~N{j_PapPUGPt%;d#iv$D z@=1@BtOSNt)uitZq!IJ7FMXT69o$eMf>-TCm;pHVJ;XNg zplCCr&nT#%bYg!EW#s!<`9`O@7Zu ztBih<%)_#34BGm8uwD>#K!wz6F7kWIX;m^$-gl+7RTG|sVQ!coYt+GgbrDqT&Bk5# zx>lxPHgAvHzAw?X@MjMln5J2dO@eM{ZKO(>Zu0|%X6`G{Qb;iHAlH3GQxeHo(!27L z_M%0lKLuPf77?Pu30Yd|tSGD~RPwC1s+2IpYVytn&}< zO3R6vT5wj>O~1@4bP71*Qv_jzBekFJDP0_IgkfXd9}e}21{~$AiDDpmgCnsvSNgFM zFI`Y^hY+$#i8vc^lN>*(aLHbssCn=>hCq+5K=b!Ic#}F0qhgWR5q@&^zw>g^aGW9V z3W$9cW zN9RwSeiBuA_r#y$vSnu~vRu@+cXj0F$ep-u3Vwj$d%=@cCts@4y=9ZBF|ExnPmOOE z0_IEKR#JzC+nzm)HKw%USvn}6`@hm8deR3Ba2M?f1_OrEd4eRe*d%iMae%JaC;Fv z>V!054?_x^%C7mY6X8}bmTt_;c!6J9+Egvz9>>4k6KixVhh>nWWU;VAH+-mpy+Mo3 zHL|DI#R;3@Pz!LxXRdO;dUr+X(5yl7xG0{kA-)AMp{y%Adha(@t|LQF`Fh@=d zjuk0xX5oj`?nj2*crFHhE&UmXo_`|w!u$cQmz44`GXB_eNlt0rYS;Y>P1L*&sfY&I zEH0OcbJ*Xu(H!u0Km_$3P8}Z0v`GxSnAIs%8lPG z(|6=B!alj)5Sf}VwWU-lT{`OuXU3GWfcR+eO8Hxe-MS5 z4*Rn@$}9g^Q3-)<VbGf2f8QbsO zX8d&6yCD;{J4aPSuVzQ{VE8cRxtwz&E4+V`cCzr%e2xbc%MNL#6bo;dIqFREjU!mp zoSCQ3uU=KNW~|YqKabaC6b%#cPgW@!4&;;-|1Mw}e`r5Hya`uA3!^Rjpg}a<4Q~x4 zdDvl-rh87K7<{IULIZ(+q4+ZS9eNvypTfW*n^iR6houXxtUKX)=`_o{yJCSG83w%K zx;Yqc*l4ji9F~}$kH@S|6PAuKadxTa2dw_i$K9f?#2YNLb}5WxMzsAg!YgrsseR#1 z2P0_=zR*W}>(muo#4!c+ITQY_(W*DSRG_>(z4RTrMqqw+rYRSscV|3UmY?-%V$ox5 z9s8ZI+L+UPez_(1CEy7uY@=lRb1INqK^M zF&%KQ*E%`p<1|ooEcn?N)LB{`pOd))<4GIC!Mjfd7Q~(}K7#2%xaPdHJIinj7v+*D zPj_cBw&B3&_oScIW+ACicwhu(Hx6mY)>K%YdZc!hta2wNlMiO9?O3u`35derXU|8% zNtxJykWGawT6h0!1>2{g@5!M_qv ztjYP6_=`2uGq3M}@dyFXE4%vzW8II#mwUlvDf@j)(gqCn7^$#*!3nvYa-pkSskTY;2(O5bC4qfUuv%n>>0(n} zjUa8W;@<-7Y&O<=g<&r}I)*Z{5yE8x{Um^G(^Puuxh_2x)_wBKvDuU7MpfV=L*taOpI`R(A&C;3>>_HW*3b?$%84ky(Q?tKMz zomwLbSMpMjmJL3BCx%aZo?1P)x9*8t3x(^8IdU&tye341*&abaQ*gQ)se@IOt*y+z z$>5*9Tlovj?_dFZSr1e+o7SG?`Iuwfhtq}2?<>_%bdqUr+b{_R2=HGwB0EadgN%L> zPMV(v;%oe~?pTy__C#^HBOMzv9T?)V*|NDPx<*w5LAb&qEL@l|JIHRL3*?>LrHN47 z3U+EY%aEFnR6gu=y%Y1th6yf)7bKY^w2d2)y;n%J9?{HWQ1nTsvd(&SFrVJhqThqv zuxgm)Q_4QM45JndM?1j0oF<|y;P@`f)3|E8g@`(Ly;_ZIIT0wLrwATb)Wo8N3tq$Y zixKD`Z*sBM{qmf=*bb&)2DfjIsM+m)2VP#Z5d|q&AWF! z*ZU!-V|)R3gvDR+iR+B4>X7JF$slGL-VTR2)ApCVNAa3zj;_a>0j$)Z`Z}wxZPoV! zK1G+qqP%teFQX2wY6ry0lOhU$|KKR7vfg3D#Xqt_vM zAWCb(aG4^RPYPQ0t-)ydLq7U9C)jX#RC7v8LaTBj19b|m;6L>XKA8BdXz1t`e^M9m ziK#=VSGxK}q^Bg1sw(lM3JQ8MuO>z7PSq(p`&*v4Uo@CGH}WlUX2sDJiKJr$b?ZG4 z_80kA2B4wcTHeO^>@Ee_=EC;55tR(Q2Dl18;;JtU4yJ<&zN{J0GiMJv)Fe?xDqny9 zq`lxz_LmVBH8?E`PDeJkLOU2AMeb18j{oDw2e!Sl7$MaXozV)V^&^p_bLTX-!TDjS zo{Ra5YfEE}!D*D*2hn!&o!bFv@_bu&4z-aGwW>5uf6JurujAMCCJTLVFl3izU78A< z{rw@ELk$sY)sDx`M~#Tk3R;ToGIJBfI!#}pgtZ_`KSFGOxZ_c#to#b6j+eReLFvOs` z79fai>m`5*us**Pvk>;T95{&AM7hV_s75A<-guTIDA$t=HcLPEl@dg1qeqW>E)bzOy}yfh6A%?uzUOIoiGKu#s;)3zrnzM}1O$`HW*?5Uta9ile?Si z$sS)psH%UrdZH32nBKTH9+c?9D!y;>Myu@$~^X}UT5iS2R&uaV_F#pz}J$%}7S(J*) z#Kx^H--cz2ZKH(bxTOdd+ktp?)WZ}xy1^v7{3~LA;5RPSXTBq8Bs@YGob;@FKKFe8 z`(I7vilC8GHO463(;)s63px?(Z&}QEQeQNII=z_|aXBhuh>Z4X$;WmN#p7U!0+=+E z_0%oNgU(KLp3!m#L!G+^gj=RFe*9Z_{fh~f@s=9AA%Tn1Lr6jrSJ+FiD~GoIwgtuh z=T9Xbo=EA$NV{56i}rS~2M2X+t-2<6+Lq@#_9#vpQf{Mx#|G?3FlFIUl+aI0Ee$=h z)*JVSv8p+-Z8?5$<1i(*=@?8O8sEq#)BKKeJSp@SWDqp8ss0 zw))Se!n>Y4rJ$-Qp{G)agb@}r8ie=l>#_)+iSuG*E_1FTLo{t^;!mN5IhKOc*Xbnj z4<$j1<-h;lxj>cF2+hRZC3iK2SYhSt!o=_mg!eDvUR@1vo|8_iQJ9fPg@OqpF~C9+ zBut1%5BC$!sq2kXIva0b<-KIR3ZX=pv-b>Yr?Hx0wDcE*5T_V6_Xv}>-IWPkUr#$@@jF&NU_2iMe|(robO#thnk$W^b87)%dx+5Rq_FE1x1AF5nM>SAj zw8|>we8bqI6}BXxs5rFEL!S)kN}LZ3z{v&^IEzQme_uSW-DG*?IF?gJ5M~p+@rVVM znnBtBHx3bcMa9-c0Bekwx9W~wKs7I}6H#ElFAV1H!Tsm zz8FCa`tJ;eYKC@R@UwnN%B1>#wE$Y$6>^9W&O8XiKwb1WI|_!@`47XQZg3j5tPp>c ze(?WC(^qh{**4wc1P|^K++B)8up%v1T#6RA7Iz8m6sLHR;_mL0;_mM54kyoh*7pap zvaXqXWbZvQ)kqxRl+QKT&Y#suC3xU?^RXeZ^q2B4_2mzpe10A-yd=Euewv)fi^TMV zwS56YW*-=CrdJiWp)L?hhZaBZuNVE&)lJIy+P#|e70B81J4x&Nm+(ZcWW*yo3Wzl{ z&BQ_(W#AEK1sxzf?s&a$W|4JoBw~X0Ym8Pq`1l{vf3`=3_2)M_xE^RMY{QKI=$|Nj zKT)QGp3M3L5O7$jz|L-X4~Zjo-;pQLKR<61=+>b0P7iC3tBjNS!*ghdH~KKdWFupS zMbpz8QX*u6b&e+nJe8$rpYlmvP7E(R_6FI0O$+$*@^uzobz&(h48PAr_lDQDr4vPG zchNGQ9L{``y!hZQv{ul3>hnRL4h0xpXrir|4jxpL#N8;x0b1ST(LxLbZXc;QlvbhiQf@Ab!ix zwr&-7ZkLL;3l@OIzC{@??-<=ebls-Jk^K+9v(PZio*H~Mi9QunS~#W7Hb_-~mwn-V zk=9kTmb)hp0rq~B`}Q`Ux>Zk%>>hh0;fd2^=<~tyvfb+a-l^uF71i?Mq@MbK1l5M= zXvrtnI|;sgV6k+UE=F!scl^PVJJEMHdeFP|D6KbICX#wV{{%^NDm`Y8%eP%LO69?o zq;Z*svG!7Wiq6EgSb_jt`B(*I_VB?VDkU>1J?pOB!S6;YGg(x9Klj0lvY-uC=%xcO znFD`F*?B;x*4IGRN_%i_Ka%L%NLwWK2~hvr>|5ZV4w1_1e_4MfN`g<-3cOy_R(9uz zqDe)5$`KkUTLe0{VLBUk84C(vq40jeF!>jUF^JIrv*~Y3s7#*2CD!vdKH3Kq);_yC zc#g3hwTgM7_*W;v?*bo(ox2+FFf*cENW~?-Pmz~B@BDC1n?kKdVzc+nLJw*%4pY*@ z@vew2CcbDQ3qtz4aqm)uqzJ$UnO~c6P<3qt3vN~B1Sg|YdTC29lTZ(+kt@#IEVWWr zjty4h!jTEmm$^2liJ^yQB1<_Ri5=2y7wq?r427mh!Z_qZ%k@t&-XRFb2*~m8e&a&a zktzqI@Ld)x-FI`njCnLa2_auJXnBzer`w*xE>|T18vau{(`4KDL7e)tv&nk?i!H4l ze%ovuxH?<289{qrk^RSVyDfRC?d+LQUFSyO)70sajrxxeo4!9Hx%$1=*0%h9vg!k9 zL;pWe#sy7woX}LYfdlcd$a?OK=B-7%hM4EtO|U9j5wO!Ro7yGpd~`MD4d^G zgH4os6mj-edwSZ#cIq8^IboX-?%df~hv$(&p2F`Kxj93H2gfd(!wkY(V*-{B^7c|j zzWul?-fKP2*ECX>MM{6_3%u$ruQks>Dg;ttb7q*A@q4HH9Ad3Yil|ZDf=w`^n3uzT zrax7xZ{1MqqD!1OiD06fkzN*@LR zi?Af4*dZ(LbS7+PEYqse91QQ+xX=O3~ARKXW|4}s*z7);9kWS%ez zb<~O0%$>^8*<+~pv`^m|Ks*1Sy5%RT6ZXtVwRF6E@3{n%(!3bkK0iX3kO^nT(FcjZ zU(sXp?BDl9tdDK(*X*=A?S((T{}?lnQrqS=La+rv07QW}uM_v9?gudiG`m{Yy5`27 z@EM1XsppbSApfNSgUF)Tws7GdLb}!rL!bE3c=h&(F2YZzD zV79WTXHTLN9-Jn%N)pieS%K#Q+|<-Yv-o#ztnx0Vj_CAy!Deaj6gPE(j=CwHrRu+<#rWjPf~=Lg~!gzBVA<1~5NWt4GDhbYo;L!TCtzrQ_H zNWUELiot&BcQ!k1j|}{cqoves`ot?Y!%Ghi(~d$gz-{9o4^Qf8PhHYfFO^H=+tK{w z^3MZ+GUHs;`9Z$$D;Br=PlO~%BgmBw{0Cdi8#0MeZi(SZ$zitkfww3CWiljm;I= ze|LoHcqLOKu*cyzyC^QDkx1ChC&cO}A(iNAbBiLy57T^fCl)wp2?cQy<1)F)`~?_m z)~BUx(kj(DqpBw}H7^)KB4<+K=O$v^nMf;CM#4QrC-_2e7JLTNrw#zc#7F;n$#h?R zRwvteJC6CY%qQFR5!Pfr-FfM3j9qrK;)ycGh7kCL1~q^LSgZiJ)tf`{m`8OyA3qW5 zJ<8}|ePOXMF0WG4s~(HWg?>1eJAeh~&E3@cP8?KMAiTMS#zzWcvC*db2ThTOK1?C> z^w{T`AM&3|938%)@CuHh9h%f?Yj;`+PMuqr_FuWsB0%OOQy6+c&ukcOu^RInH3a!j zD&wl)u;bD08i=EJoQ}$|^JA|kjoUT{dqAHWV{*YUzHIcDyKV^=ueR-5!9#MB3T-KX zh8?Np1-;Z1_0vsgY$A#{3R=gm(nAu@rrsEwmO3%2WLP0Ch1l?FZTt%=M$n65^`Sq( zqk`a#t|+=L&5bU6TDkng0N^A4SvkHsbyUqx2OiR=-TQun(B!8h&=>rPTXS44@GPQ( zhaCt@v+V;tjxP#=x-E6^uRkMu2^?}5ne+`2gHyXdF1BhNz@_!;ty2bfYTNE&aCbm( zUs+hx_t(P4zz+oo!>#JMNmiqu=LRid;;%laR7&|vhElc1yrjLoM_H(mkbCe7eJ55j zo7NeEat%|A8OBeK9i-eT&BtrjR&qBJv>W>g_dwDIBwFWjy7J|(n6SdBC>rSmS}nUe z=>#sB;2c$u3KTZ*Ku2F*LbDKSkEn@ixm4OC!D#yBL71N=`C+s|bSqz#4Tnz$H9!d5 zWe;XFi6Jtc{zUyRrF9>CDv^pmiF~=yd&?pF;E!vTouD^LHO|$HjRP{RV3aL~ow}Zj zlwCHF($`0y^KJ{n(%;Cmn{~*5v;e6G!Be`X&3N*tK65m(O{p*9a4-`i_dyV z40C40K2}kJ_`bg2{2u}cO9y)+pI#m~&F27Cvx zZ6Vas;O8oZCMZDdVcF69+aq^uZu4o|V?zGdM#({;@W2M>^6%4TXY4j?QO`Lhw1Yn&A%9)7Z!O@b$>5J&wz@{_-B2`1i z`6E@$E5^y&)MB;L03?zJAsPfB5@`h*v9@?bjb@}HZj6~-5`9bJAOeQcNI!8~y$gov z?pG%)urLA@^BU@4-(1RE~J|ptK7*@xsBqTx@dx6rk1kkCuntg$;WV zW--cLPDGGS{^R(Hw$I=~RTrl8JD%e83skowbaNf;?7S3P=QiIyo3PoL$U4CHjbty< zO}9jsVg68rWa%q9>~tusObycf)9!pY`AiNJ$&Qjh1SMX0vwCMlI{GS}jxSdH8bN4A zfd8(*Im6JC)T`p74y_}#!~e6{q~8nH+r`;vP=j`CWchb8p)LgPCrp#3!c(f@J$y(QXf_j+O(yI&8^7ZzcC2Oqc znB*Wkc;J#4Ogx(pmCA8Wn;K02>yi{!^QoSM20XUZOGn;;WT@m_-RRoxrZ#6sqysG~Ipp?G2S2)6ELeV`R1|k7bW@wU7#&;c#V9|F zEP>*+R2z&S>6`8iPEL1YWXJar*}oiz?C_elyc?$S6ztR5sT+1U2X2~9^X>KgUW>By z+}E80MCZzmsb1YW>OZW-H*5O<*;ZHJ&lCp!HS46w_x0-Cc|taIfGzms7VrRha={|EBTu)$$M`Z(5n2KjFtgO{Gk)#%JQI zRO4l4(Z?(x>3;=wtq821eguZ3qWEf7w>L$G@!%Uz8j6l)?t{N%e*U>Xh;yz}bFOua zP<1%D4>%{Rc8cOLi4J3M!Md5)f`Z@8)|sS?)lg^;=L($bcXRAnKsOg!jK9mpq2CS| zXeOke!BVyWusj!gLXLm%kufH&2iojz6xSP-+)V6_7@Gldr@3%wX;9d8KqN|*zcp)#M_kKKE63rxTbCp<-gMiv$z&#&Gb9)xi4$Ub@dxr^Ci z8;}gJvVAl=WXJ9K{Eut8*^gQdw~F5RuczI^;-8mSlK+D>aN)+NAYs1!n{en}!q|^r z*TLPM9>AA7(I= zm}CQdkOoYq(mPotQ^FT8BsRS&oC-14mrEaykauCR!x(hS{_QS8x!aPweNqBo|6HhZ z!GC*rr94^waexf~oF_L0#8XXq2}iw+dl(+!Hsl6H$HQaoL9tIS%S&`!6wmcH6GSM5m-Qo>{kI;232Nl|nA(YoMpNuQXwH2f6@D7fPvHM3HC4h4#K^s7jbPj&~0x1YrhLa?! zX@(tn32xbevy4heNFNj4Qo`dq8EQpcWdraw6G*~s3zOyNL^RMLM2-}6`oNoL@Hm|A z%^N+Nv%AD#je&A44K6mppjeAEjARFQ6yj=&5d6XF-{R@o!p>HzYU(>D+IalFLC7Yn z!ii-YOu(oH_Nhd_5g%s!qR?uLY?xM%~MazoCfCNd|*@Gbt-iQ9_d= zn&;)fVO7u|fixJIvWcHv-}ErW)@OG`Q}nwnzyFru%2>s-Fh`|!uUfm-72D9;7w(I~ z`29C)#`~!dF)RxlFoNc4VFNfyGxB)(r_oIFnZpHw2h$Vd?}L59aPO9F>gg;;2T`>) zy!UE*)9MGk*k#ufAkxwsA)HWT$kaN1ljxF*p%I0E$6qQ`SW;{%KyC#t5_MU=_*hx1 zwW*EzZMU@`waZ?ufbO)FVkU_bqT0=Mcuk>@Mkv@H+=T)7LIXJ&=I)C&&O5bIU-8~! zMyV067Y#OEKKRwJEx1K2+VULMtbT+aK?c^X1%3u>#p{UuuW1nD1}E9&@F<1T;m7iJ-=+Rb%^SMd`xGfD|D*2oOrcQ2hPnEn>z4)>%0({7 zNO~KM7m4~#@5HPh{X?lGz;_jIN$V;Dj>*A&PqOHJTlDg(*n;!ymYBUa_^9a;v|$Sl z8#Xn$$ip;xO$wf&shGy4*0k2}fJGM)4S5jy+%bRKo&+#&*Q$cg_ZI6x88eSv4&$=% z0e+am`~JP&fg-VyOt{!{1%W9DN(6?%NCGhQp5b;1P*j-|#O=#m?2pUw5EHQZxI7)_Bvyy1?#6&tk>im&$&zc7>^FiD`F1T=Q~4_!X)bRAICQ>`r+rjKCvFJGSV_~ zM#FirD}t2I?$&`52fTQ%WfDiyB-?+u~)E_c=Ok%EX!N=VoeFRwb%c2Yzra&(Dw745W%u# zY{w(+1`PXGS?7I&>a0g{gc5$ZL56TyDgozy2%Q8DghxgeR=zxMbfkA3A0KbG%*+?J z6pmv3;zCWHu+IoS*rc<&1+xmtpgFx>XQ(7WVfez`5vL}a4HM~|^@C--82k1N-ndLN zUy?f@R|QPJp)mN?_k(&J(lLU#sniLm?n#u$R{ZDQPlhAYwnj^&??0}qUw@3FF*xoxML;kwI|g}0NFY;T{(+pJ+Imfl2mMCWV;^z= zN1DFx`6(r4(B35JXDMjXePlBbLvCJtTxdHi4Qc#YmWmx@EG=uz{3SoTPy|BJ6X`y( z==WIOZ|ID><)VUlB#Rz9{dakmZ%qyFiISsc4SB>H=1nG}iDl6N7QMO|%mYT~a06B+Y zOy|P{3;rG`}vnz$)Rj+i)Cz>rDPhepD{-LK*=)<`m~x!}q4+(_iM1>q$;O ztjGyg3lX+PB0z=zMW1jUo~pwCpNpje9Z^Bj&NF7gSb>A7VVP)`Iul7cVqp`Ayv}Xd zNP#L~1w1tl*FR1MB&eX7W<{@mzeG_?4bzZk3pV zp76LeVG-stqH}*N!@iq=b_t>HN8N%DBt}b8jVO0{_RoY@F)Bc5Z{@@!t0};4RjwjE zDBsmKUP+e0?#InV2F4^QtF)gbWm*vnk3^;vP=q0e9?D!n8Vd;eMMiRlq_p z!M?BwRiR{EHq4&|1(fU`+^t9f|N7vwBAkAx=3MkwaYCL+j&l8D;*?$I`y3re`T)6r z&^vhFTdYrh%q3;Z%x3?S_;v9654f5|8R|6oto#W223?8SBH#rp!o!T@vaQF>4}&-4`KbTZQ@wIsR**QV_+ZV!Ao;$tP6o*} z*O9F$SPoR+^B<-e*8B6UIE#629vf(zmH8QZ@V2afT%5eSJ3E&DWmTgWeSeI-r)zNc z;9mOn1g?Q1hm;y5-GvW44`LYXr#a6s+c9LT@rtd>N(?IvCOPqX|KR%`6x&#s23aTd ztahPnM#Yjl1(LX%9W1Q>%J`2;LFXd>r6Qy)spQy0OjUDSC6)I6&ik6pRKxCbd<*Ll zx9+I#%_l^UlU?yOWD+WH)IIZflC99yEBQK4v!MV@?`xgS0$HgEVQr&Ys;N6d=Qv=i z?cN%ZI?dTPxG>qU!D-^5Jf8SLBkIsGY5t(#E3V%7=q_iqCR?7z+8=_ z>)P2nQNb7*G#e3cJ017cemib?>K?@JNM~5_^~H>m9WnfJRyRs+dV9t+ z*g;u?odQG)|9utxryThpL;-+pGvRHC=jnpkHHtAmlz7uX0M$l*vT*Z%+hZ#G>WdW= zBD3*=m{qABH6r)}9vaL`7%; zo3%>nU_%xtoxp_Az$_Jd4CSFXez3AuYn`(b-S08B33-;tEEl8V!8K5ASVNzl?(L6d z-8ltd_7o>a3Em}!EP@&zub-JQ^Y^xF6b(NKFt;*OCAS;!HHg9&Nfa(zxg8U#jD#cR z1XsaWXGQTU$GkF$uh$y!dsJ3&SGh~?( z^ciEL8UP%R4Cm;hzV`%G__`r`)_XVz4*OYMoRQhNvS%nWDk1k@h!U{=<@}Fq ztp$8Y0^;0nDhS&Og1Epm`z^^hChHNjL3o!>i`$F%igZ~QWby#S#AM?; zx93Zn^|ObE0_+`?3Sai8`~xYnUHu;BNii*@(K9i4IW%DHzz&;BxdS_1qwVvv<$c!| zDO6Z2u>aV%ob88Xz%iNsa%bV@SvYItoDMZ)%%X71C!OO?mWwep zu+-f1pCWxeXL5ybbdXOD=)(;4EEMd%K5e_Hv+-kmQQ&q;r2gdmD?QD9ja_c?7%c={@6ITQmJpfPyN#nF z>(4ZSH{0y1#1k`4UA+6iJ-njEs%IutP|{Gud=sP)*C};2cloEA5#b0Y07}V!^yVUX z9F}Ri`h<#3vg{0F16_2QvXfW$C6?Gw(nV0l+7=pl|DztvAwaI|Fb_jO#`<8Ag7*EL5`3`fU(}ZIT}n`66Bu_xQC#XHtSbCA=Y0D9<5-XTl7B zD;lM~h|1;e?Go~~@(GYelVn@nYq$bP2%`!GBovqOQ;5#6O|l!2&^nKV(!N_fTDElW z^fR@VfTX;PrS|qNE`YWxH8`eUGh(*3S}+Q#3B^k?_o+9mAi#hxX7@%nz96ImuQRG` z=Ze`4!Jk0p^%kttI%{vL;a+uibn@p?OMKt0%zlQz?6RyPVP>QbW{H2y(~7@KeXeub zcHJAK-4;GYOM+BL;nq~CA+E)l8@CZas^3B4_LTC2tEOqLu+}j^lP&;Q+!EINlBQB^ zdAdUKzwiMKAULoY0Fc*Ov4GBQ^oEuU?T4!ss-5h!m;(!6xM*XTdu!Ium_qV~HcB8< zeBs?vgX7E9Mr6m6DinAxH0Th~HHVl?VQq@S>3CE1O^{o)#XV@H>CAH!Cb!FCX{@>(3EvnT#^oknyK8910WyosoI6wB0=h-~z(tc0F1N;MUqY6w1Pr${FBg3D zQ#R2M&QqJOh&5gk-oCg(!!5U$()bOmB7jwYP*$Qe!2W z#CnUQPtQE0!NYf*{?Ktd)h9`Nop07aRM=SAu3e~yK12LkrSNWx=VZ<(+vCNo2~pzM zLOEk)XOOlHDQ?kQoW0N;lnsrfN{=*_8QYb)7}|hv?=rfD~!cmNWHa$NXg;XBsle$oi7R3vIWf7*?_NJJ6|6cyFMGzb|f#oUK3M0z&N`}g0X@vCWzGF?DgqaSj)q=-)MZbaqH~Qu~rMbSHzQ1 zFx4Z68ikENzHqf&BrB*b)b6!@FUF`?STA+Coh{iPtU+--oVnsV5K? zy#L0uL}74Q$=3$YMI)hh2iVyk4LI%&6(Mw1Y-@1xb?o@95NMK~yt z(fP@E;+`;>`W)@KJ=cyjt>hDELkQu6p)LC21bNY%ehBa2_ohagkELz^MHvr<8#jo-^fK?GLQQN6=@DBv3B(SoA0cjfW1TUy?nPWTfYWOM_khAO-8!CfCx&)JX6`UPS!h{ceD|vnN-I`*?#h-5Om#{6Tr8y$ z#>J;akBdFR2?`dXe}PB7?=Dsy|4(Yc9~{GGD1@fZj!ap;7DfKmC(z?ZGR%+~d74hO6Wf6y1<0#y~Ij$iLmZ~meGsC0u=`4QI8M)YpHJ@5wor@I%_ zAaQ&c@z8Q8dLX-><)UdFPXF7gPZi<=97V@^J0c>YOe(h%#SF=4kd0w`v*l%we5XWO ziOl7AeQWvgUkvSsK9OHy*OYgD_bj~4{9#yp1E1ta7r!BhWCE$PwAvQAopb1d(n>01 zQJW)y)DoGj9FktaWTMbRxu?I&Op78kO$E;J_yL%UZT1zmz?%}_WT{fPLdET9@K&<< z)>6{le{|jl_<$k%?vG^nk>Ui|KV;qN?^JO?UvepVDSaQpEfVf?{?}=5OZnd|hDl)o zKrQh|o!s;-Ars?z?^un{wJ+!R_qrncm7p#wC0wTyFHS(eRRE!PW)ukNpm~p5v@F&;Ww7 zK9WGuhA*%SO-v+pL`w*Rn3hh?%lWzBmsKu$9>wGTCvA)Hfb|r zI=iF1VwkM3FND1LUOV+iLx)FGz$mZoW-Vb3_Ll-UyXVuTQj=7i zeScM4NC)JizUFB5Fn&Bh58VUv6#{dB#hn0ca&B2I_kaoMW(N^U(2*l9ZDag zD?0ehKKn30@@@i}zBEx(K9u!4{JP#D>3o=SbUv9OSoiaTi6j{BTXFkOQkZFdO!*!p z-sW}9dWPcgV8p*?%BGozz-K|1n5DJ7r%vyn0%bZEA|!l3kT8$Os*%b37w(#xm)w~j zE6^;l&2TiMt&tG9-`0CUxqNls*ii4TFpGFRGLSDnp{W*V5BD3Z>*c`ckNdC;j(IKPG8|x79ZPaw4%|l&{Q@7xY>GS^j)q| zVD9jn=biomP8HT677VRRu4;)`2QZqRfF*!^y||^V8{_zdIjm}nv!QI!*3|z6{XA&U zSAUXhkdU7(09rZ%nu38P5xSpDx-c*`7?g(w2P0>QnVG7^*lr?b(NqlSdn0y_t?LSv z*X`Y*BP&W-9|(1Hl1$d6cVoqTDFuGoZ;za=3wzM-wW6WVY-Wp3S39c0+?^1%+Ud(7 zm#|>vesi*Zc~YnUew|9hEdr~fB)TZUDjuf*_Pam<*41Y+rq_igr8@^90 z$HQRNF?3~jg9jm#7zYlDBtYr??V0K1<$ElhI%Tt%cb^gPKK4+3-K&lb-qM8@07Zn+ znQ1EShJ%GNr-*8ZcVyRcI9C?YDU!;wTXRJWtDgZf$L*KZv{-9PpJ50D>%0iU zItK{ej6ha29&pfM9OlQ5>eu0Lwd3OQ2dYfW zPK!X~6(`$4H4qh<75@*gK&Fwv22-?sh)E^D!GS;(xm_VHU*irBN(me|xcKe#f?uC~ z``_9-MY#X*jEl*KL^rc6YX`%&doo}2R@kBwk%ec-({sQpb3l_?y>0FQhxoU=;?#fu zDQZx>idkIgoxBen1R(NlC}f-MQAK3Zl}YT)o0vW-Be+fE=fIbF`&i?UB+3U=ph zIFF&ZE{}!QUF(H`N_9#t0hbITU2~#C^QsuAUMQd+?lDj);r3BO>QOzScRm?q@-EHb z$3aCgxSV{R&{3m0P9ZwEe-c^1_8Ln6mN{ea9FaHiPw- zN!o!@LA?0P4c;6!SYnkL>OU@#or-b{(~Fe`(uFx+Tin?MH7gAbIDMd>TXqYOn0WEq z;MZ1rl!~wNJz8Hi2?1_@x?zaWX=2F!LOvs-`-zcR^R3QG3C(m0qvWz@;xF9$@TY0M zrS131!`hcL5d{1vY8YzEJBY={{bph@v!43i{ny$EJJ&Qr{A=*K?<4v8sgMz0Tg4FpJUO*5lsBIea>g}0qFHos zL9|eikV)3g#;Opj_v%WkTImM9f@^wc4;D#OjFCkm9@~A5fsC1`zP{(gw=f`FK_6=Zi#d*na}b3X_4wISx#gN1J-~oVe+}^h0(o&sc~+v<_N3ZSBAvcJ$mzr>9pb#a_G}w`G@+7gsirXcCIqm zx}QB76Wy47jq>sdsr^*5keywL8H#02O%oKH@)aXU^SIe$_>3Czbf2`H!STa!6NixI zD@u^k*`jn>zf1)K{*f?9T42i2X4IJWJrh#o=W)|&%OU_h+>t0uZ%DP5MBnt!qPC{3JTByfvZ z@Zq;D*;tLkw#{3(_4We^`tPE+8KXX)j!l(`qx1F194@f5)&cVEco6rnXsCtTsf+cm zfpCfG?s&^7288#r<{f?*=o|t%k>mmLDBW$4w0&&=N!Wk1KM!`XEI@~Qk_0@YMmghh zPjhi{Ep@qaE#>s?OAi6V7IyHh=V9X;oAMNL46M#P6C4Y-f>o#_QO!5z>@a0xQG&ZS z(tgJY19H2Shc0IC$X-0P!!8|yC5o<Pr%Et%>#YLlM%Ma&jJK(pHXZh6hK>@@n1nDnv-+eVG-v$Iswzvwpoo$1p@&3# z^M+td3vcsl1*gOi1Qq=m3lxe3rc+af5czPf;h+0s#)f!n#(@=ruxY$|RW+66a|@SW zHpHWp50O0{+>*J+`4L*iZP8?!afZcPl#_FrLDGlFiw%Zf>`((jVqjzdd^h-S?=NCH zjd)zus_tG(UQG@KVJAh$De;Cf>nAIE42;1c)=oP{^!7znmq(}D1#xCrh<8s?G#E%7rk_@}2TWX=W3Zd~nG@?r{>zuxUlz@yG83z0 zFzYk5-`(x)K*%Q+$BizBg~olA@)1$@kACRnLNGrWM(geMRB}z{Hl=4vLj3u%`o`QP z%|}1*v0+S(>4N~diCHKMAO4X_4)+r|R|ugTp@WM{8xRZsh8h|m=WB6G^r6kI-{?rf=50_t-dS+%sEw=|@&?8yHM}{bpM+``_pBA)(yHm$8w{%t`!w z^?au<5cx`z<2?oL!KLo0y>=Ac<++@8KR}Q8Ab8F}*jcPlr4kh!_R#F`PLV2d>!Os& zO9`FS{MJe-eu)3@_+-?7bvu_1!|i-x2@DH0;yxzA7y8EM8eN~qCmqcIow&6NUQ@C? z?H$A&M4MpMdo^Mrr-MNE0hO^(#yWT~I6;0)ZV`awbFbhy>vcsA3B&U|rBN@_c_#O0 z3nkD{6peFw~7^ zOLxClRzr6JEVS9-uVp<^oE0r5r!S=?U%4ZBSMw2`E|pwN9dPQm54e20$GqLO1%G7Z zgbErNV1xJSYr|Eu*mo3SVCivi4RIkeMO(COKV49x; z)}YY;tVn7jn-un&731IRg$n>k`o&~2AuTK-Lc%`F1I)=dT6Ezu)RXD4*ttu}s{OVYFoI(0b!+<_#MT@rEIg%h-(XT!48%vK(hT(S1u zg(h|^XA+FaltB7lWPJ8~VE7UUnnRF=&8H-QbdDVA6@2maJ zITjx4?KU$GJ5T&K7tT5L+tAY$U@j+_R0M?KH6qn#MId3-FE2h^(B%aL`;KRwBmB7P zyaW?R(&ls3Hm}z?3bQ(7ktGxEz$)n);KzllcCOH01x{tey=s&igITwd0*Qw#qL6=! z1xdv@&y-&Ku=u-|^_LbbtZ1wTaWN6(ttRJBjVaQm(R_D?c>`-+0(T31B#I}i+Bkf7 zYmC$%&#S7cUWL!Ej9I%nmfeikeu&U7rg@#eoRwYrq&5p^pj#Cp;N&8hne-ABE@ z?<=7Q?afKuuRIZPEMS79eoyY@Nat$ej8embu@`l2NfPI?za03@|XJC zf?H8u>$pB*kOUwV0)q`v3S9mE>usVGExq0{EWX#5KQiZ!z25PB9}OrVdNW@XNHE4{ zrT+wkkRg08(@zc?Bd@Lc(FmW+>L$y7Nd0Z9ZOUoPjN9pEJkzLF+uiY;iGWRC(IVX% zJu_v@+jO^oSeR)sQSrZL=8<77bJt1qphiidfiO7?gDrIvSrtH$-Kj zv1gzZD#7lxqAMBPiO&w_ybxR`SN$MMLj4jSj?I{qlfX-8USOilf@it86D?p{N}Zx| ztYPK&OZ%fJ2Y4v1$A(S^4jG3AB!O+DQ$1lWr@pfM1jhtAlnqYc0AS!0>wb75 znH6`E1pwjp6#W6gNIljEKC&>qLDLmN(2s}LD#7Vs=e zr|#t7N8C6%tU~OF@FPK|av0Wh)H9)pPet&;RHlTA23IkAga&gY7ndD$AGTjacEAiT zfv@js&IFfRh#}%^W{u{k{%q6#@trJo7BHwKNpc!kEu*OK=J;qY+(%uO7g933v5_+ZCeh3zcb>8m2N<(6Pm_$}iL z4v`(4y+-DQr8S>^sw<(wVdE;S73q`-)RXJz*f5=}P+!1D$X1f^N+5&?23TqU{&?Gw ziw3CxNB5~8#l}Uh_^q{;mMNdjPVv#{mp`oCg={ekZKK#aIs>QDh0#=BmZUT2 z)!P%DUln8sM=f)?@C=sa&O;MospR_jSF6vRMB@r97_FTldD+{{`c;Kp}|skM3972w$Kv1s92#~rQ6h&p!) zK>vK+=TrTeKS@DL_1`y7=`=<=-P2+(nS!%-@?Rz{b3cEXN{niuUc#+u&C_)x)<5?` zGq%YFu}Ib)o1_nz9$dbCXPPVOH~w8t%C1eQ-}`&UNbiBe^-J(oo{LD$*S+015r{t> zZt<0r&IhEWt?pzk*{?`+0Kxfdcnxt&=3e6cGWlAZe1?DzvPrL$^24ci&N=#jJ24$xW&#E5 z7ma3hEkwM{#1LzuyGuVj5{c9atcb2unQeNi*ljkR>WBA+e%}0dsA!!czhCf^Tdf1E zQ>M*FsxfcZg>J#YYc~m#AEK;olT9Kq`fQjAw>wL^9@XeEMIlf5qB8G7{hfHgXVOHQ zN97PpYhiX+7$fDoEM#JnNy2c{;0jL)E)noH9p~(P%KGJ1kQ}?aJKpr};W}}($fna- znxJJpgKZFx_y4p2mDnv!Lz8vYfJ`9(7hUbe&yR&TkO&1qx#6CXJ~nMLHw5h3gw5>C z$bI3jQcR5}9RCft%2g~cLT|d^x zKd|F(rW|J8%rej@0Ik)g;RnTK6P_fW5EN~(;rjid5jjE<2csRK#9Y)x!E&d{Dl9r$ zpia2_RJ~^+%=pl9jaQGZ?nHDW$8&RN^!1J-Ls$6GI!{P)Xw@KuJ+tPEICiB54WY%@ zqRFTyLz}NuMaUrwa$!xat0(VOG#c4~ry3%4Ut#o;}O3BJS z)H5b}av_7He!^~NDyqalER_Jo+*rkT;sn6udQg z15r`^HH)I`+>vo)d%!auBwfyBumG>IA{)qLlzZK#J0wUDQ7pXo{B9z2+^EG|CCWyS zQFcdb@n^EAmb1Q&&5kFtfScqJC!l`O!wiNtc!A2Od$pXW$4|+~Zn#4kH5H z@U__)LM$qcYQ|gZiCL-14XLzJ86uylqHuI!GOT1`IgSwqL7RXy9L?ko(Tx@~|25v% z!9OM|5s3$5S84(}l@U&FX^OSpI6ge3!MfTt!%rHF{xplEcIs`@_{7BHfc2(H*|~uC zgj-H+g%;>ZX%Mk& z2W0|6kAUNJ4014N6lYCmMe?KC z$H5&K9uVbPg3fBWX)V{;yJ_mtK5jbY9M>)jF;{ZnU#coq7p^RixI3+Dk^sy19vZG= zLCl_{w*a-ard_SGXe#%X)z`l-QMFhq3tn>|E3Z~TQwq$Qj`$fd)W2u2QR_a0hGTeK z3PyPTW^8NwTMFY>hZqmA+d1^L&NlM(d_(PsV{{`h?zwbwm3fjL_-7?w_P9sC^DGO@ zsM<&;gaKNL$#%Uo4=UoAJkQb>ECd0z)*$7(z`*IptAwaw-b0sMNZzQmvG;+To6`nS z57T0ZqrMV4WY$c_;o?XQCb8U_6$xYNR~Dz`n*+RSiQ&P}HJdCI&7Tf|j~qJ%cN}Y` z)>JBrC+M(ufX2(u@e2IMP9+?n8be3hIEFx9HI!1GT&@?qW!FX~8CBM2;!YGlSsTn^ zdQIEz*mbSp=&%=JFes1*0zNRphtYsF(Y=$Ks3&anvg!d6QuX6ItMY>12_i&_)ifeO zd<>;NGd{pXtqje!2#r_nWG7+1%}Y+&Kv1jFyC#l6PR@~;_4SpKfMWzoLUkufqQ8HK zVzKFC8YLRzR-QbfD2j9cLkG0)$wF`QCGT{>;*c#uv(XX)Ls$3sku(T2_d#Ey&EAbh zoAvvLd(3cyc{de5MNdOo`^{crjwnA>lK$q$hH&?0a+2F_&S4S|;YJg8YLJPquH?tw z#$njFlkmqGw9&PbftU%Dcz4Sy`F%NmP4tH^O}{u*9D{$Jh0-{7vz^nIJ_wG4aAKe9 z=f1!0j8WT0ydyJR_55&li&j46>R@F=>=B;)0Bb*U9I)@< z7--`z!#7NZCgwN$ox613{^H6D631rH)SNdl$f!YNn^y(K-`uT}Il3@JmL>_rZ9@V7 z!m%h`RDF0>$I5R1Yme>UQ?-H@reKuvS%;u|eX!)D-T^I$@)ruy&(`+wy?q*mkL%=l+;{w9+e1kTj_UM>_p`j8fZG)Muv$^9e(4Bw}+rh+JmP54!OfE{*6*li{D` zRw5g!C$g7UsHvQk;DV4P2a{?VlNzVxPhn!5M6g*mQSHKI|83+4HxxTmoZlIK=G6v( z8Hsn}a35G1W-E1=niXDA>vFs5XgkST3|V%N&y6NYNq>A zNX|WKlMKVspMN^EX$cfWn#?xuOt*t_r>vFdI$9lwX1=?Nd7#x=- zVud>}2#(sE#Lt!A^!Ibwzl>HGl{1prjZY#e6OK_^5g;KwF1c%w4o0SiSz`Jxnh#+G zmL(9b$*YEpD#%lbUVfXfu4Cm&!zi&I-j|VfH9I$^k$VyZ-{xVg$&ik^)A+HcE4C<) z#Bo}+c}e2v>#wGA4#3Cc+%Ep6ym$D&mLphv%{vgxf_Gw=ef_I?PA8^ktlv6NED*x> zRYb;Rzy`ye;arfm`0pc3g|zZ;00M2!v3F`l@XJ-9cdQ8g zm~I2f?!qiC|Hs7sd8NnB;EGUuz-PW=z{r(NO2CEOaw<@5W2-X=^3Qf?|7@q+Ern%8 z>7rt}(+1<=jN6w(KApjg=3plcM(8jWXm{{p^+z3N)dz0ni|R!pIjifZ^QC4K3iVZAiduMM&um>qW`%eLRfMn5*$?&hI1EaxjMvxmA-*pJ09OL2&Mh|VM$p8-!P80=gV z$6zP;E}7g`S{*|9WZMxFJu2YBi{50j_)0lGlHBfN0K|v^D}Zv62M{N%%DRae*QsbK zM-Eonv#JovB`}uP~N3=Vh}6QAM{nzqlKJ-ZbwyPP{d`F&CMg z$}sK&lv3_W}$l=;n(Ly_Exem+ktSK*>>b`bhOo)s_H8z-weUHAm`Ljkm+{hhAAF7YaU-en@Hu7uPC!5P zI!ln1ltYeWzg7erzVv9DUjNgC{a*I1>O*;A|j zTH9MQ9ApK6Y-WLdru?0FVAsVif12JtuAm(0)p5@`507{3$7b`CLhd90f25G`@%NQw zVur1dlUMk)mctRbWO`LE+0ZG^gUfB6D(jh-#m(bQm7U6JZosZgUBhU@HP4J&g=^;) zZXa%->9nD0Drm*fk19J*OCZ$Xhq=Lm;WwS?-e8ZoRlL*4Eu)9PlF47gZ7?O`nT9lk zx$u4n8CZK;MPfobQD6G)A)3J#b2oD#3NS9Mtm~=8+~h2@VA6PgjUx$uf!_#a?V$kt zrH6;=bks%a7B$*Ti20eDL=ng5Luud`g#NMMB;qrK$`#s}K$WdXjJ05%?2k|RLF0y6 zvkCc55A^7!ie|GP;7dz3;vFKfHrr~uov%mbzEqstR_FaTJUWezoC4cjBi-CSrjMXk zlrH=|na1V^jPLHY-$quk7XBm@CR!7R6|X5EFkH#P48`G<7E(|2l=r+69R?$X{6 zF0Am0N21j7^)<&M) zfqN=f-7XeSPKZK@w9{nzFFB=|lY#gC8gI|8z#?jse3xjzy`&1Prq;$FPNnuQ!~jSs zJ_!l!KDG0pba%{;gF%E!^=`~RH{5fl;OZ)o)-aGsVvU3bVDhN~kA-&a{3A;-t`lEtkxD{drw|7WfUD4KB~s^6tkv(H9C0)S&R+ty;(%;I$F`7%(I%)#7}svl?!- z=wz~BMbS~?IrEM$+Q7A-708ceSr=dDLg20DV1Iaa{@x6p^Pghx>nMoBEWc2FAS=3c zo`5wZJv3!j+0t!hf;D2}C<`XVnG{%8`&j?l^of;<6gImvy*>>M{ z`MDcZ@Kq-s9PQQ8NwpxG7%Ys$Kq0>nC-9Hu1$%`O7^-#;auVu}fdM~`tug6cE=pbm z>!c8naUw*ZRkG-j6g&L}BV4#=3vxNfS{-`u@j}*L9GY!Z^NP%2hvS9MemrBAk#jI# zEcIV|AR{)N!lE|>cj?Fn%i|Yx&$CqXnaqq+F$r{^t8#c^X!lwH83>kA{$S&zYdPOv zId&*d`uHX%x#*M?%3N&Z0{wp&&Ij{fTsF9fa?q6al41NE%_DinPnwQjeXx5sZR?ic z>kf<1EIQa!(f+fJdWeq`X3^!<1$l<1+GW37U5ye?DDFH*s7Ht1E)vO2t>I(zoXdX* zNy!AU%lkCLt`jT-jZu(K4@q>ReC~d@;3hpA6McsU;Re+H*(WZQAxO2{svhBlSlu7O z*9-OfYqa<0XPMooc!FMHuNLB5IU7G1;Zx)<6AFGJ(IW_*5s}vR1bMCXmH|oJh7D z-1>!Rrcv0QL^_DwObm0S>xd%;Mu-cdzUo;1zB0$_qW?AnJa_Cwadql)r4^FFcB6k& zO>BPhmpvDfN*O_DM!^S-GZ{JXzQ^bLTePsdNU;Rq{GH*uB`bD?iZw$S!Ju5d?Jqaf zY&)XcgaHWPjo=dyO&PTEou_XJ1HM3zUBgM1?$GKU{yVHHV_&XC8e!e(o?n1SL&h1F zO<^9K(1H}Q2DwGI?TW$j#7BcBTN+eVnWiyE4dt&1w5yk<&lV{6$VMOSDpt59sX#DR zvG?rBMT0+bmIKgbogt9>dJW&@T?gxm1AHS1!5#&2r7Ua|Z}3A4ZxsuJ&%9xH&Yf{c z)V`c13&O>9BD`a|Gv!+?cJ=39`9cW_Q>yqQfp|OqAKo@nk7_B+8+gl?J8;JUUd<9( z6UHZYvA6F{y%UtJPzGf4dQ@@h+1>1n48tye%LY2Y89wv1rx)f+XOcC)by&esM|!0ncqkkkVb-|+KH(K zio(AO(1{T3i_j#(Ovzl76|hlJqjDd}11?Qp^yh^D@+t8596%%p;19h7$%0Zr`*MvobQl*xDAGB@4MM~Y8Su)Cf_)ok;G)vr@6QI%py zgAyptwdTyR+F%h~vA&|WU!B1M*E6yT((+i|j~OVjJ2%|p{W!UEW%qQXHl9`uR(KA= z2WAy0xtW)TUwdOML*b%`eJ8fHZECPItv-l*m}g|@fu%3X#&9CP?5q|Y(n2kZkGy&w z5+)BBWDoox*{5m5_K(Uz7bFIpUY1R5&OB}x#VIj3*>SHp-4470^=iVr@I1uP0#zl* zvPrG_`M2R|n%)IZ65m*UMxp)Wx^=#gG#oOzFr4A^h3^@11GhP7hK{of=mu0L9L$h) zP#&HpCHSFnsIiYX4cTj$6f&y4F#->=gHnM?8-bUy6*Csfb7Wt6K;}j7WcAm|f0^_k z{lW7f8KxuyMz{Jtpqzyd7l^LQh=q7mBy%N_U{pITA&jMU!c*vaxR!RWuY<)ELr|T(bu?7 zK_nUr>X(N`rE0VIfzsp0-LFQ|H7H*AbWPKaH+83Sy*E08xsns8&MIux(il(v(!T1U zRJjh;;qA__Z+_fliZy;Y)mj0XW%RK8p*6MrU58DrrcY1`U_r3MSOd&`U@P06iE0Td zs%++Jocb%+H-&+9$s74>hXZ;^YY z`>gUyc{2Dix2062d`l?npD^_}Y0G3;oEyDWY&tBwmQqxPl)+W_ii){B_LOhojI!h^ zfyB$sB9wy_EbJ&!p3`;x;M4<-Ak2OCk;n0UhPj@iyo#sS5u-l(ch8fM6i08osEIwf z#mGqB5#a(#9=wH^a;qdN!;#HJp~M2c`#@hF-Iq7c28qFA!&oX;>R*lP;iDOQpL6?j zvu@Cviw{7<@^i9iJ~$Xz6$r4IZ{*>0F^jPG`)vJ~@%rn1J3};*0SgXH>5^oTD3D4_ z7oQ*G?9U^ZQMfQ*&Z{oAD9Tlv{yjFI8oPgi35l4X7qY>Gw!~>G!aYoTrw}tbB&2^W zJ!D*3TJ>?ad%U@A}WD!jfW2IwH|4eA`;S+o5)_mIo*dEM7=2naGVgyNfLri&B>2bsVcjm$~74w z9$!3t_#rZLXo239ve2|#7PS~~LMFhR8Ot>%jLlz~JN-KcQlhI-!I{OYxgv!-)CniRd03YFHJ*gyM!nrszPR|~}V%&fo(MT36+<1ctJEL2Th zR`vgULv{7Wb}y0-L$^W>7sh_u`lY{jL@Brty)8@OXi-;bW&cwRpg)#o`q+O?3WJlvJET_e-fI3dSx8iBV}RIbc@s5TMHh=yw&uj_%|hE*a)PQ5qn+Sa37JfN zY~Dfl(@q<{41?FWgitm!V#n=SRm7YYHFfx_sw^f35e4AQQ9~KPkiDl?c4~F_&sdBi z#$kv8z4g$*_qqPT#Cc98l^G7{rU1Bgf&l5pLg`?iG!{H52$Tr4>W_ZuuHE!hMk^pO!TVPstLiU^aMtG7S2w#d z!eB32S8QUUysl?4Fv3cK_m0u6#c?t)A06&52Y3Iju)N&F3UQD63qZGd zdA<)il2+g^CHUny_}j^wxlS)(qJIXmYxXRf*pP;lcIo#(R4K0NpZmb`_0_n7;U0Gt zK#IB`HPNVF)QN_+K>F{VfHVyqo=nd5QmJn2RJbD52@jLvzx~OwJBgJWnnVISmCUVT zMXQ4@{WYGVhm2ChFXvQ{Nb zAo;KBmp=s1;TS*gZdg!g?UVI)n)Ac@K3iuq8%?9Vpx_i`;iOQWTy?2)@%f1SZj8bLhznO|yDhp>lGN888#`Jwac_5)0YLK`^39;G7(V zC5}m<<*VTcHLRBJFkz&l3arq;JYa8`+i4AUNeR3pnHGSrh{XqN;S!>~qQ_zGNz9$d7UCsuA=(s)cEB5bhjFoG@FZPiD1j6sr+rdsk1MO{4 z0y!b-si9P|_e%T4Rr6TiS;_XU{ub?2-X10VQEi!n{^gRUY&wBBxx59@^qv?{lLF5U zy(Z?79vPTIIT}gX`jdMjJFI>qQ)xlr^9SJ>;@0}g!YZg?CDP*R&8?dOnQ|@yMw&T) zzRAbkeR{W%5rd5XfEL;4u)uDYegGnL6duMj0LAjZfLFO-(H3D)pUVFDj#jDN1&(;l z&9V^$e7P+Z3jXvW;BNa@W&GJ+uJZpCXtp2Qj>qcsW(s%7hM=alR@-!Ru)8;v%4xoXWtO!Z~0fy&ODg)Z02gGMk5z8|;%5s{6zYCTze^BOmE-NEwzOX#zY2t7VZQc5uul%(nBVQF!B_-i*fuETUr4ZrCm zgRV3RI|84Ge8^SB3(};dKt+==o&9AVdV#(3)I+5dDASmvtj^Q(e`weX@XpN$zd`1e_DW#o(dF7 z6QNM`RD?UxCnxntY}@RX;;05YQyrS}ML0fntcf3lo(Bt?;DqEsxYLExazk6&W_XOL zZYrhW=bdaW%E;=hGa?De-o|~cr375&tpo(C@LU(2AG#V@73OSoGqQX?1isYaXR=}0 zfL=Ph)afUMz$TQwz%lHOxfeaeUPqu%)5KyGrb8X<~ zJO6ycv8DX{jv(=}YHiR?T_^;YHxUW@DUj=m1f(JE#!c$fqfk>KK0B8l|Vow9BxGP$atHXO*IosYIwmr00SLPo!GrH6MFqDM`iqxOrTaTOUeq^!B%p}n zlwv%vM$vyj*?D!?g)bl40zuBHQJtHtp+_s? z=S_GljiBGD9$vGv8_Aqgwa4s}2d6IAYM<-h?%;sD*8A~7b zOW4h-E~h0lTwu8&j{*ad~G=yg^hn>5J@{M0<9k!71yI*Zo^il}uINYtZJ$i|g|suH3N ziSPL4cwe_0n9%I*EGJWq@R|a6b~KL3pp@cYb#>NB3W432tOaC4#{2UN(|b7V_+SR& z1%To&z63KeT!YuoIRY(1{I<7s0aXd&F_KG$O7e5)10wc7l z7d-}mlKyKDONeCubWY;JLkx+r9*Q)JxO+>oyYXD`69FUSOr-IE+gXNC45=$iKqDX_ z(Y%SkyjRd^ZRON^jgN9~`8|?b2cB1Bfw?869c}B31My4M+3(C>^`XLUmxcdZG2fq@ zUMkIR16dud0HUqD(INoTs|?+TAg-Zer7sQXMf%JqRLQ?q0w@} z3Q^Xe@T)Y)d&9LpgxmTq`ul01APB>>efxA}4YxlMS-I0dlRw2tV%6GapW*z{i=zO&aAgbr4u| z8PS+)L4t&{uafj>>1ZfxS?rT(ZHBS=vreHC$l@3j0UcO@r6Q2l*WtnO60ZHwBdi&)>|-6Ul#cJ)_`Jwbv-GsZGt4y#YT!mA z)d=WGGAZ(2KX?e0oX(|IMta)Fv7GPupN9~kdhU_vYvR@0X=5hY6hL470Tby#Xbl&; zYoGK&9|a#_Y)o2YSGA!8LfEL7Vo-_fz`#OfN7>Q|-eSH5*7fc@66=RDN$U!vBeWzQ z@nlPAt!AHnrWlM5;kq_hAp?rh0x2Lan1T!93gzo4=&i~#8CUtr`kHUkEfJePe6j}Q z=|TZb6yN8?D7AUqV$vKm?e+`3{PfNRZwnf{9gqX%$*cHRHgzK>t|MXO=`!oOW32wd zx{g8@HT+OF5Q!2S>ixtlPf$Dlbd|0P`2+0jO@=7x6G+a$+IUI^saMQyYX zGWLr}qc&_Blq`8@XE8^vq7M&7W#@&_q9ov51cDW^N1&;mCrF>l%zxGwPmK#224IZbT*sxtYP_j9bS{> zoW88vXtnVERL=3!mwi)T0tlKYfeygDEf-HfT9oiH|1N_y6@?l2U=&!zXaarRfN3+< z?I=J<0m@HUvgBZE!}fB=W3dtgiGQ?mUN2U6*+xAO+h^-vdmVeQyDTa_fIx@=gTOp& zsQ+`Qy0@|HeggKe*T(OgfAQB+Roxg8@pTz;EJ(Z%M9q);LIy&MDWgj0@m==s>q?Ix5L!ZQORvX}yA*-eT@g5wT4%@MY+`jZ|Z^-1^IUHoDne}_b>bPcF}a5zw* z724Z$)2Q4yHDu07=d`!90A5GbR9e`Emk?MNzJf8Uc+e>G_;&t!e`~lPNl{4pPO61V zec$#Bwr{ys+E&Y>|M`1xg80n_D$mQXI87Ybld>h(h6a)Rr;L&uMGixXjt0G4>j60s znGrHHY+M5Xo6Kv4{RDoAlouf^7smxMHF2ZU^PNYH{QmO|a$c|k=i#qtPi`z_yq^+k z;nmWxcWf*4pqXSBOHAeoX%%wZ=n2ykwYRzCiJ+|P(o(g+2;EBGXZKdKE$i(&qcJG> zC}Ljg8bt`yf;SDvaQx(Rf|JxOE(6O&S$4UNG)S+Iz+M>&7*f<hz3wxpMR$Rb~ZajwFMo6(M4#K;k=j^Khe3}PqZN4 z-tqEdr{7s`tzk;^%U` z5!yXX))8!khcrH#AuGSH0(gELD3u7cOD>pa`aH~=E*JjDuJME^8@1gpQ0|KpAM*Fz zc}x$LPTs$pW*gGyZm0E!5@<&zd4TrY|JUpuVrv<)Hri@$5p6(&r}v(uX;AwIWXVt= zpbb|?KPisR!-HU#F$TLiFqVV}7=j5%Wbf^GjPNv3K_6XIqdYcU+=mLs+@H=@1BXlf zhfnC%^#^K%byUi2yGU`U0!xX!Hh7`WRNx(qMq~YFw;#n#sjB_)aZ)b4ZcgL-y}Ov` z?L4W>!7aAUB2}`#M?bWXw>gHLT(r@6eX%s)L_J{@E6yC&&POL8X~AU(xMzY5Rh&t8Xbru(C@ZS_rE*c3VN1j z!G&8Lhom}PKOsU8GG}K%CuhUSK*Jco2w~!y;tR}$cYs)+;R;bVWJ3tZm>z&|$2Kcv8nX_weV z(4^!Q%3vfd_N}ElgJo|d)IgR?P)iw|gGNV%DsbXq^AI#sIt!Ln_4JS#->y=TiQvl!%4kB&_9h3hRF>tN z_?YGTof}+BzzrAV`hgQJ1v=$jZsgthBTJS#E?(T3>xXD+bzZ_Nuq+7}@b^F!g`(o@ zD{iL_)I{Uy6cb&%VkhZhvFv--_pj|W0+z$`<3VRp&chu!63ukO4vxz|3q=bpOlj9%^;{xXHx(=^S^v8)4{T zg|J*F{}M;B94EAB!bE>ihL;#fVt?^}E8WRuE&gI$u9Pms)XzHyi=UB+^}OQ!8Vuva z&Y4kAF*vorS1R&mk7Wfvo3wm%(hM_Iu9wDO4pSl*HKtFKzJ|d%*f^tMZ(fTn9WkqMKbw%D?wU^Cv;Sj56 z-yhh3^X$ZqX(ey}NYmjGH|wS%f-;+qoFo8~fB`1Hq(mw71gEzbSN(%yQVcF#ARpiT zS6pt%9CfbF02^$jrVJT6USVD_-@hk^jRcueKyc?^tHU<16MkfaEl*5x;e&z!h-`c6 z$bMsjkei6&aN6S3=o~FEQJ$)GS>p)^64g3AXm>%*l{=wC;_`yI*zgY47hykH?_|Q2 zqlle$mR2<60dwh8QT6vLDf}4Dd3%iAS_mHvvmHOF1l1`@ne{;dau@KZJrAEi(Sl!8 zDOWNMvo1P)O`K9cp_Y;p6|_)1`k_T_MorM^=`r(o@|~_Ye(HVRF92~Ffc@2k zXqu9nQ;vXW3Bi%jU1gBGi7IJg2o9Zdcd)!(>a=nCaYQ5=4+yr31=y!5k{k}}wWTMB zc=I*6KvWOR!xK=T@IR13&oJ0O>AZtU_3mXF^{zd;>2f_Gr?WY{jt(7{+h61o8Lj>U z(HY*grhR+4;!OPUBv`&R`_Eg%TfY_;GZOM5{pri2(6Ht1tDi`L%+fjQ&>;vmebHBt zwjVVc!qHZn%&Mg8|C%H9^^Y!8xg&^Kb2VQs>^{#}%~o3_tlE^_{qCjnb>9t@0>gNu-| zwZW;n6NZ0tdoyLWR7AH>wi=qkc5!Mpp@abLw90R7r?`~kKdwUE4^Z+{dca^rcyVzj zE?G7U{kRXOupqKEJ=z>iI1Qx{jmoJ@YrB`3V`0LH`FR9NKq3+>c(%{iutM9iqFUSJVJD7${;6 zAV!VjLtzW_1qZ5$V!_Fx0^yh~HPKtXx@%CvS*eN3YyCu+z9z?w=Ludcd(yTa(BKJ=3GH}lk=e{1)SbOLNi}pm{X%fE8 zjA0$ULlO-SWBJ&)N{5SLQ$_&^He}QNU_dP&kTR(6EsTqO64jmgglG3WmC@|9)uJu{ z;u{zZzXVQ4%b*)~M@6UDg~PnSLf}Y({$A&j>)#jftFr5BYt>f6^z!dpnQGLr@lw$h z6)1tHy-Fs6TPKd5r;NuJ)b^RD;k9jla09Da`oDslOC}w|Mq(Y#Gza9_j)g12Q)@Y3 z*PML?slH!`-1WsBHRY|85Ik~()X3zoQCr$_7$Nc0A}ekUCK_w=wdZC^XT(Pi!#m8@ zY0RnMT3y)59T`$4g~eDf0vZ?>Vl@UYEjv^k_&2qMT`l)0$#y6Ga~JmmxIi=$I0L z21x*gM(`#x!;f&fKY3neJem@ByQVV`Y?9%dh?sy8Lt<(m8gfuEmIt^E{EBo+fa!<;ZWNmJdP-qCs6x9`9` zdp!2`p%{e>w?t&6D4vU6)ibIv^-8e>gOiSaTS-V5WUGNFoxg$+`b?jn2p10@(pxEE z!>%Q4hk6H-xLmyq^QX^R%9~CHWcd97z=5^T$FWkPCt=tWo!IdoSW#KsxLWMELD(%X zs@+sI4yyc!Jur|;HLVpq;TwcPhnbFEA$my9m6vU%jFeDCz=KX(`2LlF`&)WbiQ;z9 zj=nO~He%yYx0lvL+u5(*+ETq!*jQu0MSVQj-_{1!R?vzzEA@tq2pOaUTT5vQ1C0ns zX;5Iq_sBz~+CJkCGk`T2<%VHZpsz8oSyzZj$Jm~Vbo+SUdt5a^Z~wwPIBdGT76>Kq zwgzwtu-H90Gnnldu@x&~tcs-7;lQq|yHo9HzI`LIWQBb|{~Zt#f(_hG7L&NhT;&-j z9)v<6b}P3sHkrx=8xi!U^5^_EWPbC7>mmKU^nmJH0b(9m&PoBNd}Z46kqq!4iA1cs zG?v#EmW6W)sj<{hE$(7F#m>6MzibL zNbh}Bc?^8&f9QYPw*mz1M`c{6r+6ehFwYqo~H_6CDi zYq7eO%_woqP=Dllsnz?cd3rN|bf#*aa4!)U;WvlsRz0U< zS+EYNen@Acs;0CD0w;Y$)Q)xrofGM?Zvqn&c66%Y3M}@zM`Nteph2pBr>JS6TU21D zJGKnsl>@(Y6-`utfr4CQ^ZoxT4w>S68&Ch z`-#Qn{iyjTHw-)qN;RB7$Z4uQz8=a9SS&hfmd{~L+0}B^iDL7gJ~+vDT3XoewUtv| zdgk{6Ym;dH7um>KyD~sVoo~I53!MCdDh4lQ4bSWf;!0K!kZGv+bQs4(5(tSyf2zTJ zWp)&8xcMIIO!OnpX9UwLN3C7(gbyxk1u1n*$D=mLg)AFH0JdJ;`nQg3t)c~pxMLvZxXM8ftnWG1JQEu(@PY% z*+eO+OWnzz-r||Wa=Q^*g?49g4U!?314I%z&|GYM*Zf@n(LohRMLA9~h* z=via!x0s|MeRRsQ&sUJ-6Fj7zY-{xi=nF=dT=42ac0C1=J5 zK)pUu1Zw{+<@_y-_XJj2;j$#E)OTP=sg2Wod69CiA}R7iv$xU$?lC8 zg7{g6{yrFb3`Qdk$X9M5G+<8;2ObT+029MV_HY_m^_S)UCAfekpitjlkf9*ToCv4f zG1plFyUVftxzIZKt{)il+mC(RGn}F2l5+TQDeZJ?2L&1WVS}a455^<2?~ozxSp{MH z>9=ynbvzf}u0ez{F;&1jGr!dpcAJpjr4W+PSX-=Nl4jggK``~Dd&PWldK*@EMRn zZ#3^27~HuswTfUa{@;56zGj@Aod>JCE^arX1yAn;O_osWnkrh(hFBT$aX}~ah(5xUDXygE#DU6788!+@&dqV19uS;zde=3+Nzu%i<$~6TMofH%6 z)ttc`F}}jJI-d-*{X%^1TW(zDhj-uliInz*=1mpeoTtwddtw;X{xRXF;M@KDI$z~x z$=-I~i#*{ssd*@5#E(PgPeF;kHbw*_*95dDH}Vv=*8Ry82d+xYpgJDwQg7huJO8zB zLob0B8UPfLK*nfvn*i(^a2+TXkWL+m<$u%`xX(l47i+m%s8=$0#9#gX{XJ@7YF4Fz z{5Pgw@znVNaHLAL-nL8I3dJBDrIwjLRDI7@&SMhwS>T^mM^Ejz3?66!%Oox#vdiJ# zG(z@=4V-oCs4)<(5{}$QC=Gg5xTVg?Uu{s>88G6NcG9qN-r!S}yYm5vCC$saz-u(r z-RfG)Owih&bbin2V|;I5IG$Gow}%7M35b3zKQp%~^-L!G7zO<+OQq;hCFp-h&?iaI zlfY2e8_FJz=8Yx^q*L;%8=?t`b3Edv&x!4b6!|%Ovok$(V+sokFo6GSb@+4Mi9@ME z06(gUWQ!$2knQ5{1~>sHr%rRl#U%1|W)pyXGpX@9oq-~G15kximXTLu{Qml``?$)V z%3%dfG9T}u#8)HhL~k7C4`|x#7^}GR{{R`lVLh*PU--QgLh$JJsEAi4FyGD-)RbjI zULAycX3(d=>f7LvJ8W%fVJBytfa2=y))Zuz1``-1&HuKf8D%w>)r+{_Tl5Q`c4y7^ z;ND2mO{5v;>cwuAJ2)z_)qi8^Ei5${#>QwO1yXGw2vez-w}#N2Nk0@36?B zqZ!fylUO}06o^1BJ+Sm3@(2LD_<)8)TlPg;{fCcfOar}L1mlxL_SLvRFBK$vQ{8KSHIb-aVgrX52W5ZF_kO|@ zrrU$vP6YkKIw{a+ZO>N7wqD{<@S=~G+VLNPFC<86gl7N|lK^DxRb`smR+`$%R9!n& zU5$p`d~drn+3`fE4jgc`YCGY=dMmG3wGCVqblzsETN3lGf7P_M9kM|nUmejuf+k72 z9zzQXc=-t=Elt2u^S{`8>#(T4w_jKhbpU}uN|YLrl#mvN96+RzZj>RVy9dER1WD=c zF6kJ;qPt@VrC}J57KS*R@AEw8JnwtX`Mv+Y*Y6LmYXf_)eXn)b=Z>}4)gyc0l$V@{ zt<=DYQr*t9+nNB713jLzjv9GvX;8u_`%OGv^sW&z5%9?X1ANTT`|$>#hw#P_x$qnQ zD_Sa|DO)bkYS+eeWJq;t+SlqHRC7E+{BAar2IJ6pD}TI_n#4I3;n(^h=uvJoN6e)z zw+7I`cceiQ*Q6N7&DBwJmuzDMO)l)PM;sA3Eqwo`;zo9Jy0?~Vu&#ytH2*v5?)nH=+x6Nb8THD3@Oo$XkGzA&bI`_=-*Kp?9ck~pwt5x~% z0w~#r44+dU%)xW?Jv~l)1M}rRbvc7R{_Z&=mjZY{w(0k){X0PCb~v}f>BtpLp4fDh;LY_*S zf3d#Z=JAI{lbBUkOxs<9i4^$86k`y0=I-^r*$05(ifNSwolD+ii49$hvg=qg^;}+y zK-D$^ib_@Bc*onv`}M)3#RDNX!uw0Hwfrzk{d+f+sISu(fMcTP$DX{28qls;F;UO9 z1c1tMp~?#mexl{u=tB(5gX zChWS8Jv3Qzbgf|e-O{;0nQw3GmmB^B;X5|@8V9&#Q`1XzAIMiTeloEV!d`R@xcQ2U z?{TnC6|OEO>rMRLW5YnJyE4RPnGfoeud^NfEipv|H{n3(GMbl-oPkQ__3@m-OBI!_ z%153fVZdIb+Gqa!MYatdK-!f3MO0cv`c1yR9FSf!pobY;+re!j1Fyy`Xl0cTp6WRC z1c8-$WM!AQ!|N75Xttp40F8dMv%*z6=~PS4S3(88hnShqah~Jf{*giu_08{@xA(H^ z_q-CF;~6!g%3E+NR^4eAA4#FsBQI=bJCS>IN} zhZrQa(bNK8;Xww=z8>0Pnx$c^;S7^<1|#h##l%!*Kc)*Me(B#Sn%QeGmoCc4!yC*W zlzWE;oAb%tAx9SFy<$b+oiu-~C)CZQ?Q|HF9fuw1hOQ5&ekT>@dsSz7!<n1HR(a=Xq-Nh%2xiH zl{unUe@O8HU*mNbd<4mTGd6r%4AsHtluS~3Vz}QLJDDoZ$1iD=nrWB0Qwwv%H|yAz z2E^+amOoM_`xM0XhKvG4a4NaZ606MOy4yeJYqirqcOs$2kUCf6w|=1t8}uC#StcNa ztb`UB2hw>y%+^$s)RCu0q)ZCb`tzy%nJkLI$Fm`W(LI8iXCRLndQbQ~=YMWeYJtjW zPi(nN>7#J=8I`SyJi2YAwzl*UvY_Dj21%9VQU~pbS^G-j?^{70nlG{z6IyH0F+Xb0 znR< zkKQ0v>U>+cu#U+c%oEIteG~JhS0cllg<|9&%bX2Z5jtm=8eU2-}4bq_{%TuMbTL+G{%^txz z+!dN~7V_F|#Xv6aaqtN4uet@4$7X)l?W-+{v@gwv%N zU*Uscp^DVsUP%A?`aYl}24z>suZsFv14Tx&<_O)sb8n+^PuQpg>KGsu;M=hnI~Q~$ zwfX%1%UCdS`w|sS>HF0mH*R}o>*}^XFYb=5RN|Ql6PK9%lp(chkZw-Tun2!0;d8uO zLNDHI?e3qeQ(2-r-+QOrXeR4}wr#DCT&qriVdWVmvBCK!U%B2-_*(9e4xf)Kh?z-E zmLO0AECq@W67}y)`O1>R7c!pKE6rct5i@;sZiH(b&7<@?b~48F4Nv zC?N2+Qn^Q#{ADV5_U#e4)yOyE7~`IAQtsDo-o!2ox~LzT;gbxKr-Nph@1;gMn)rO4 zG||k>oodTwj(kFpO+xoj@Tg~~c1QGR7P0cW++;v*lsR49jpQb%@xBy@mzVKIpdGNz z{luW>AiWdN#o7nx(X8zl8B8t-Vi@4*YAm{AcX6~jC9pRsSyUB6#PjK$Ag>BOC9L55 zL#4m^@ZY&e_2fJ6J3n)MR8SfmW;wdWFW>bL8fPg%{TTVyp-HE*olpL5q={)|tBE!k z1LFudT%~(xdeOMEc?^3TJj}y$smMy#F6$dU`!3fkSQ&o{b^|XPAT2m7u@e$)jR(q> zEsXm0>|Pml(Y9w~T)Mg|tldZlXafI{xdB-Txo^R!o&hY_YO?1Gtn}-{ zY@AI9o%}}lnCl|b&zPz?Mp99820HKYz!Wbu!{K>NfW<;Qd!PUzB(}FNkuEzOQ{PQX z$L~oPeAHWyE>?#;5v21psBVPGGqjuN{kF0{$#XoJR9M_Dwm-|5C{Vs18BR>ERj7Np zU%V5L6~f(GX1cPy0mcKrlL7-v!&u8k6uAHR9hjrikKZ5@zkb?`+}M9!E?GX82PcXX zhjoBqsScuA42b7_R^~nI9{WkTN3pL^Hs32*wUX2=csSKMLcX_mSw{j0cs^w&QJsovgp zBSE{+(W#5G|tLFL(x<~7Duorh!eBV~+RBUHuZVRjTC1~T*iLOF!+yu$0 z-hfbuxQHU9%mAwI$8z9BqKV5!Trdy)pGE>ahRnz6Aw?CS-H&<6b}O>ABLBqHPkqp z^(1$_V>5PAaF5UYMrrE7e7q5;m8W#BD;n6kp*tx@i@ko|?`c`BYa4DQ-3t!oH zY1?mgYJ-k;v@5ML9X?CrXrHMoB{06nV^04Lh(!-Tvf_t~NC?;$5RmD@k2jR$enrci zjQ!blEG8O4aR@-%2L65$bX>rj_c@rKwQ3i4`yML4Vd{7#-*CR>Fu`qLRFb_uzuVY1 zG~(G-6NotKGsOgCA~HOoTFTTnC1KraG&~#~R50nE<05@0Q~G@Y1;#j|JpJ@F@8GS| zw#=%(?8`GTC~I985t!nsH1npB8h*3_)c5vge|F0{J!Iqptkt`aXA4G2aWJz9s_ ze78O_kq*pf`r^O1E8|1&r8-a-g^; zw$WdsrnQJ@b>Ebms>>7nh@cAec1`2?(>n7bsKGjWGs}|lCEnBb5$J=?x9Sr7k%{QD#>8BH+6McC% zl0Iuzu49pXyf7PO>E~XEn8V$_D0Rib^PTU*aJwgU4(+Q%7d8eFs^W0tauZ`IjoAGk zFVg_g+5$vNBT?fHeqaun6o`_TnK(cGS})@Cr;UAn*U15=w+K$0UHG?;Aom(<&K_O4 z$XR8$c^rGQS}g!3ht6lWHOefsvD($@Vr{bY@b_JQ_r3wou4~Pf1c-;o%oy=qC}JxG zoy!Xa+s^h{zTKsSd3&yCR239RN6lR|-MLpZB^^>xd4({Vg9ekBRONOC_?LY+gf3{O zbjX2>ogB&sB@1=h+p-%vO&3u~A8m-PEoB}cLNQAP{GcacfH``#`FL6btmiq8Xtr1q zO!2~q`<&)a%_5_BNwVL|@0N-m(-xCQL0Q+Mo83!CiwhZ^)@W`v!Ur|%?ay~8MX}Uf zZ(W%x2Okt_m(H4y7>4 z(;xCf;fNNDa57v2uu8qIv>p&=U(m9MQ*%nbEJPfP_4~tIMg5cc;eej%d|i(ypO~(p+H5vGndBn(wHZkH z&blaXx{&>}lwtDy{N+O^#BJrblKX^(>E?lVy4#$>g&^EA@%vq6BJjH#_=?ImAX-cK z!{Yd6z!k;v3fRC8^dR&Ajjot1ORhOeeYDH@5`-0VF-%8v?uo8-^VgaMx1$1;>0A?I zW|$9;MlGstj1@XM&ikMRo3Adr1hHzsS-&hnFS!HFJ|;aUfW(I0rOqtOCdSyb2t5&O~Co>&p^yGIFA=_`~sUKS15l`kL{vRPoqNNMK8mXxr>)Q(#c*G zsZPZST!s}-c~Dg=dtj-3g1lFt2?38WC8Em7=nt0}1ZOQ~*#&O?#%jRNu17|BQLy?{ zC--a#BAVmTyoH*(%6nCY8okA<1x0a*{1{@^pq(+2h-(I20Jq%?w~Lw$ctNw9%Nbf`_s z=DAO$?v_oPq)s?yU3sJwN?s}Z_=FhvH>=`&o2VjN+p;c|S0!wHtZ~gMf@Vk0>PfKbK{_n`)N@$cHexjEw(;TRFUP}mEEPubQC-+neuK)O z?WCR7qN$`&YgK(QnytpxMmt1QWmimd?5Wk((IEd}RBy7u!nZ}+?%JanFL)7u$$MPycqDo$@LjP3TfK@6Sq{9q>|PK`|4nizN*%am$hflRbY^rmdM86e3`EpxJH?*vg`cfD#^0 z+fvg7oc|WxnXXZ+<}WNMQEX6cdBM|qSVG@&MPRyI0LDKDUQjoG1b;F@RWmhOG&MCT zQF)}X$Q;Z7KdWB8->NUd#1v>!dH(Wh>%1y++?;C+rTd<{%_%!l!mPO9szx!E0aL+x zrI)+f2c;T!cmT6re&a6c-~X7-?H8X)rb#{;(NLce;9MTGl*jjfo)J6a>z(^sMl%Y! z>%Pf3-&p|<`WIJ zYS@PDHD>$W$~L)nbJYyDTzv`k(^$S{5$j+YGkHd0LITP@l$Z2az-KN>YXAm{G5 z55tfaO$Fit%KZbHjTYy9^6C9^P!1@6`&J-(K=Ntq96|+>V)O%m*dLm)Tlk+9Z$RS4 z`^h{N2=3_x7^|Gmdx`6z^6AAb8!Pp80ygUVd26UM0y=b0?ShZ#>rx|u?q|AyZM|}% zs_LxzAT1NC`L<@)(W8g1qqkFpcRw*|vlHD^!;?m;*Zca0Ig`0YKkv`lZ{X) zJ6@r8p4OoIvdD+!+c)&zlVcSZXhPBZHHNJDZC&-42ZJC=c-V#^7yH%;#ny|;3Lig3 zPw`9Hh_}?*UV}1(0CEApWCEvJq zCX2lTF%Ma0_G?)n#TU)_K98y#G4bV`QVXayLS1Y;8c3Z|aJ)cqxH=z5E^eh93}!RJ ztaFJm0_VO@>yC6vYcJ{--8{(r_AmX~M%YswxA9&|x>_^2yYrVF)DPz^-sx0qWz{tc zmKZh&mXy3b+clVffiup&# z4SWq4AV{BO`R;*`Qh?RM(@NoF0KVAOny-=}sUQh;a zw-BGnR7!QHsO#*l;PL5D+kJA+%^=sx;r`?r8SJM{$UE>`=-tm==4H|Pv@6|ukPCI{ zYdqL=orX~=pkc)iB9{W)wt7Jfss(=`f?!fH6=*d{=xaypMXYh1O9zL0`Bu)sU=xhr zisJaA73*<@wz1%5#-qdG3(doI8=em-@mviHTJ7f(dUP&dL$i-%mch?}xq-45FeJ+% zH-VSkzz+jFjMkHAfm?wTKv0watoRVUH|rpJQO|WU+3c{Q992Vy@BL|#H!ETZvbhAI6&Rmczb2C`~chC z%Q_VGgk>c^2g{T{vgR;MBek8mW1efcCoAm!mxKT(ka>I(y2HHLw zF=+RhMuM}G_645Tve?oE51f0-*|@9E&P?K`S?&mF#$x3^p#dANcu zAoLQ7A)goD%+6UY0ep3o*fBKSd6xO?aBL`SlABnXvFD$8lR_xCO$`8R@;}2;$gjj3 zux=jqUTMZP*hZENBE@@l8i+3RYK@2&EuW?bT-u195A$Y=e=D>8HVVdn3}l`NsRdwc zMs2k~Mlp^7VCv~=8kx*jo}0*MQ;oRyQvJch(UA9UV~&->&XSUbbwt#Z%%<|R?pYs5 z9_92QM6%hiBOv_IYb)kJMfNYIXU2_G_Bs*wDy8?f4!ab?^2qf}#ZMU(oh+ut*u+xf zGY(%PxgBL7bJ&+S2_W@-CLk@=p2lwm`U|MczEYSA_~kpW=yDnPc&@Lfv3Ezr?e$W4 zS7gfh-}L6Q-qbL}EB9~TMu14=B`^@TA5y*1&xQ^U%q9sqzWqM$J^8sJ61uq4OmF?G z_RaPPY+E8b{Ar<`MGCsVHkT8tchOusLL14Iacut_o**yj05_;9crWVy)?zqA#Y9+< zwyKD8=uQjDs?Tifp&CjK?s_ptq*3~N5>d?~;mVoiAJJ3Q=$T4tl9O!>?^P2pr@Wg0 z>akT`kSxTm$WS@|>Ua0`9;J8$YenydtRZT?@Kr&Vznl&IOekJADVYCTwl{q$`k?V>Vl?uV zBiAo5?A#bXFbMQh1w?tUcOXeqmwG&hlNUWWR3b8yUDdeH<^=4fdJ35;gs8yzGdIj} zaB&PP%w9se=OR>njDdB*qD3OR_q0d3k5y|S^UvH^qsnAnhSq76CDlTvi#}1PuxGmw z`eId=JCktr@B5+p;k`3>MX*wWTDc4N4a2R!xMlvSr2&JD+D}tCGh$PNqVOt*HVgZ% z!l(h)0gLSAG$39PRq^*7+Ds5Kx_amFbLrTo7_QtV@yfnp%u-B(O0~-wE)W6SSth zopJ8GQ!Eluw@ocO5`C2|sbQ&dIdyvVh(ZCL2gZH1oIa`OFC8B9@ur*SN@ufFfit+C z=0;D@%})wru=?VfWAC@vLSq_JxJ$oo!|5;Phbh#vJ9~BUv`t-cnby`r1rOl+RClq6 zJH`ibzRFyNuM|%UIsHRa8E-?8Eq3L73{{bmf2s|xgwR#hJY^|5vfKf$sos2Bwu$FQ zW6C5|(Vf4~b5TbamaDDHyCoAzeO_4frPyVWgTB}5v{0g}VOm$As6E{C3crUV)?FI? zA#mt+(ED$BJFae{``>!&hkKrR_LEwf7<7$ZlBXLHr3>A&%S7C}`t8Ma<&z+hAyRA{ ziS9r0IIXP@5bEGHUv{0C{-TjN*j9(7dWH59>sm_6ob<8`7}b~gFm4eKDtDc=GD*Sh z9UP2au7CH1jH?R7y^a|ZrEXcaKYdg>tmeuWAinw+Ua?9Zwrx?3c)YS_ql%N9tL8M@ z&gAs=gRM48*__DR?WlS6Gk6#-wpdLDq+NM$9Sj73*CVIe*q&Q$Mx?0oPp*=_4IrXp zEiDW1yK_FyG3KB|7ZBjLX3(Nflr9XYapYm&z{~T+1^_ zENV{6(OpIoBGwID16_}wty9Sad`eG4WB3A;n*(N-gc5}8>yqzEP=iSBkfRVKnr(D> zc0_cx((&$rqia#WUlXMt!)?xP{q;rD7QK12TNbhdt(nKG88AATw)9#`3iZM6#vU!8 zDr+xlIr!Ns)xOz@8B^gOmFBCaw@3<_#Vj8er-oQtzxpZnmpX{Wh``C5b1w8-OqJ8= zs3<<8Is$NEtBI~J?%iz17xfE3e~YlEo+BaqRh>1|)M#%KJ}p^g>*>JL#R@GyatV0Y zQwT+9DmOhN_=)XKqA6{{t#_vK@NDcI2+o%teU)k0jEfzdI`<~}F8dM_=S>qTeT}0@rYX~^2K&ka~4ehhPXR`wM zFed=<21A+u6@0k=1ZhAodDVA~LKaEmP+?(&;>RmbF7}r&hnF~hyovm0_`QKrRl({a z&xrV5Al1PJ|6s3QDnMCm;NyKTn=ardT?WLKxd{Us>1p`iqmHK%ttb0u&MxvoZbi7q zs(jc=*`vk`zgN|m-JSPa0ITu8s|gr}Pj)G&AX=YA0L(?;Aqs$U4Is-Kx3t11 z0HOf!loq2@NuqFI<08bo+O>PbU(h8HE6yNkI@46cBI%qsD7o%3kaDEp&6+SG!+7_m z2OzED|B4nP&=YBpedEaM`M;@s?sG#!I@s@W`Uj1xlc{g#DhEfh?`D>L_;6>R_$J64 z2m=W{-vaFUzw3?`DEZ64@;ZahF9mU2zfy%at(f^OY~56pfYbY%%`4w+y9I#&>pc+o zZ@Dfv>D%(q`ik3$11wK^{7;AnNST&VM(v$I0YEYH*;B)rUGNm9A?8_0T|>H4W%;F* ze^ow=P#HRus0hu!Om(cP5}Gk*(snBu?x(4_PGoN!UE!=&Xg9%l3Xgv=Be&taE+7I5 zP82BnbqgCX38}B20A&6NybFXlKmxB<_$0gqg#Y<5(qry4M0EFDQxM+SHS4uZd^E7{ zcyxJ}|L~hH|IxR*`~u6lQJFS&joy4P!Jw*~inHz(NCn+sr{K>js_z8SM7G zm=eHHkpLRCq(+KV-%B2S44CcfYTjykzzfnqBjBo^6hv_?HaEmdU|IJ-Uu4+4K9j+| zCBM3L9j0>wf$iGe{~p*fA_?EgYlGr$0!H=E6DDL3f9@S11ipy`y8=m{?hwF8GQ1rR zlmd({SQCi8yRTEaeh9|@+l>I>B0$pnFC$=zZ}z+bz;qgo;B^`tVC;1)CjroSs-8=7 zP3r%$383s>(M7;~rGPtkz=StG<$&4vfqC*NJ^#VQeKRtgG7-v+fr+AV25cN!E3F;4l8%LcAb%9s60t>V` zz{T`lDjT>8zMqHC2NFZ^?q@V&z=(LjT7cAT?gKht3p`V;D)~M{N)=c`77#umAUYg3 z=(Vrg2Ci*5FW0sBPyk_cQKOg*F`f;;F-1)w8l@Fr;25St8Q^WJz$Lrdvmfto;6G*s znw@Ax=wOVzz#l^uC<8lV09lCC2ga8ACrnouq^|<}lrzxW6$aP&NPxEoyb(C2>f_^U zQVCRO-vIxu0;Uya{}yx)NZ7Ig)WXQ+r@$$G`J-#mC4&vnBh<-Fj{$yO%r zgtJ|@&(nty3F{Y!vB@^_+B}3%#L6OR@4(p1ztRsdAr<>1_ZP?jT*>1e0?M}L15n@x zS59APPzN8^t2@Equ+JXVXE0E35)V@SqZ51-sMN58f<*2i)w|!3!SZj@HULjM_r2WM z170GZwh2T_#Or#;L15rqrks0(5DI3j`B5;Kkk=HH4gTGkXMq( zbB9(Y0IPwAT^wQt!ryU(0huwovkZs_5{Lt)#DL?#wkpBV#V_O;S&GC*5 zkC#g^yc-JUs6i@82dmHA3`ZQhJQ@fEK#PsDCWb%C_a+y4cxm&nLrY(K?-#Xu^Jfj>qA02($8LkVLKP+|cD3;_T%@(ZxC!7968w(BTWV3-Ux z;#5El`uQKYK2%;ASjvNFB@kA!ES7t*sk8)YMf!R_q||-HR5$p+8_hARt1Jyx(#r8T znvp}R-I{8+=Dj{$rS>zlqDrzp!ps?(If*F< z7_am5Mct%qe$!B4;K}7WmU-AA91*zeGML*eI7;U@wYqIJxgyj##L5 zzb^{^<0EPMZmPY_?M4VBizdg7Xw2seX>@_KsRAp z^C^p{UTYd`Ls~(8&3e~dL0F-LaMH>ozf$1fY0hPT<6WiMZ)7%cy!gQaGNaZC4NX7k zYRef{2QuGGDT!)p?5>4XD$I_IbZ30Nr&}7HDUpV491!+RE@xIrsC9N-9z698&NCHi zw_1`g9Hpz5GU2)peM-G6(15j@>Sw}a(zP3M_GX%9CiygW9V#ssxXW0#kmWgX)#cDO^+MdvLEXx}$g?0sT+b+}zK zO2GPZuzGT8X5oZ9(=geHH~9e<&EZMAuma=LHF*a6Fn)BO)AmTNf^~8tO{%wkP#@-k z7BCj8soSrQ{C2?{@lIbpkmrZlULOy6gmG{bP%E3#v*WnmLJ{x%xz00TlYCK+I*J(O3+;;k}F$3JZa!Tx+H7D zm+HLeWSKSJ$vM8O3slI4Tjc!1Ph<%nf^{=Rrh(j%YX3fa6kyw?K-tGmTNJ9W^Hr?oO}P(3n1ZvQJgi8hy2!9i1uYp&Uc_8?>nEycTi&B z=LKSEP?L&%VG;l7Gae`z4$Z1R0J?}B0RF7Ca#wB#Tu%s$*QL~GMe=mT3ifg!wJXJaToJ` z?|VHZwzI-0?y`9ns%AzajFCn9uE=t2q)akmfK1qSZp{`K^Vqf_hBDKCDu#^cq7>R2 zK2@?S78&=c)OaN+U1ZJc^Fd?m#ICWg?&kYo;$%9pgrqN@?l#apRjrpUEOb4IM~n5w z-}4Z&i^+7Pi7@)nrD#uLgFN2F%IxY?Ea9c2K>tW#wZg zHwU}4PhRVPv3R|+;&2T|I;Lja4$CVuI=X6xs_IVrwkgypXCRua%*fwhj|Sq}4f!n6 zYjL!h7Nl9Icy-xOyWq2fD&9}7)=@2&n0HA~LO$TWb=Oi-XXB_XGpW@~^v~DHbcuxX zswrL(Ayh!Krz12m9Xh)0(*H9ab72IH>hJmN9&$=UV?p>Nx&iEBD24JLLWp(#d@Cuj zEO!4;>L5tuKt2sS9V0?m8=1E|?V<5J>XyFyyoV3I9;20$0aQgf)AAry|7U8VCY#=} zf5oXk=4I^ZD6M?;u4UD1-L9BRMsuQWU?%1q{519E?=An((Qq;Ud!GtL* z`|OKvevFRG|UEMNKeagDl93C^3Y zh!w!8ex=%t`pk8D_jf&AR^>Ir_B$C)r`B(G`EWvb-K^2`T!RnNP;bgk%8$9*^k(fF zbRcl7^6A#o&DBK1j_8TZVk?iB=eHATh+P{Z>TY$-6vp$6b;(hmq8@R4Ri)(FrWvuI z7In}Vun&o}nU-ka47A!E#`q8YN+I&2yORo~1p?CWNf#j3fLyKN776EriW*SSir2Kb|r2e*S8-Y2bu<22HoX zsq9hBwf&ynv*r^SlTBGV&GBB+1LgC{D!M|aXOFw$8Y1sB(dkz+l)BL0;&adZLO{d+ z;-IzsN%GTuPG0jQ8s|UlYf$7i>_>S7pp}oer5+hpddI2gh%s+EDJuCnhLcoV|Q)xX_enz~Q&M8|4jG%qUh+Sm=Ha;aS_0 z@z5@YT%I)^DZ_1YugKBx^uuI?UU)lHiV)LBHX^%VVZGIpQJH3a(sae`# z-JHL$W?eHCso-7@+5v7xZgjEI;5@5|QF*SsG|)E4f-Kuj?Q4lJ=dXluPu8y_`gdsx zoi2HVdex&MIgd?teODJ2A`i?QeI?q@3wW8J>7Jm~rC23U@^a|fYMgRYB#&s<33`#|y?$%80omhLH%N^GFgp|L6rD+#;u$pK8i5ayUX*5#FW9 z;6Hv0Gq&BcT?y77ZwBOB&a;9}!lAkYG2VR$UuwGW2%u&_Gl%?sZmB$`x7`)^BGRti z_D36ZGsQN=BS>%AGwdF~wCX-0-*(liU-bt)SiP7F4I5VKN{Imn23KGf#?lV1C3>*# zSvvFfcOt2NRZ3h>St?QCEej{72cKhfCXFR0Nf=Rcslt_;FdJYyU%`bP^_TVgFqX`< zcoooTqpVma9k8v^xk%`Nz%$IQL3?9wv5_^*`cWdB+oa3to>!$Yl>-Wz_UY}q*|fK5 zxNZ>k^D-0Kn15~G9Ak!IHTLM7?ucb>>34X<6u}8-_s-hma%JUXM8uzJ(;O^I-S#SV zvk`~=x|zp8lChGV=TT^fQ zK0d?zP0mb8vv47R*iy&$lpc^kT%A$=o@q7ncCc=v#|V|0FK*;8hm+SLvkOi&WTIy(+ydlUg=GV1de3NdRscuPETKzNFJ1qHN-*Wx?v`WSEDC3!^G#cL5CX~ri?plRIU}qGLuOWe|lJ$7A|w74G+uzbWC7L^6WJGRX`Rf znQmIEK6yfYELWv1E{{(bvO*P=s$3n_g}GpqG(niTNX+-wW@4=~yoc;fX4c=MNwU90 zhOeI8o%E>$Iv)H=umO`u7G%Gf_u6+8+6Byr_zBU-Ue0aLx> zptfGa5aM>c&Vto=6$gzP6%zB20p0`5lCYv-oOc?uQ(4&o#+IsFyOxaB{Mlk2GxZm{i%Uiov>a?& z4i@H$-~joUjHz0*0HWouF}zHO65A3(iSb%T66waf$>1Jt^b1f^4@0FIDpvg5DVNj` zbQ*JiG6(p~2Ft5o^)j7J&pdYUol&Un&r)l6uW_0cEg#QXWxBESG`?tHXXo0|>J_fc z1YNnP(A0QmM%%0-Rpl#%OJPK;YyCXbE12UT+>?q>r%)?OOiS(egvkwVGykdp<>N#>E94zjF-G@@nY>c15+j!%R1iTeQ{${{Q`VN9;BbMTp1AWF_V9! z@mf+1-&HZl&jXaar{A@%Odp=qTbKKUp($34j`hS2<=L`>;f-nx20Ja#Mz29MF z@l74{jhQ=hh3kEXBKsFh7a1;%J?`HA$1O2HDfoUHoZL&kjq(?p)+Q~Gk?jAC#N+f7T4PZ=|O0l3_aP^h(Tdd2~2shMb zXAbyokZ)8PYX1FFj$aEwEg4Kz$r|Q~7NppPbg(vmK@MMB758yE4D|Wrc~rbYGk<7$ z#5VQa>#XHNf6Ox!h4X?EoQ@plr=NRg+|AnCu8Cp4X(zjCm$t{_?&pb+MJD(l^qmVG z&A|`BNLcrM76+*HoNOo=-=m88s)6O{fz|2bbn|1Ql$I5rMKxe|#QD#a{u=i#&HA>v zwfCD{&AYwc>j^epmzQzLMy77wwE+vl{o^X$a`Q_u4Vn8Es zk<1ugEDH-}kjYA7KL&a_UUgziK;A$n;9w8k4XNgy9`xuRz+Bvre43ntFsq(*TL_LX z=V_RiIG(pyli*nA6~W=wthj))-$@`9{2){vvH_}AarS(S=M5AR~Pil_Ic!S~IVSlY{YAm%%$zX$w0D=kk1PuapG zg8=Dq)kW6*Dz~+6wzB-`L;0}PW?e{asygHCsvojmdupzSZx1Uv)t91T_yPnt%Vwso zpH=hkRJXJzvgdRAJoVaP$GPT%eZ@6o?&!VWE%#>ab;F9SA}?u=3Mut@q&#*c_L{Y3 z*}di>U(7U7DS?{m09#6`)}ZtqJC}|(h^;zYYs;|v-r>FJ!HZCAF{?gv8uV70ZHy2> zuP!D`ANnlX8X*4o26tqy*&T9@r9w6^mj{fb85Ob<^DE3JN!=jsTR9$1kO2~nk z`53meQqgm6u7;+&A?N|GDPQ#t72)_2y%3@)!~ikM*sl`{oTI&fE>h%b>o zM(P#eC*QO0TjN5`c?j!$@^p3UYp$`3TsE^{(ol5^ow~$lcXf<1W)Z>h*#rBBlltPz zZ&zIun;f&gvp}WIif*mmV@-YFjMAEIMlquuNQD*5&s@>TX5vkKVotoK5c77eSrL*- ziBHVP{-lAv`_BhGF6hVhYfxQ?^;h*u{WbGL%Pom)R}8t6DT99NDN4&mJ0vb>vQ_u& z`b7!jPAh8I(7?05L=b4|-BatOogs?3PRh_HvDt*75&14>%~YuVJ!UUMTnM zf6frqW^Iwn(xzRw*p3o)EesME-CEL3?K zB+|7UJ_5wJ&H%)oxpc0}h=hxKb57C8Ag1Ht*YSFtdL2E=!NWT#@gkCP-JhezN-5EJ z@`+7&TGdvH&#^Im!o4p$EzS}i3$xzv3E$QD0=W4k`M3U)^wEy62FFF6(A9)PyU#zy z8zkrZMG!dSm&YD83eVP=eo=GB^;?V!&&Oqgn~x1_zTw$4dW%Irk&H@jIHCCfuI^)H zwe=;z?#_sat_MzJ#J0A!C5KE#vf<9Fdsmu=x`ucH?RfRwU9mU%Sia3661J%$eOoh` z901sk{rH}NHqPcT5Ule7;(>DK8DL0d2()kiHThYV%1N_REOO3AG4ZI|V_lr%xPG1< z>R4wx!H>;+15L1K^Wgql9$e==O=UpWCA<_(x?)mu@Jk%;5~)AdzA~-lUd!2AunN z;`=Giy&ly@qIw&2^t*R0tsor^ywn!&druxB{8_fm*JX+cp-Rwp?S zHbt(zmahKd6&9XVW7K+#k)-{F<+OS&Nx``A=@b>EhNr=3=#*CvVAKy3N#9WX0z;TCT zBHN(eYj{NnPBkF?BBH$Z)%^{SYQ00$Ks(m5LYD^*H;bO-GPB?_YPt1{S2ciEJ{e{v zlqM@T;RyLMHTuHlo(n8(fi5n0yXzB_6{!&iD+$x*=t>p|&g~uZe_83xkqE8UC(aM~ zFXUz}0a%hzdM{+m6r!WboV=g)BIuqeY$^hsEgzNGpdC1>lJhyfxvfXkRCBxLgBbaz z8{Dv9Ps(^(uq-}iS~DH4FlzFO!D7VtvCijCv=cv=+;n$B;bkMoQ=rub{F_Z&(zi95 zC?OdZU{11LaEGU$Bmxtb z^vA{+W^ptCW#>CBj3p>p+sDyw)sh0W(2BlnngGDniAF=2WRBdFyp)THFYR{KSXFQoZPEauFF=K4@kvlc?nwaenP*Df97+NEQD;_QL|8<{{P08|nJ^%O> zR1)|<~R7`I^ zSKFuFDDM;aM*lh69X_ygT6s>!blcm`C%kv`8@8U%Rak81&**Z-G&#EQP&oIF2iheY zM!|_iWKN7ee0;o!j18YlyZvxyR6b|>wIw!mP4=X)h^<16Qv9dNNmI?4O~iokfxv$C z?!(bGllq@@$TK9-;4$QZIw+Hj5s)TCFY1-I(cPz%v=G8@)A>Oam#pO`8IRaZ? z0($*`Df(y21#RBK($AI3!!{BI6Ry#i>c>{o_T^TLO(NI1+) z`W~4h^dzeIiNN&;SVX7?C`Aga9K`*M47IIdbX8F&c0zMlvqC2aR|Y1c+$m@VZ{1?x zhq2EmX4;NiPI(T%T%+B1IjVEI+p!9Z?rjkdby*`Y23H3rD&%uc;Ib950)s92{V|Tx z1A{4do^f>)K$(?Q>*Gi{tc3F_LBGnKa3_cE((G~n7Wab9tkkKQiCC@lF}(Fh>jiym z31|4-rjwiQ4&;vf?V;xIBcc7(#^3>E5s6uleVda$*>t$TAn7NuW$rs(d$-zJojs1b z(8sxVz)i6+fP~6hEAml(MoPOP0=Ku+h@=TOJ|WJs(v8-K)#PsY4~@-YmtKVr*)=pj zmDICvb?ELJSZ^l&q{W!x>#&6=KPdJsZ6fwKXoU6!CKOY~OWo~QbY3hY37Nhb_KHE9 z8(Gl!+!?;oGKkZNBtyt+nHIzT?=lO}Tb8Q+VFLqQ_BESlbc5>iEAn>I@*~zOsVE~| zb!z_^ei&t^+hCa9Dy}gd*S7kitV-i6H|c9j+-jPduSO$wwZF(@N2M=}Y61bk1ijmm z>8~+u7{bAG0DdsCX6GTj;t{jV^8x=rONUFNF6NGYS3tg>o;sCru5cBAfE#>+U>EuZ zQ*tl~CG#&zwU3{UOP%yX4Y?*!J>@Dif@#t#7QYmBsF$)E&HuW&L&I#lyvQPuuKm{%-a;l5Eg3dbn4@zs z9<|9D-|s656aG=`;CE37{`zFRb~i`!x#r?h-&sAi%|MqlaG?9{s*o1!kYk@vGBl|3 z`p4Asx*@|m=xc#FQW3>BN_s_XFu6u(ZDHM(k`^ zaa09zIzq^a2Zop3Q8o?#&Q%~6pjn23aj7+(zS*S)>duSDdSsDMxc+_0?JxsRGrsP5 zH=FxVkiws^Uy7fuS{}nI(yv>jd~FTGTP@)bPmw}vUgssnl#IdUm&}jZ|7}q=>?XqS zbn&|BKH4Q2I8i~2^2xUYQYgRmd}e#aJ(6g4q?x*g2p|Z-tMT?X5a|?2cy?LLNzJ;_ zD#t}SEvkNjT~gWza`5Ako2GxexH0=pE^|*dHnu8+@fo}8kU|t~tIeRdS_?HepTS!~ zxPv-1cXNMy`Lud+;t!p}Pz-Al9l5bo??MX_d1MhA6_L93+w<$~J| zhZsjM9?AbX#mXl3?O&2$OTh JB>07x{{XirAAkS= diff --git a/pkg/indicator/v2/ichimoku1/indicator.go b/pkg/indicator/v2/ichimoku1/indicator.go deleted file mode 100644 index b38e801115..0000000000 --- a/pkg/indicator/v2/ichimoku1/indicator.go +++ /dev/null @@ -1,293 +0,0 @@ -package ichimoku - -import ( - "fmt" - - "github.com/algo-boyz/alphakit/market" - decimal "github.com/algo-boyz/decimal128" - - "github.com/algo-boyz/alphakit/ta/dec" -) - -type IIchimokuIndicator interface { - // out result array sort: [new day -to- old day] - // one call per asset - MakeIchimokuInPast(bars []*market.Kline, numberOfRead int) error - - //one call per asset - PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) - - //Analyse Trigger Cross tenken & kijon sen - AnalyseTriggerCross(previous *IchimokuStatus, bars_only_25_bars_latest []*market.Kline) (*IchimokuStatus, error) - - GetLast() *IchimokuStatus - GetList() []*IchimokuStatus -} - -type IchimokuIndicator struct { - line_helper lineHelper - series []*market.Kline - Ichimokus []*IchimokuStatus - ConversionLine []float64 - BaseLine []float64 - LeadingSpanA []float64 - LeadingSpanB []float64 - laggingSpan []float64 -} - -func NewIndicator() IIchimokuIndicator { - xx := IchimokuIndicator{} - xx.Ichimokus = make([]*IchimokuStatus, 0) - xx.line_helper = NewLineHelper() - return &xx -} - -func (xx *IchimokuIndicator) loadbars(from int, to int) []*market.Kline { - if len(xx.series) == 0 { - return nil - } - if from < 0 { - from = 0 - } - if to > len(xx.series) { - to = len(xx.series) - } - - return xx.series[from:to] - -} - -func (o *IchimokuIndicator) GetList() []*IchimokuStatus { - return o.Ichimokus -} - -func (o *IchimokuIndicator) MakeIchimokuInPast(series []*market.Kline, numberOfRead int) error { - length := len(series) - if length == 0 { - return ErrDataNotFill - } - - if length < numberOfRead || length < 52 { - return ErrNotEnoughData - } - - fmt.Printf("Calc ichi from Last %v days on %d total candles\r\n", numberOfRead, len(series)) - o.series = series - - // descending - bars_len := len(o.series) - for day := 0; day < numberOfRead; day++ { - - from := bars_len - 52 - day - to := bars_len - day - - ic, err := BuildIchimokuStatus(o.loadbars(from, to)) - if err != nil { - return err - } - o.Put(ic) - - } - - for day_index := 0; day_index < o.NumberOfIchimokus(); day_index++ { - item := o.Ichimokus[day_index] - sen_a, sen_b := o.Calc_Cloud_InPast(day_index) - item.Set_SenCo_A_Past(sen_a) - item.Set_SenCo_B_Past(sen_b) - } - - return nil - -} - -// analyse with two days -func (o *IchimokuIndicator) FindStatusin26BarPast() { - - for i := 0; i < o.NumberOfIchimokus(); i++ { - item := o.Ichimokus[i] - sen_a, sen_b := o.Calc_Cloud_InPast(i) - item.Set_SenCo_A_Past(sen_a) - item.Set_SenCo_B_Past(sen_b) - } - -} - -// Analyse Trigger Cross tenken & kijon sen -// bars : contain with new bar -func (o *IchimokuIndicator) AnalyseTriggerCross(previous *IchimokuStatus, _52_bars_latest []*market.Kline) (*IchimokuStatus, error) { - - if len(_52_bars_latest) == 0 { - return nil, ErrDataNotFill - } - - if len(_52_bars_latest) < 52 { - return nil, ErrNotEnoughData - } - - newIchi, e := BuildIchimokuStatus(_52_bars_latest) - - if e != nil { - return nil, e - } - sen_a_in_26_past, sen_b_in_26_past := o.Calc_Cloud_InPast(0) - - if sen_a_in_26_past.isNil || sen_b_in_26_past.isNil { - return nil, ErrChikoStatus26InPastNotMade - } - - newIchi.Set_SenCo_A_Past(sen_a_in_26_past) - newIchi.Set_SenCo_B_Past(sen_b_in_26_past) - - if newIchi.SencoA_Past.isNil || newIchi.SencoB_Past.isNil { - return nil, ErrChikoStatus26InPastNotMade - } - - if !newIchi.bar.Start.After(previous.bar.Start) { - return nil, ErrDateNotGreaterThanPrevious - } - has_collision1, intersection := o.CrossCheck(previous, newIchi) - if has_collision1 == EInterSectionStatus_Find { - newIchi.SetStatus(newIchi.CloudStatus(intersection)) - newIchi.SetCloudSwitching(o.isSwitchCloud(previous, newIchi)) - - return newIchi, nil - } - return nil, nil - -} - -// analyse with two days -func (o *IchimokuIndicator) PreAnalyseIchimoku(data []*IchimokuStatus) (*IchimokuStatus, error) { - - if len(data) != 2 { - return nil, ErrNotEnoughData - } - - current := data[0] - previous := data[1] - - line1_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.TenkenSen.valLine) - line1_point_b := NewPoint(dec.New(current.bar.Start.Unix()), current.TenkenSen.valLine) - - line2_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.KijonSen.valLine) - line2_point_b := NewPoint(dec.New(current.bar.Start.Unix()), current.KijonSen.valLine) - - has_collision1, intersection := o.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) - - if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { - return nil, nil - } - - Line_Eq_A := o.getLineEquation(line1_point_a, line1_point_b) // tenken - Line_Eq_B := o.getLineEquation(line2_point_a, line2_point_b) //kijon - - if line1_point_a == line2_point_a { - return nil, nil //paraller - - } - - if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { - return nil, nil - - } - - if has_collision1 == EInterSectionStatus_Find { - - current.SetStatus(current.CloudStatus(intersection)) - - current.SetCloudSwitching(o.isSwitchCloud(previous, current)) - return current, nil - } - return nil, nil -} - -func (o *IchimokuIndicator) NumberOfIchimokus() int { - return len(o.Ichimokus) -} - -func (o *IchimokuIndicator) GetLast() *IchimokuStatus { - - if o.Ichimokus != nil && len(o.Ichimokus) == 0 { - return nil - } - - latest := o.Ichimokus[0] - - return latest -} -func (o *IchimokuIndicator) Put(v *IchimokuStatus) { - o.Ichimokus = append(o.Ichimokus, v) -} - -// -------------------------------------------------------------------------------------------------------- -func (o *IchimokuIndicator) CrossCheck(previous, newIchi *IchimokuStatus) (EInterSectionStatus, decimal.Decimal) { - line1_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.TenkenSen.valLine) - line1_point_b := NewPoint(dec.New(newIchi.bar.Start.Unix()), newIchi.TenkenSen.valLine) - - line2_point_a := NewPoint(dec.New(previous.bar.Start.Unix()), previous.KijonSen.valLine) - line2_point_b := NewPoint(dec.New(newIchi.bar.Start.Unix()), newIchi.KijonSen.valLine) - - has_collision1, intersection := o.line_helper.GetCollisionDetection(line1_point_a, line1_point_b, line2_point_a, line2_point_b) - - if has_collision1 == EInterSectionStatus(IchimokuStatus_NAN) { - return EInterSectionStatus_NAN, decimal.Zero - } - - Line_Eq_A := o.getLineEquation(line1_point_a, line1_point_b) // tenken - Line_Eq_B := o.getLineEquation(line2_point_a, line2_point_b) //kijon - - if line1_point_a == line2_point_a { - return EInterSectionStatus_NAN, intersection //paraller - - } - - if Line_Eq_A.Slope.Sub(Line_Eq_B.Slope).Cmp(decimal.Zero) == 0 { - return EInterSectionStatus_NAN, intersection - - } - return has_collision1, intersection -} - -// analyse with two days -func (o *IchimokuIndicator) isSwitchCloud(previous, current *IchimokuStatus) bool { - - if previous.SenKoA_Shifted26.valLine.GreaterThanOrEqual(previous.SenKoB_Shifted26.valLine) && - current.SenKoA_Shifted26.valLine.GreaterThan(current.SenKoB_Shifted26.valLine) || - previous.SenKoA_Shifted26.valLine.LessThan(previous.SenKoB_Shifted26.valLine) && - current.SenKoA_Shifted26.valLine.GreaterThanOrEqual(current.SenKoB_Shifted26.valLine) { - if current.TenkenSen.valLine.GreaterThanOrEqual(current.KijonSen.valLine) { - return true - } - } - return false -} - -// find cloud Span A,B in Past (26 day ) -func (o *IchimokuIndicator) Calc_Cloud_InPast(current int) (Point, Point) { - - if o.NumberOfIchimokus() < 26 { - return NewNilPoint(), NewNilPoint() - } - - rem := o.NumberOfIchimokus() - current - max := 26 //from 26 bar in past (find Shift index) - - if rem < max { - return NewNilPoint(), NewNilPoint() - } - - index := current + 25 - c := o.Ichimokus[index] - buff_senco_a := NewPoint(dec.New(c.bar.Start.Unix()/1000), c.SenKoA_Shifted26.valLine) - buff_senco_b := NewPoint(dec.New(c.bar.Start.Unix()/1000), c.SenKoB_Shifted26.valLine) - - return buff_senco_a, buff_senco_b -} - -func (o *IchimokuIndicator) getLineEquation(p1 Point, p2 Point) *Equation { - eq := Equation{} - eq.Slope = (p2.Y.Sub(p1.Y)).Mul(p2.X.Sub(p1.X)) - //eq.Intercept = (-1 * eq.Slope * p1.X) + p1.Y - eq.Intercept = p1.Y.Sub(eq.Slope).Mul(p1.X) - return &eq -} diff --git a/pkg/indicator/v2/ichimoku1/line-value.go b/pkg/indicator/v2/ichimoku1/line-value.go deleted file mode 100644 index cc2ce0c64b..0000000000 --- a/pkg/indicator/v2/ichimoku1/line-value.go +++ /dev/null @@ -1,28 +0,0 @@ -package ichimoku - -import decimal "github.com/algo-boyz/decimal128" - -type ValueLine struct { - valLine decimal.Decimal - isNil bool -} - -func (n *ValueLine) Value() interface{} { - if n.isNil { - return nil - } - return n.valLine -} - -func (n *ValueLine) SetValue(v decimal.Decimal) { - n.valLine = v - n.isNil = false -} - -func NewValue(x decimal.Decimal) ValueLine { - return ValueLine{x, false} -} - -func NewValueLineNil() ValueLine { - return ValueLine{decimal.Zero, true} -} diff --git a/pkg/indicator/v2/ichimoku1/line_helper.go b/pkg/indicator/v2/ichimoku1/line_helper.go deleted file mode 100644 index cab244f355..0000000000 --- a/pkg/indicator/v2/ichimoku1/line_helper.go +++ /dev/null @@ -1,163 +0,0 @@ -package ichimoku - -import ( - "fmt" - - "github.com/algo-boyz/alphakit/ta/dec" - decimal "github.com/algo-boyz/decimal128" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -type lineHelper struct { -} -type EPointLocation int - -const ( - EPointLocation_NAN EPointLocation = 0 - EPointLocation_above EPointLocation = 1 - EPointLocation_below EPointLocation = 2 - EPointLocation_overlap EPointLocation = 3 -) - -func NewLineHelper() lineHelper { - f := lineHelper{} - return f -} - -// check Point above or below line -func (n *lineHelper) isAboveLine(point Point, line []Point) EPointLocation { - zero := fixedpoint.Zero - if len(line) < 2 { - return EPointLocation_NAN - } - - checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) EPointLocation { - //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) - // v := (p.X-line_p_a.X)*(line_p_b.Y-line_p_a.Y) - (p.Y-line_p_a.Y)*(line_p_b.X-line_p_a.X) - yOverX := p.Y.Sub(line_p_a.Y).Mul(line_p_b.X.Sub(line_p_a.X)) - xOverY := p.X.Sub(line_p_a.X).Mul(line_p_b.Y.Sub(line_p_a.Y)) - v := xOverY.Sub(yOverX) - - if v.Cmp(zero) == 0 { - return EPointLocation_overlap - } else if v > zero { - return EPointLocation_above - } else { - return EPointLocation_below - } - } - - return checkAboveOrBelow(point, line[0], line[1]) - -} - -func (n *lineHelper) positionPointInline(point Point, line []Point) decimal.Decimal { - zero := fixedpoint.Zero - - if len(line) < 2 { - return zero - } - - checkAboveOrBelow := func(p Point, line_p_a Point, line_p_b Point) decimal.Decimal { - //var d = (_p_x- _x1) *(_y2-_y1)-(_p_y-_y1)*(_x2-_x1) - return (p.X.Sub(line_p_a.X)).Mul(line_p_b.Y.Sub(line_p_a.Y)).Sub(p.Y.Sub(line_p_a.Y)).Mul(line_p_b.X.Sub(line_p_a.X)) - } - - res := checkAboveOrBelow(point, line[0], line[1]) - - return res - -} - -func (o *lineHelper) GetCollisionDetection(a Point, b Point, c Point, d Point) (EInterSectionStatus, decimal.Decimal) { - - denominator := ((b.X.Sub(a.X)).Mul(d.Y.Sub(c.Y))).Sub((b.Y.Sub(a.Y)).Mul(d.X.Sub(c.X))) - numerator1 := ((a.Y.Sub(c.Y)).Mul(d.X.Sub(c.X))).Sub((a.X.Sub(c.X)).Mul(d.Y.Sub(c.Y))) - numerator2 := ((a.Y.Sub(c.Y)).Mul(b.X.Sub(a.X))).Sub((a.X.Sub(c.X)).Mul(b.Y.Sub(a.Y))) - - // Detect coincident lines (has a problem, read below) - if denominator.Cmp(decimal.Zero) == 0 { - return EInterSectionStatus_NAN, decimal.Zero - } - r := numerator1.Quo(denominator) - s := numerator2.Quo(denominator) - one := dec.New(1) - if (r.GreaterThanOrEqual(decimal.Zero) && - r.LessThanOrEqual(one)) && - (s.GreaterThanOrEqual(decimal.Zero) && - s.LessThanOrEqual(one)) { - // fmt.Printf("collision detec : a:%v , b:%v, c:%v ,d:%v ,r %v s %v\r\n", a, b, c, d, r, s) - intersection := o.get_intersection_point(a, b, c, d) - - return EInterSectionStatus_Collision_Find, intersection - } - return EInterSectionStatus_NAN, decimal.Zero -} - -//line senco A or B -func (o *lineHelper) GetCollisionWithLine(price_point Point, line_clouds []Point) (EPointLocation, error) { - zero := fixedpoint.Zero - - len_line_clouds := len(line_clouds) - if len_line_clouds < 1 { - return EPointLocation_NAN, ErrNotEnoughData - } - // Create a point at infinity, y is same as point p - //x := time.Now().AddDate(0, -1, 0).Unix() - //line1_a := NewPoint(decimal.NewFromInt(x), price_point.Y) - // line1_b := price_point - // line_b := NewPoint(0,price_point) - //var ps EPointLocation = EPointLocation_NaN - below := 0 - above := 0 - fmt.Println("___") - fmt.Printf("Cloud : check point :x:%.0f y:%.0f \r\n", price_point.X.Float64(), price_point.Y.Float64()) - sum := dec.New(0) - for i := 1; i < len_line_clouds; i++ { - line2_a := line_clouds[i-1] - line2_b := line_clouds[i] - //fmt.Printf("Cloud :x:%.0f y:%.0f ,\r\n", line2_a.X, line2_a.Y) - fmt.Printf("%.0f,%.0f,\r\n", line2_a.X.Float64(), line2_a.Y.Float64()) - //res := o.GetCollisionDetection(line1_a, line1_b, line2_a, line2_b) - buff := []Point{line2_a, line2_b} - // res := o.isAboveLine(price_point, buff) - c := o.positionPointInline(price_point, buff) - if c > zero { //below - below++ - } else { - above++ - } - - sum = sum.Add(c) - - } - v := sum.Quo(dec.New(int64(len_line_clouds))) - - if v > zero { - return EPointLocation_below, nil // above - } else { - return EPointLocation_above, nil //below - } - -} -func (o *lineHelper) getLineEquation(p1 Point, p2 Point) *Equation { - eq := Equation{} - x := p1.X.Sub(p2.X) - y := p1.Y.Sub(p2.Y) - eq.Slope = y.Quo(x) - eq.Intercept = dec.New(-1).Mul(eq.Slope).Mul(p1.X).Add(p1.Y) - return &eq -} - -func (o *lineHelper) get_intersection_point(line1_pointA Point, line1_pointB Point, line2_pointA Point, line2_pointB Point) decimal.Decimal { - - tenken := o.getLineEquation(line1_pointA, line1_pointB) - kijon := o.getLineEquation(line2_pointA, line2_pointB) - intercept := kijon.Intercept.Sub(tenken.Intercept) - slope := tenken.Slope.Sub(kijon.Slope) - x_intersection := intercept.Quo(slope) - x := kijon.Slope.Mul(x_intersection) - y_intersection := x.Add(kijon.Intercept) - return y_intersection -} diff --git a/pkg/indicator/v2/ichimoku1/status.go b/pkg/indicator/v2/ichimoku1/status.go deleted file mode 100644 index 24f251cbde..0000000000 --- a/pkg/indicator/v2/ichimoku1/status.go +++ /dev/null @@ -1,150 +0,0 @@ -package ichimoku - -import ( - "fmt" - "time" - - "github.com/algo-boyz/alphakit/market" - decimal "github.com/algo-boyz/decimal128" - - "github.com/c9s/bbgo/pkg/types" -) - -type IchimokuStatus struct { - TenkenSen ValueLine - - //_______________ - - KijonSen ValueLine - - //in the future - SenKoA_Shifted26 ValueLine - - //in the future - SenKoB_Shifted26 ValueLine - - //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) - //SencoA 26 candle in the past (for check) - SencoA_Past Point - //extract value sen A & B from 26 candle past (26 shift forward in calc ichimoku) - //SencoB 26 candle in the past (for check) - SencoB_Past Point - - ChikoSpan *types.KLine //close bar - - bar *types.KLine - //----- - Status EIchimokuStatus - cloudSwitching bool - - line_helper lineHelper -} - -func NewIchimokuStatus(tenken ValueLine, kijon ValueLine, senKoA_Shifted26 ValueLine, senKoB_Shifted52 ValueLine, chiko_span, bar *market.Kline) *IchimokuStatus { - - o := IchimokuStatus{} - - o.TenkenSen = tenken - - o.KijonSen = kijon - - o.SenKoA_Shifted26 = senKoA_Shifted26 - o.SenKoB_Shifted26 = senKoB_Shifted52 - - o.ChikoSpan = chiko_span - o.bar = bar - o.Status = IchimokuStatus_NAN - o.line_helper = NewLineHelper() - - return &o -} - -func (o *IchimokuStatus) SetChikoSpan(v *market.Kline) { - o.ChikoSpan = v -} - -func (o *IchimokuStatus) Set_SenCo_A_Past(p Point) { - o.SencoA_Past = p -} - -func (o *IchimokuStatus) Set_SenCo_B_Past(p Point) { - o.SencoB_Past = p -} - -func (o *IchimokuStatus) SetStatus(status EIchimokuStatus) { - o.Status = status -} - -func (o *IchimokuStatus) GetStatus() EIchimokuStatus { - return o.Status -} - -func (o *IchimokuStatus) SetCloudSwitching(v bool) { - o.cloudSwitching = v -} - -func (o *IchimokuStatus) GetCloudSwitching() bool { - return o.cloudSwitching -} - -func (o *IchimokuStatus) Is_cloud_green() bool { - return o.SenKoA_Shifted26.valLine > o.SenKoB_Shifted26.valLine -} - -func (o *IchimokuStatus) IsChikoAbovePrice() bool { - return o.ChikoSpan.High > o.bar.Close -} - -func (o *IchimokuStatus) CloudStatus(intersection decimal.Decimal) EIchimokuStatus { - if o.SenKoA_Shifted26.isNil || o.SenKoB_Shifted26.isNil { - return IchimokuStatus_NAN - } - if o.SencoA_Past.isNil || o.SencoB_Past.isNil { - return IchimokuStatus_NAN - } - - sen_B := o.SencoB_Past //Senko B in_26_candle_pass - sen_A := o.SencoA_Past //Senko A in_26_candle_pass - if sen_A.Y > intersection && sen_B.Y > intersection { - return IchimokuStatus_Cross_Below - } else if sen_A.Y < intersection && sen_B.Y < intersection { - return IchimokuStatus_Cross_Above - } else if sen_A.Y < intersection && sen_B.Y > intersection || sen_A.Y > intersection && sen_B.Y < intersection { - return IchimokuStatus_Cross_Inside - } - - return IchimokuStatus_NAN - -} - -func (o *IchimokuStatus) GetStatusString() string { - result := "" - switch o.Status { - case IchimokuStatus_NAN: - result = "nan" - - case IchimokuStatus_Cross_Below: - result = "cross below" - case IchimokuStatus_Cross_Above: - result = "cross above" - case IchimokuStatus_Cross_Inside: - result = "cross inside" - } - - return result -} - -func (o *IchimokuStatus) Print() string { - return fmt.Sprintf("ichimoku cloud %v|%v|%v|%v|%v| Green: %v, Chiko UP: %v | status: %v | %v\n", - o.TenkenSen.Value(), - o.KijonSen.Value(), - o.SenKoA_Shifted26.Value(), - o.SenKoB_Shifted26.Value(), - o.ChikoSpan.Close), - o.Is_cloud_green(), - o.IsChikoAbovePrice(), - o.GetStatusString(), - o.bar.StartTime.Time().Format(time.DateTime), - ) - -} diff --git a/pkg/indicator/v2/ichimoku1/tests/analyse_test.go b/pkg/indicator/v2/ichimoku1/tests/analyse_test.go deleted file mode 100644 index c240dd8163..0000000000 --- a/pkg/indicator/v2/ichimoku1/tests/analyse_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package tests - -import ( - "testing" - "time" - - "github.com/algo-boyz/alphakit/market" - "github.com/stretchr/testify/assert" - - "github.com/algo-boyz/alphakit/ta/ichimoku" -) - -var ( - interval = time.Minute * 30 - //52 bar - ts = []*market.Kline{ - {L: d(8110), H: d(8180), C: d(8160), O: d(8110), Volume: d(664372.00), Start: p(1667201400000)}, - {L: d(8100), H: d(8260), C: d(8200), O: d(8150), Volume: d(1241301.00), Start: p(1667205000000)}, - {L: d(8110), H: d(8450), C: d(8440), O: d(8170), Volume: d(2909458.00), Start: p(1667280600000)}, - {L: d(8310), H: d(8450), C: d(8360), O: d(8440), Volume: d(778238.00), Start: p(1667284200000)}, - {L: d(8240), H: d(8370), C: d(8260), O: d(8360), Volume: d(658420.00), Start: p(1667287800000)}, - {L: d(8240), H: d(8450), C: d(8440), O: d(8260), Volume: d(1814124.00), Start: p(1667291400000)}, - {L: d(8270), H: d(8440), C: d(8300), O: d(8440), Volume: d(1267103.00), Start: p(1667367000000)}, - {L: d(8270), H: d(8510), C: d(8510), O: d(8300), Volume: d(1821017.00), Start: p(1667370600000)}, - {L: d(8430), H: d(8540), C: d(8440), O: d(8510), Volume: d(559250.00), Start: p(1667374200000)}, - {L: d(8420), H: d(8470), C: d(8440), O: d(8440), Volume: d(544851.00), Start: p(1667377800000)}, - {L: d(8480), H: d(8730), C: d(8730), O: d(8550), Volume: d(4284720.00), Start: p(1667626200000)}, - {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(1382828.00), Start: p(1667629800000)}, - {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(1678201.00), Start: p(1667633400000)}, - {L: d(8730), H: d(8730), C: d(8730), O: d(8730), Volume: d(549277.00), Start: p(1667637000000)}, - {L: d(8800), H: d(9070), C: d(9060), O: d(8800), Volume: d(5342062.00), Start: p(1667712600000)}, - {L: d(9040), H: d(9070), C: d(9070), O: d(9060), Volume: d(8126959.00), Start: p(1667716200000)}, - {L: d(9070), H: d(9070), C: d(9070), O: d(9070), Volume: d(527101.00), Start: p(1667719800000)}, - {L: d(9070), H: d(9070), C: d(9070), O: d(9070), Volume: d(702521.00), Start: p(1667723400000)}, - {L: d(9160), H: d(9440), C: d(9430), O: d(9290), Volume: d(4409696.00), Start: p(1667799000000)}, - {L: d(9410), H: d(9490), C: d(9490), O: d(9420), Volume: d(7522839.00), Start: p(1667802600000)}, - {L: d(9490), H: d(9490), C: d(9490), O: d(9490), Volume: d(777299.00), Start: p(1667806200000)}, - {L: d(9490), H: d(9490), C: d(9490), O: d(9490), Volume: d(405416.00), Start: p(1667809800000)}, - {L: d(9300), H: d(9890), C: d(9530), O: d(9890), Volume: d(7097789.00), Start: p(1667885400000)}, - {L: d(9460), H: d(9570), C: d(9470), O: d(9520), Volume: d(3033312.00), Start: p(1667889000000)}, - {L: d(9380), H: d(9490), C: d(9410), O: d(9470), Volume: d(2714433.00), Start: p(1667892600000)}, - {L: d(9390), H: d(9490), C: d(9450), O: d(9420), Volume: d(3876877.00), Start: p(1667896200000)}, - {L: d(9250), H: d(9540), C: d(9410), O: d(9350), Volume: d(3448605.00), Start: p(1667971800000)}, - {L: d(9400), H: d(9840), C: d(9800), O: d(9410), Volume: d(6547559.00), Start: p(1667975400000)}, - {L: d(9640), H: d(9830), C: d(9650), O: d(9800), Volume: d(2416825.00), Start: p(1667979000000)}, - {L: d(9650), H: d(9860), C: d(9680), O: d(9700), Volume: d(2463503.00), Start: p(1667982600000)}, - {L: d(9640), H: d(9870), C: d(9800), O: d(9750), Volume: d(2000789.00), Start: p(1668231000000)}, - {L: d(9520), H: d(9800), C: d(9520), O: d(9780), Volume: d(3214849.00), Start: p(1668234600000)}, - {L: d(9520), H: d(9680), C: d(9620), O: d(9550), Volume: d(3019512.00), Start: p(1668238200000)}, - {L: d(9610), H: d(9810), C: d(9740), O: d(9640), Volume: d(2473212.00), Start: p(1668241800000)}, - {L: d(9450), H: d(9710), C: d(9530), O: d(9710), Volume: d(1455003.00), Start: p(1668317400000)}, - {L: d(9510), H: d(9700), C: d(9700), O: d(9520), Volume: d(1341450.00), Start: p(1668321000000)}, - {L: d(9520), H: d(9720), C: d(9650), O: d(9700), Volume: d(2922575.00), Start: p(1668324600000)}, - {L: d(9470), H: d(9650), C: d(9470), O: d(9650), Volume: d(907574.00), Start: p(1668328200000)}, - {L: d(9250), H: d(9620), C: d(9250), O: d(9510), Volume: d(1573592.00), Start: p(1668403800000)}, - {L: d(9220), H: d(9420), C: d(9380), O: d(9270), Volume: d(1372258.00), Start: p(1668407400000)}, - {L: d(9340), H: d(9530), C: d(9490), O: d(9380), Volume: d(3147032.00), Start: p(1668411000000)}, - {L: d(9370), H: d(9550), C: d(9370), O: d(9490), Volume: d(2153637.00), Start: p(1668414600000)}, - {L: d(9380), H: d(9750), C: d(9670), O: d(9450), Volume: d(1861478.00), Start: p(1668490200000)}, - {L: d(9580), H: d(9700), C: d(9650), O: d(9670), Volume: d(2890813.00), Start: p(1668493800000)}, - {L: d(9610), H: d(9700), C: d(9670), O: d(9610), Volume: d(1288957.00), Start: p(1668497400000)}, - {L: d(9630), H: d(9800), C: d(9730), O: d(9650), Volume: d(2413843.00), Start: p(1668501000000)}, - {L: d(9580), H: d(9780), C: d(9630), O: d(9750), Volume: d(803830.00), Start: p(1668576600000)}, - {L: d(9630), H: d(9720), C: d(9670), O: d(9650), Volume: d(699785.00), Start: p(1668580200000)}, - {L: d(9640), H: d(9700), C: d(9640), O: d(9700), Volume: d(393592.00), Start: p(1668583800000)}, - {L: d(9580), H: d(9660), C: d(9630), O: d(9640), Volume: d(1443871.00), Start: p(1668587400000)}, - {L: d(9300), H: d(9600), C: d(9370), O: d(9510), Volume: d(3845936.00), Start: p(1668835800000)}, - {L: d(9310), H: d(9380), C: d(9330), O: d(9380), Volume: d(1380628.00), Start: p(1668839400000)}, - } -) - -func Test_26DayinThePastNotExist(t *testing.T) { - - indicator := ichimoku.NewIndicator() - - indicator.MakeIchimokuInPast(ts, 1) - - _, e1 := indicator.AnalyseTriggerCross(indicator.GetLast(), ts) - - assert.Equal(t, e1, ichimoku.ErrChikoStatus26InPastNotMade) - -} -func TestInside(t *testing.T) { - - indicator := ichimoku.NewIndicator() - - today := ichimoku.NewIchimokuStatus( - ichimoku.NewValue(d(8705)), - ichimoku.NewValue(d(8710)), - ichimoku.NewValue(d(8707)), - ichimoku.NewValue(d(8930)), - &market.Kline{}, - &market.Kline{L: d(8400), H: d(8460), C: d(8440), O: d(8440), Volume: d(906352), Start: p(1664699400000)}) - - yesterday := ichimoku.NewIchimokuStatus( - ichimoku.NewValue(d(8720)), - ichimoku.NewValue(d(8710)), - ichimoku.NewValue(d(8715)), - ichimoku.NewValue(d(8940)), - &market.Kline{}, - &market.Kline{L: d(8430), H: d(8480), C: d(8450), O: d(8460), Volume: d(652416), Start: p(1664695800000)}) - - lines_result := make([]*ichimoku.IchimokuStatus, 2) - lines_result[0] = today //today - lines_result[1] = yesterday - - a, e := indicator.PreAnalyseIchimoku(lines_result) - assert.Empty(t, e) - assert.Equal(t, a.Status, ichimoku.IchimokuStatus_Cross_Above) - -} - -func p(v int64) time.Time { - return time.UnixMilli(v).UTC() -} diff --git a/pkg/indicator/v2/ichimoku1/tests/cloud_test.go b/pkg/indicator/v2/ichimoku1/tests/cloud_test.go deleted file mode 100644 index eea4ed7de5..0000000000 --- a/pkg/indicator/v2/ichimoku1/tests/cloud_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package tests - -import ( - "testing" - - decimal "github.com/algo-boyz/decimal128" - "github.com/stretchr/testify/assert" - - "github.com/algo-boyz/alphakit/ta/dec" - "github.com/algo-boyz/alphakit/ta/ichimoku" -) - -func i(v int64) decimal.Decimal { - return dec.New(v) -} - -func d(v float64) decimal.Decimal { - return dec.New(v) -} - -func TestCheckCloud_Above(t *testing.T) { - - h1_above_ := []ichimoku.Point{ - {X: i(1667802600), Y: d(8762.00)}, - {X: i(1667806200), Y: d(8882.00)}, - {X: i(1667809800), Y: d(8908.00)}, - {X: i(1667885400), Y: d(8928.00)}, - {X: i(1667889000), Y: d(9152.00)}, - {X: i(1667892600), Y: d(9222.00)}, - {X: i(1667896200), Y: d(9238.00)}, - {X: i(1667971800), Y: d(9238.00)}, - {X: i(1667975400), Y: d(9260.00)}, - {X: i(1667979000), Y: d(9285.00)}, - {X: i(1667982600), Y: d(9318.00)}, - {X: i(1668231000), Y: d(9318.00)}, - {X: i(1668234600), Y: d(9318.00)}, - {X: i(1668238200), Y: d(9320.00)}, - {X: i(1668241800), Y: d(9320.00)}, - {X: i(1668317400), Y: d(9358.00)}, - {X: i(1668321000), Y: d(9358.00)}, - {X: i(1668324600), Y: d(9410.00)}, - {X: i(1668328200), Y: d(9485.00)}, - {X: i(1668403800), Y: d(9485.00)}, - {X: i(1668407400), Y: d(9435.00)}, - {X: i(1668411000), Y: d(9430.00)}, - {X: i(1668414600), Y: d(9490.00)}, - {X: i(1668490200), Y: d(9498.00)}, - {X: i(1668493800), Y: d(9482.00)}, - } - line_helper := ichimoku.NewLineHelper() - point_from_price := ichimoku.NewPoint(dec.New(1668497400/1000), d(9670)) - res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) - - //fmt.Println("senko A", res_senko_a, "err:", err) - assert.Equal(t, res_senko_a, ichimoku.EPointLocation_above) - assert.Empty(t, err) - -} -func TestCheckCloud_below(t *testing.T) { - - h1_above_ := []ichimoku.Point{ - {X: i(1666589400), Y: d(8660.00)}, - {X: i(1666593000), Y: d(8660.00)}, - {X: i(1666596600), Y: d(8618.00)}, - {X: i(1666600200), Y: d(8555.00)}, - {X: i(1666675800), Y: d(8548.00)}, - {X: i(1666679400), Y: d(8502.00)}, - {X: i(1666683000), Y: d(8435.00)}, - {X: i(1666686600), Y: d(8435.00)}, - {X: i(1666762200), Y: d(8430.00)}, - {X: i(1666765800), Y: d(8360.00)}, - {X: i(1666769400), Y: d(8300.00)}, - {X: i(1666773000), Y: d(8282.00)}, - {X: i(1667021400), Y: d(8282.00)}, - {X: i(1667025000), Y: d(8282.00)}, - {X: i(1667028600), Y: d(8240.00)}, - {X: i(1667032200), Y: d(8160.00)}, - {X: i(1667107800), Y: d(8120.00)}, - {X: i(1667111400), Y: d(8120.00)}, - {X: i(1667115000), Y: d(8112.00)}, - {X: i(1667118600), Y: d(8110.00)}, - {X: i(1667194200), Y: d(8098.00)}, - {X: i(1667197800), Y: d(8100.00)}, - {X: i(1667201400), Y: d(8060.00)}, - {X: i(1667205000), Y: d(8052.00)}, - {X: i(1667280600), Y: d(8055.00)}, - } - line_helper := ichimoku.NewLineHelper() - point_from_price := ichimoku.NewPoint(dec.New(1667284200/1000), d(8360)) - res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) - - assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) - assert.Empty(t, err) - -} -func TestCheckCloud_below1(t *testing.T) { - // h1 shegoya Tue Oct 2022 18 10:00:00 - - h1_above_ := []ichimoku.Point{ - {X: i(1665819000), Y: d(8745.00)}, - {X: i(1665822600), Y: d(8750.00)}, - {X: i(1665898200), Y: d(8750.00)}, - {X: i(1665901800), Y: d(8730.00)}, - {X: i(1665905400), Y: d(8725.00)}, - {X: i(1665909000), Y: d(8712.00)}, - {X: i(1665984600), Y: d(8692.00)}, - {X: i(1665988200), Y: d(8692.00)}, - {X: i(1665991800), Y: d(8680.00)}, - {X: i(1665995400), Y: d(8680.00)}, - {X: i(1666071000), Y: d(8680.00)}, - } - line_helper := ichimoku.NewLineHelper() - point_from_price := ichimoku.NewPoint(dec.New(1666074600/1000), d(8650)) - res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) - - assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) - assert.Empty(t, err) - -} -func TestCheckCloud_below3(t *testing.T) { - //|2022 Tue Nov 1 10:00:00 - h1_above_ := []ichimoku.Point{ - {X: i(1666589400), Y: d(8660.00)}, - {X: i(1666593000), Y: d(8660.00)}, - {X: i(1666596600), Y: d(8618.00)}, - {X: i(1666600200), Y: d(8555.00)}, - {X: i(1666675800), Y: d(8548.00)}, - {X: i(1666679400), Y: d(8502.00)}, - {X: i(1666683000), Y: d(8435.00)}, - {X: i(1666686600), Y: d(8435.00)}, - {X: i(1666762200), Y: d(8430.00)}, - {X: i(1666765800), Y: d(8360.00)}, - {X: i(1666769400), Y: d(8300.00)}, - {X: i(1666773000), Y: d(8282.00)}, - {X: i(1667021400), Y: d(8282.00)}, - {X: i(1667025000), Y: d(8282.00)}, - {X: i(1667028600), Y: d(8240.00)}, - {X: i(1667032200), Y: d(8160.00)}, - {X: i(1667107800), Y: d(8120.00)}, - {X: i(1667111400), Y: d(8120.00)}, - {X: i(1667115000), Y: d(8112.00)}, - {X: i(1667118600), Y: d(8110.00)}, - {X: i(1667194200), Y: d(8098.00)}, - {X: i(1667197800), Y: d(8100.00)}, - {X: i(1667201400), Y: d(8060.00)}, - {X: i(1667205000), Y: d(8052.00)}, - {X: i(1667280600), Y: d(8055.00)}, - } - line_helper := ichimoku.NewLineHelper() - point_from_price := ichimoku.NewPoint(dec.New(1667284200/1000), dec.New(8360)) - res_senko_a, err := line_helper.GetCollisionWithLine(point_from_price, h1_above_) - - //fmt.Println("senko A", res_senko_a, "err:", err) - assert.Equal(t, res_senko_a, ichimoku.EPointLocation_below) - assert.Empty(t, err) - -} diff --git a/pkg/indicator/v2/ichimoku1/types.go b/pkg/indicator/v2/ichimoku1/types.go deleted file mode 100644 index 97e7171e08..0000000000 --- a/pkg/indicator/v2/ichimoku1/types.go +++ /dev/null @@ -1,70 +0,0 @@ -package ichimoku - -import ( - "errors" - - decimal "github.com/algo-boyz/decimal128" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -var ( - ErrBuildFailed = errors.New("build failed") - ErrNotEnoughData = errors.New("not enough data") - ErrDataNotFill = errors.New("data not fill") - ErrChikoStatus26InPastNotMade = errors.New("chiko status 26 in past not reached") - ErrDateNotGreaterThanPrevious = errors.New("date is not greater than previous") -) - -type Point struct { - X, Y fixedpoint.Value - isNil bool -} - -func NewPoint(x, y fixedpoint.Value) Point { - p := Point{} - p.X = x - p.Y = y - p.isNil = false - return p -} -func NewNilPoint() Point { - p := Point{} - p.X = fixedpoint.NewFromInt(-1) - p.Y = fixedpoint.NewFromInt(-1) - p.isNil = true - return p -} - -type Equation struct { - Slope decimal.Decimal - Intercept decimal.Decimal -} - -type EInterSectionStatus int - -const ( - EInterSectionStatus_NAN EInterSectionStatus = 0 - EInterSectionStatus_Find EInterSectionStatus = 1 - EInterSectionStatus_Parallel EInterSectionStatus = 2 - EInterSectionStatus_Collision_Find EInterSectionStatus = 1 -) - -type ELine int - -const ( - Line_Tenkan_sen ELine = 9 - Line_kijon_sen ELine = 26 - Line_spanPeriod ELine = 52 - Line_chikoPeriod ELine = 26 //-26 -) - -type EIchimokuStatus int - -const ( - IchimokuStatus_NAN EIchimokuStatus = 0 - IchimokuStatus_Cross_Inside EIchimokuStatus = 1 - IchimokuStatus_Cross_Below EIchimokuStatus = 2 - IchimokuStatus_Cross_Above EIchimokuStatus = 3 - IchimokuStatus_overLab EIchimokuStatus = 4 -) diff --git a/pkg/indicator/v2/lookback.go b/pkg/indicator/v2/lookback.go deleted file mode 100644 index c599fa9f6f..0000000000 --- a/pkg/indicator/v2/lookback.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 The Coln Group Ltd -// SPDX-License-Identifier: MIT - -package indicatorv2 - -// Lookback returns a value from series at n index ago. -// Series must be in chronological order, with the earliest value at slice index 0. -// n = 0 returns the latest value. n = 1 returns the value before the latest etc. -func Lookback[T any](series []T, n int) T { - var empty T - i := (len(series) - n) - 1 - if i < 0 { - return empty - } - return series[i] -} - -// Window returns a copied slice of series starting at n index ago. -// Semantics of n argument are the same as Lookback function. -func Window[T any](series []T, n int) []T { - - ln := len(series) - if ln <= n { - window := make([]T, ln) - copy(window, series) - return window - } - - i := (ln - n) - 1 - window := make([]T, n+1) - copy(window, series[i:]) - - return window -} - -// WindowAppend appends a value to the end of the series and slices it to the window starting at n index ago. -// Semantics of n argument are the same as Window and Lookback functions. -func WindowAppend[T any](series []T, n int, v T) []T { - return Window(append(series, v), n) -} diff --git a/pkg/indicator/v2/maxval.go b/pkg/indicator/v2/maxval.go new file mode 100644 index 0000000000..b9f6d5e2e3 --- /dev/null +++ b/pkg/indicator/v2/maxval.go @@ -0,0 +1,41 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/indicator/v2/bst" + "github.com/c9s/bbgo/pkg/types" +) + +type MaxValueStream struct { + *types.Float64Series + bst *bst.Tree + buffer []float64 + window int +} + +func MaxValue(source types.Float64Source, window int) *MaxValueStream { + s := &MaxValueStream{ + Float64Series: types.NewFloat64Series(), + bst: bst.New(), + buffer: make([]float64, window), + window: window, + } + + s.Bind(source, s) + + return s +} + +func (s *MaxValueStream) Calculate(v float64) float64 { + s.bst.Insert(v) + var i = s.Slice.Length() + if i > 0 { + s.bst.Remove(s.buffer[i%s.window]) + } + + s.buffer[i%s.window] = v + return s.bst.Max().(float64) +} + +func (s *MaxValueStream) Truncate() { + s.Slice = s.Slice.Truncate(s.window + 100) +} diff --git a/pkg/indicator/v2/maxval_test.go b/pkg/indicator/v2/maxval_test.go new file mode 100644 index 0000000000..a131dae7f5 --- /dev/null +++ b/pkg/indicator/v2/maxval_test.go @@ -0,0 +1,24 @@ +package indicatorv2 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestMaximumValueIndicator(t *testing.T) { + t.Run("rolling max series", func(t *testing.T) { + data := []float64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1} + // expected := []float64{10, 10, 10, 10, 9, 8, 7, 6, 5, 4} + + source := types.NewFloat64Series() + ind := MaxValue(source, 4) + + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 4.0, ind.Last(0)) + }) +} diff --git a/pkg/indicator/v2/minval.go b/pkg/indicator/v2/minval.go new file mode 100644 index 0000000000..b56fbbe0c3 --- /dev/null +++ b/pkg/indicator/v2/minval.go @@ -0,0 +1,41 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/indicator/v2/bst" + "github.com/c9s/bbgo/pkg/types" +) + +type MinValueStream struct { + *types.Float64Series + bst *bst.Tree + buffer []float64 + window int +} + +func MinValue(source types.Float64Source, window int) *MinValueStream { + s := &MinValueStream{ + Float64Series: types.NewFloat64Series(), + bst: bst.New(), + buffer: make([]float64, window), + window: window, + } + + s.Bind(source, s) + + return s +} + +func (s *MinValueStream) Calculate(v float64) float64 { + s.bst.Insert(v) + var i = s.Slice.Length() + if i > 0 { + s.bst.Remove(s.buffer[i%s.window]) + } + + s.buffer[i%s.window] = v + return s.bst.Min().(float64) +} + +func (s *MinValueStream) Truncate() { + s.Slice = s.Slice.Truncate(s.window + 100) +} diff --git a/pkg/indicator/v2/minval_test.go b/pkg/indicator/v2/minval_test.go new file mode 100644 index 0000000000..d607a1787e --- /dev/null +++ b/pkg/indicator/v2/minval_test.go @@ -0,0 +1,24 @@ +package indicatorv2 + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestMinimumValueIndicator(t *testing.T) { + t.Run("rolling min series", func(t *testing.T) { + data := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + // expected := []float64{1, 1, 1, 1, 2, 3, 4, 5, 6, 7} + + source := types.NewFloat64Series() + ind := MinValue(source, 4) + + for _, d := range data { + source.PushAndEmit(d) + } + assert.Equal(t, 7.0, ind.Last(0)) + }) +} diff --git a/pkg/indicator/v2/momentum/awesome_osc_test.go b/pkg/indicator/v2/momentum/awesome_osc_test.go new file mode 100644 index 0000000000..df62f967c0 --- /dev/null +++ b/pkg/indicator/v2/momentum/awesome_osc_test.go @@ -0,0 +1,55 @@ +package momentum + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_AwesomeOscillator(t *testing.T) { + tests := []struct { + name string + high []float64 + low []float64 + want floats.Slice + }{ + { + name: "AwesomeOscillator", + high: []float64{24.63, 24.69, 24.99, 25.36, 25.19, 25.17, 25.01, 24.96, 25.08, 25.25, 25.21, 25.37, 25.61, 25.58, 25.46, 25.33, 25.09, 25.03, 24.91, 24.89, 25.13, 24.63, 24.69, 24.99, 25.36, 25.19, 25.17, 25.01, 24.96, 25.08, 25.25, 25.21, 25.37, 25.61, 25.58, 25.46, 25.33, 25.09, 25.03, 24.91, 24.89, 25.13}, + low: []float64{24.63, 24.69, 24.99, 25.36, 25.19, 25.17, 25.01, 24.96, 25.08, 25.25, 25.21, 25.37, 25.61, 25.58, 25.46, 25.33, 25.09, 25.03, 24.91, 24.89, 25.13, 24.63, 24.69, 24.99, 25.36, 25.19, 25.17, 25.01, 24.96, 25.08, 25.25, 25.21, 25.37, 25.61, 25.58, 25.46, 25.33, 25.09, 25.03, 24.91, 24.89, 25.13}, + want: floats.Slice{0.0, 0.17, 0.24, 0.26, 0.28, 0.23, 0.12, -0.01, -0.12, -0.16}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stream := &types.StandardStream{} + prices := v2.HL2(v2.KLines(stream, "", "")) + + ind := AwesomeOscillator(prices) + + for _, k := range buildKLines(tt.high, tt.low) { + stream.EmitKLineClosed(k) + + } + + if assert.Equal(t, len(tt.want)+32, len(ind.Slice)) { + for i, v := range tt.want { + assert.InDelta(t, v, ind.Slice[i+32], 0.005, "Expected awesome_osc.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } + } + }) + } +} + +func buildKLines(high, low []float64) (klines []types.KLine) { + for i := range high { + klines = append(klines, types.KLine{High: n(high[i]), Low: n(low[i])}) + } + + return klines +} diff --git a/pkg/indicator/v2/momentum/awseome_osc.go b/pkg/indicator/v2/momentum/awseome_osc.go new file mode 100644 index 0000000000..3e161fc486 --- /dev/null +++ b/pkg/indicator/v2/momentum/awseome_osc.go @@ -0,0 +1,79 @@ +package momentum + +import ( + "fmt" + + "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/types" +) + +// https://github.com/Nikhil-Adithyan/Algorithmic-Trading-with-Awesome-Oscillator-in-Python/blob/master/Strategy_code.py +type AwesomeOscillatorStream struct { + // embedded structs + *types.Float64Series + sma5 *trend.SMAStream + sma34 *trend.SMAStream +} + +// Awesome Oscillator. +// +// Median Price = ((Low + High) / 2) >> need HL2Source +// AO = 5-Period SMA - 34-Period SMA. +// +// Returns ao. +func AwesomeOscillator(source types.Float64Source) *AwesomeOscillatorStream { + s := &AwesomeOscillatorStream{ + Float64Series: types.NewFloat64Series(), + sma5: trend.SMA(source, 5), + sma34: trend.SMA(source, 34), + } + s.Bind(source, s) + return s +} + +func (s *AwesomeOscillatorStream) Calculate(v float64) float64 { + if s.Length() < 33 { + return 0 + } + ao := 0.0 + if s.Slice.Length() > 0 { + ao = s.sma5.Last(0) - s.sma34.Last(0) + + var ( + prevao = s.sma5.Last(0) - s.sma34.Last(0) + currDiff = ao - v + prevDiff = prevao - s.Slice.Last(0) + crossOver = CrossOver(currDiff, prevDiff, 0) + crossUnder = CrossUnder(currDiff, prevDiff, 0) + ) + if crossOver { + fmt.Println("awesome oscillator changed to green: ", ao) + } + if crossUnder { + fmt.Println("awesome oscillator changed to red: ", ao) + } + } + + return ao +} + +func (s *AwesomeOscillatorStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} + +// todo move this +// CrossOver returns true if the latest series values cross above x +func CrossOver(curr, prev, x float64) bool { + if prev < x && curr > x { + return true + } + return false +} + +// CrossDown returns true if the latest series values cross below x +func CrossUnder(curr, prev, x float64) bool { + if prev > x && curr < x { + return true + } + return false +} diff --git a/pkg/indicator/v2/momentum/chaikin_osc.go b/pkg/indicator/v2/momentum/chaikin_osc.go new file mode 100644 index 0000000000..a9d0cddd74 --- /dev/null +++ b/pkg/indicator/v2/momentum/chaikin_osc.go @@ -0,0 +1,41 @@ +package momentum + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/indicator/v2/volume" + "github.com/c9s/bbgo/pkg/types" +) + +// The DefaultChaikinOscillator function calculates Chaikin +// Oscillator with the most frequently used fast and short +// periods, 3 and 10. +// +// Returns co, ad. +func NewChaikinOscillatorDefault(source v2.KLineSubscription) *ChaikinOscillatorStream { + return ChaikinOscillator(source, 3, 10) +} + +type ChaikinOscillatorStream struct { + // embedded structs + *types.Float64Series +} + +func ChaikinOscillator(source v2.KLineSubscription, slow, fast int) *ChaikinOscillatorStream { + var ( + accDist = volume.AccumulationDistribution(source) + diff = v2.Subtract(trend.EWMA2(accDist, slow), trend.EWMA2(accDist, fast)) + s = &ChaikinOscillatorStream{ + Float64Series: types.NewFloat64Series(), + } + ) + source.AddSubscriber(func(kLine types.KLine) { + s.PushAndEmit(diff.Last(0)) + }) + + return s +} + +func (s *ChaikinOscillatorStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/momentum/chaikin_osc_test.go b/pkg/indicator/v2/momentum/chaikin_osc_test.go new file mode 100644 index 0000000000..a5b72661e4 --- /dev/null +++ b/pkg/indicator/v2/momentum/chaikin_osc_test.go @@ -0,0 +1,41 @@ +package momentum + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_ChaikinOscillator(t *testing.T) { + ts := []types.KLine{ + {Volume: n(100), Low: n(1), Close: n(5), High: n(10)}, + {Volume: n(200), Low: n(2), Close: n(6), High: n(11)}, + {Volume: n(300), Low: n(3), Close: n(7), High: n(12)}, + {Volume: n(400), Low: n(4), Close: n(8), High: n(13)}, + {Volume: n(500), Low: n(5), Close: n(9), High: n(14)}, + {Volume: n(600), Low: n(6), Close: n(10), High: n(15)}, + {Volume: n(700), Low: n(7), Close: n(11), High: n(16)}, + {Volume: n(800), Low: n(8), Close: n(12), High: n(17)}, + } + + expected := []float64{0, -7.41, -18.52, -31.69, -46.09, -61.27, -76.95, -92.97} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ChaikinOscillator(kLines, 2, 5) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected chaikin_osc.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} + +func n(n float64) fixedpoint.Value { + return fixedpoint.NewFromFloat(n) +} diff --git a/pkg/indicator/v2/stoch.go b/pkg/indicator/v2/momentum/stoch.go similarity index 87% rename from pkg/indicator/v2/stoch.go rename to pkg/indicator/v2/momentum/stoch.go index fe0d300867..3a95241213 100644 --- a/pkg/indicator/v2/stoch.go +++ b/pkg/indicator/v2/momentum/stoch.go @@ -1,7 +1,8 @@ -package indicatorv2 +package momentum import ( "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -26,15 +27,15 @@ type StochStream struct { window int dPeriod int - highPrices, lowPrices *PriceStream + highPrices, lowPrices *v2.PriceStream updateCallbacks []func(k, d float64) } // Stochastic Oscillator -func Stoch(source KLineSubscription, window, dPeriod int) *StochStream { - highPrices := HighPrices(source) - lowPrices := LowPrices(source) +func Stoch(source v2.KLineSubscription, window, dPeriod int) *StochStream { + highPrices := v2.HighPrices(source) + lowPrices := v2.LowPrices(source) s := &StochStream{ window: window, diff --git a/pkg/indicator/v2/stoch_test.go b/pkg/indicator/v2/momentum/stoch_test.go similarity index 99% rename from pkg/indicator/v2/stoch_test.go rename to pkg/indicator/v2/momentum/stoch_test.go index 73a3becca2..3d632d96bc 100644 --- a/pkg/indicator/v2/stoch_test.go +++ b/pkg/indicator/v2/momentum/stoch_test.go @@ -1,4 +1,4 @@ -package indicatorv2 +package momentum import ( "encoding/json" @@ -7,6 +7,7 @@ import ( "time" "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -57,7 +58,7 @@ func TestSTOCH2_update(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := KLines(stream, "", "") + kLines := v2.KLines(stream, "", "") kd := Stoch(kLines, tt.window, DPeriod) for _, k := range tt.kLines { diff --git a/pkg/indicator/v2/stochstream_callbacks.go b/pkg/indicator/v2/momentum/stochstream_callbacks.go similarity index 93% rename from pkg/indicator/v2/stochstream_callbacks.go rename to pkg/indicator/v2/momentum/stochstream_callbacks.go index b4bc8bb80c..00e8f34920 100644 --- a/pkg/indicator/v2/stochstream_callbacks.go +++ b/pkg/indicator/v2/momentum/stochstream_callbacks.go @@ -1,6 +1,6 @@ // Code generated by "callbackgen -type StochStream"; DO NOT EDIT. -package indicatorv2 +package momentum import () diff --git a/pkg/indicator/v2/momentum/williams_r.go b/pkg/indicator/v2/momentum/williams_r.go new file mode 100644 index 0000000000..510f62d092 --- /dev/null +++ b/pkg/indicator/v2/momentum/williams_r.go @@ -0,0 +1,55 @@ +package momentum + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// Williams R. Determine overbought and oversold. + +// Developed by Larry Williams, Williams %R is a momentum indicator that is +// the inverse of the Fast Stochastic Oscillator. Also referred to as %R, +// Williams %R reflects the level of the close relative to the highest high +// for the look-back period. In contrast, the Stochastic Oscillator reflects +// the level of the close relative to the lowest low. %R corrects for the +// inversion by multiplying the raw value by -100. As a result, the Fast +// Stochastic Oscillator and Williams %R produce the exact same lines, but +// with different scaling. Williams %R oscillates from 0 to -100; readings +// from 0 to -20 are considered overbought, while readings from -80 to -100 +// are considered oversold. Unsurprisingly, signals derived from the Stochastic +// Oscillator are also applicable to Williams %R. +// +// https://school.stockcharts.com/doku.php?id=technical_indicators:williams_r +// https://www.investopedia.com/terms/w/williamsr.asp +// +// WR = (Highest High - Closing) / (Highest High - Lowest Low) * -100. +// +// Buy when -80 and below. Sell when -20 and above. +type WilliamsRStream struct { + // embedded structs + *types.Float64Series + min *v2.MinValueStream + max *v2.MaxValueStream +} + +func WilliamsR(source v2.KLineSubscription, window int) *WilliamsRStream { + s := &WilliamsRStream{ + Float64Series: types.NewFloat64Series(), + min: v2.MinValue(v2.LowPrices(source), window), + max: v2.MaxValue(v2.HighPrices(source), window), + } + source.AddSubscriber(func(v types.KLine) { + + highestHigh := s.max.Last(0) + lowestLow := s.min.Last(0) + var w = (highestHigh - v.Close.Float64()) / (highestHigh - lowestLow) * -100 + + s.PushAndEmit(w) + }) + + return s +} + +func (s *WilliamsRStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/momentum/williams_r_test.go b/pkg/indicator/v2/momentum/williams_r_test.go new file mode 100644 index 0000000000..f8477740ee --- /dev/null +++ b/pkg/indicator/v2/momentum/williams_r_test.go @@ -0,0 +1,60 @@ +package momentum + +import ( + "encoding/json" + "slices" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_WilliamsR(t *testing.T) { + high := []byte(`[127.0090,127.6159,126.5911,127.3472,128.1730,128.4317,127.3671,126.4220,126.8995,126.8498,125.6460,125.7156,127.1582,127.7154,127.6855,128.2228,128.2725,128.0934,128.2725,127.7353,128.7700,129.2873,130.0633,129.1182,129.2873,128.4715,128.0934,128.6506,129.1381,128.6406]`) + low := []byte(`[125.3574,126.1633,124.9296,126.0937,126.8199,126.4817,126.0340,124.8301,126.3921,125.7156,124.5615,124.5715,125.0689,126.8597,126.6309,126.8001,126.7105,126.8001,126.1335,125.9245,126.9891,127.8148,128.4715,128.0641,127.6059,127.5960,126.9990,126.8995,127.4865,127.3970]`) + close := []byte(`[125.3574,126.1633,124.9296,126.0937,126.8199,126.4817,126.0340,124.8301,126.3921,125.7156,124.5615,124.5715,125.0689,127.2876,127.1781,128.0138,127.1085,127.7253,127.0587,127.3273,128.7103,127.8745,128.5809,128.6008,127.9342,128.1133,127.5960,127.5960,128.6904,128.2725]`) + buildKLines := func(high, low, close []fixedpoint.Value) (kLines []types.KLine) { + for i := range high { + kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i]}) + } + return kLines + } + var h, l, c []fixedpoint.Value + _ = json.Unmarshal(high, &h) + _ = json.Unmarshal(low, &l) + _ = json.Unmarshal(close, &c) + + expected := []float64{ + -29.561779752984485, + -32.391090899695165, + -10.797891581830443, + -34.189447573768696, + -18.252286703529535, + -35.476202780218095, + -25.470223659391287, + -1.4185576808844131, + -29.89546743408507, + -26.943909266058082, + -26.582209458722687, + -38.76870971266242, + -39.04372897645341, + -59.61389774813938, + -59.61389774813938, + -33.171450662027304, + -43.26858026481079, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := WilliamsR(kLines, 14) + k := buildKLines(h, l, c) + for _, candle := range k { + stream.EmitKLineClosed(candle) + } + slices.Reverse(expected) + for i, v := range expected { + assert.InDelta(t, v, ind.Last(i), 0.000001, "Expected williamsR.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/indicator/v2/pattern/abondoned_baby.go b/pkg/indicator/v2/pattern/abondoned_baby.go index 1a773ee4b2..327143a9e0 100644 --- a/pkg/indicator/v2/pattern/abondoned_baby.go +++ b/pkg/indicator/v2/pattern/abondoned_baby.go @@ -19,6 +19,7 @@ func AbondonedBaby(source v2.KLineSubscription) *AbondonedBabyStream { } source.AddSubscriber(func(kLine types.KLine) { + var ( i = source.Length() output = Neutral @@ -53,9 +54,13 @@ func AbondonedBaby(source v2.KLineSubscription) *AbondonedBabyStream { } } - s.PushAndEmit(output) + s.Float64Series.PushAndEmit(output) }) return s } + +func (s *AbondonedBabyStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/abondoned_baby_test.go b/pkg/indicator/v2/pattern/abondoned_baby_test.go index 973c72fa34..5922914d41 100644 --- a/pkg/indicator/v2/pattern/abondoned_baby_test.go +++ b/pkg/indicator/v2/pattern/abondoned_baby_test.go @@ -9,9 +9,9 @@ import ( func TestAbandonedBaby(t *testing.T) { ts := []types.KLine{ - {Open: 90, Low: 85, High: 105, Close: 100}, - {Open: 125, Low: 120, High: 135, Close: 130}, - {Open: 110, Low: 92, High: 115, Close: 95}, + {Open: n(90), Low: n(85), High: n(105), Close: n(100)}, + {Open: n(125), Low: n(120), High: n(135), Close: n(130)}, + {Open: n(110), Low: n(92), High: n(115), Close: n(95)}, } stream := &types.StandardStream{} @@ -24,6 +24,6 @@ func TestAbandonedBaby(t *testing.T) { expectedBear := -1.0 if ind.Last(0) != expectedBear { - t.Errorf("TestAbandonedBaby Bear unexpected result: got %v want %v", ind, expectedBear) + t.Errorf("TestAbandonedBaby Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) } } diff --git a/pkg/indicator/v2/pattern/belthold.go b/pkg/indicator/v2/pattern/belthold.go index 7b57b856b8..02d462343d 100644 --- a/pkg/indicator/v2/pattern/belthold.go +++ b/pkg/indicator/v2/pattern/belthold.go @@ -57,3 +57,7 @@ func Belthold(source v2.KLineSubscription) *BeltholdStream { return s } + +func (s *BeltholdStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/belthold_test.go b/pkg/indicator/v2/pattern/belthold_test.go index c742825d13..ea05022292 100644 --- a/pkg/indicator/v2/pattern/belthold_test.go +++ b/pkg/indicator/v2/pattern/belthold_test.go @@ -10,8 +10,8 @@ import ( func TestBelthold(t *testing.T) { ts := []types.KLine{ - {Open: 60, Low: 55, High: 75, Close: 70}, - {Open: 100, Low: 75, High: 100, Close: 80}, + {Open: n(60), Low: n(55), High: n(75), Close: n(70)}, + {Open: n(100), Low: n(75), High: n(100), Close: n(80)}, } stream := &types.StandardStream{} @@ -28,8 +28,8 @@ func TestBelthold(t *testing.T) { } ts = []types.KLine{ - {Open: 120, Low: 100, High: 125, Close: 105}, - {Open: 70, Low: 70, High: 95, Close: 90}, + {Open: n(120), Low: n(100), High: n(125), Close: n(105)}, + {Open: n(70), Low: n(70), High: n(95), Close: n(90)}, } ind = Belthold(kLines) diff --git a/pkg/indicator/v2/pattern/breakaway.go b/pkg/indicator/v2/pattern/breakaway.go index 4e63755e6f..29868557d9 100644 --- a/pkg/indicator/v2/pattern/breakaway.go +++ b/pkg/indicator/v2/pattern/breakaway.go @@ -60,3 +60,7 @@ func BreakAway(source v2.KLineSubscription) *BreakAwayStream { return s } + +func (s *BreakAwayStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/breakaway_test.go b/pkg/indicator/v2/pattern/breakaway_test.go index 085fe76284..0315c2e112 100644 --- a/pkg/indicator/v2/pattern/breakaway_test.go +++ b/pkg/indicator/v2/pattern/breakaway_test.go @@ -9,11 +9,11 @@ import ( func TestBreakAway(t *testing.T) { ts := []types.KLine{ - {Open: 70, Low: 60, High: 85, Close: 80}, - {Open: 115, Low: 110, High: 125, Close: 120}, - {Open: 120, Low: 115, High: 130, Close: 125}, - {Open: 125, Low: 120, High: 135, Close: 130}, - {Open: 125, Low: 95, High: 130, Close: 100}, + {Open: n(70), Low: n(60), High: n(85), Close: n(80)}, + {Open: n(115), Low: n(110), High: n(125), Close: n(120)}, + {Open: n(120), Low: n(115), High: n(130), Close: n(125)}, + {Open: n(125), Low: n(120), High: n(135), Close: n(130)}, + {Open: n(125), Low: n(95), High: n(130), Close: n(100)}, } stream := &types.StandardStream{} @@ -30,11 +30,11 @@ func TestBreakAway(t *testing.T) { } ts = []types.KLine{ - {Open: 130, Low: 115, High: 135, Close: 120}, - {Open: 100, Low: 85, High: 105, Close: 90}, - {Open: 95, Low: 80, High: 100, Close: 85}, - {Open: 90, Low: 75, High: 95, Close: 80}, - {Open: 85, Low: 80, High: 115, Close: 110}, + {Open: n(130), Low: n(115), High: n(135), Close: n(120)}, + {Open: n(100), Low: n(85), High: n(105), Close: n(90)}, + {Open: n(95), Low: n(80), High: n(100), Close: n(85)}, + {Open: n(90), Low: n(75), High: n(95), Close: n(80)}, + {Open: n(85), Low: n(80), High: n(115), Close: n(110)}, } ind = BreakAway(kLines) diff --git a/pkg/indicator/v2/pattern/dark_cloud.go b/pkg/indicator/v2/pattern/dark_cloud.go index 0214fcda0c..52f06acb54 100644 --- a/pkg/indicator/v2/pattern/dark_cloud.go +++ b/pkg/indicator/v2/pattern/dark_cloud.go @@ -46,3 +46,7 @@ func DarkCloud(source v2.KLineSubscription) *DarkCloudStream { return s } + +func (s *DarkCloudStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji.go b/pkg/indicator/v2/pattern/doji.go index ff4edbbd7b..358d0f45f8 100644 --- a/pkg/indicator/v2/pattern/doji.go +++ b/pkg/indicator/v2/pattern/doji.go @@ -24,7 +24,7 @@ func Doji(source v2.KLineSubscription, maxDiff float64) *DojiStream { highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, maxDiff) ) - if openEqualClose && lowEqualsClose == highEqualsOpen { + if openEqualClose && lowEqualsClose && highEqualsOpen { output = Bull } s.PushAndEmit(output) @@ -32,3 +32,7 @@ func Doji(source v2.KLineSubscription, maxDiff float64) *DojiStream { return s } + +func (s *DojiStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly.go b/pkg/indicator/v2/pattern/doji_dragon_fly.go index 96e1f835dc..06ad563f24 100644 --- a/pkg/indicator/v2/pattern/doji_dragon_fly.go +++ b/pkg/indicator/v2/pattern/doji_dragon_fly.go @@ -8,30 +8,20 @@ import ( type DojiDragonFlyStream struct { *types.Float64Series - - window int } -func DojiDragonFly(source v2.KLineSubscription) *DojiDragonFlyStream { +func DojiDragonFly(source v2.KLineSubscription, maxDiff float64) *DojiDragonFlyStream { s := &DojiDragonFlyStream{ Float64Series: types.NewFloat64Series(), - window: 2, } source.AddSubscriber(func(kLine types.KLine) { var ( - i = source.Length() - output = Neutral - ) - if i < s.window { - s.PushAndEmit(output) - return - } - var ( - one = source.Last(0) - openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, 0.001) - highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, 0.001) - lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, 0.001) + output = Neutral + one = kLine + openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) + highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) + lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, maxDiff) ) if openEqualClose && highEqualsOpen && !lowEqualsClose { @@ -43,3 +33,7 @@ func DojiDragonFly(source v2.KLineSubscription) *DojiDragonFlyStream { return s } + +func (s *DojiDragonFlyStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly_test.go b/pkg/indicator/v2/pattern/doji_dragon_fly_test.go index 20e580534f..4abd171f05 100644 --- a/pkg/indicator/v2/pattern/doji_dragon_fly_test.go +++ b/pkg/indicator/v2/pattern/doji_dragon_fly_test.go @@ -9,31 +9,31 @@ import ( func TestDojiDragonFly(t *testing.T) { ts := []types.KLine{ - {Open: n(30.10), Low: n(30.10), High: n(30.13), Close: n(28.10)}, + {Open: n(30.10), Low: n(28.10), High: n(30.13), Close: n(30.09)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := DojiDragonFly(kLines) + ind := DojiDragonFly(kLines, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) } - expectedBear := -1.0 - - if ind.Last(0) != expectedBear { - t.Errorf("TestDojiDragonFly Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + expectedBull := 1.0 + if ind.Last(0) != expectedBull { + t.Errorf("TestDojiDragonFly Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) } ts = []types.KLine{ {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, } - ind = DojiDragonFly(kLines) + ind = DojiDragonFly(kLines, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) } - expectedBull := 1.0 + expectedBull = 1.0 - if ind.Last(0) != expectedBull { - t.Errorf("TestDojiDragonFly Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + if ind.Last(0) == expectedBull { + t.Errorf("TestDojiDragonFly Not Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) } } diff --git a/pkg/indicator/v2/pattern/doji_gravestone.go b/pkg/indicator/v2/pattern/doji_gravestone.go index afe4e62de4..04d035ed24 100644 --- a/pkg/indicator/v2/pattern/doji_gravestone.go +++ b/pkg/indicator/v2/pattern/doji_gravestone.go @@ -8,38 +8,33 @@ import ( type DojiGraveStoneStream struct { *types.Float64Series - - window int } -func DojiGraveStone(source v2.KLineSubscription) *DojiGraveStoneStream { +func DojiGraveStone(source v2.KLineSubscription, maxDiff float64) *DojiGraveStoneStream { s := &DojiGraveStoneStream{ Float64Series: types.NewFloat64Series(), - window: 2, } source.AddSubscriber(func(kLine types.KLine) { var ( - i = source.Length() - output = Neutral - ) - if i < s.window { - s.PushAndEmit(output) - return - } - var ( - one = source.Last(0) - openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, 0.001) - highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, 0.001) - lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, 0.001) + output = Neutral + one = kLine + openEqualClose = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) + highEqualsOpen = fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) + lowEqualsClose = fixedpoint.ApproxEqual(one.Close, one.Low, maxDiff) ) if openEqualClose && lowEqualsClose && !highEqualsOpen { output = Bear } + s.PushAndEmit(output) }) return s } + +func (s *DojiGraveStoneStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji_gravestone_test.go b/pkg/indicator/v2/pattern/doji_gravestone_test.go index 6de2c730ca..32f5b4fed8 100644 --- a/pkg/indicator/v2/pattern/doji_gravestone_test.go +++ b/pkg/indicator/v2/pattern/doji_gravestone_test.go @@ -8,14 +8,15 @@ import ( ) func TestDojiGraveStone(t *testing.T) { - ts := []types.KLine{ - {Open: n(30.10), Low: n(36.13), High: n(30.13), Close: n(30.12)}, + hasPattern := []types.KLine{ + {Open: n(30.10), Low: n(30.12), High: n(36.13), Close: n(30.13)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := DojiGraveStone(kLines) + ind := DojiGraveStone(kLines, 0.05) - for _, candle := range ts { + for _, candle := range hasPattern { stream.EmitKLineClosed(candle) } expectedBear := -1.0 @@ -24,17 +25,16 @@ func TestDojiGraveStone(t *testing.T) { t.Errorf("TestDojiGraveStone Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) } - ts = []types.KLine{ + noPattern := []types.KLine{ {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, } - ind = DojiGraveStone(kLines) + ind = DojiGraveStone(kLines, 0.01) - for _, candle := range ts { + for _, candle := range noPattern { stream.EmitKLineClosed(candle) } - expectedBull := 1.0 - if ind.Last(0) != expectedBull { - t.Errorf("TestDojiGraveStone Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + if ind.Last(0) == expectedBear { + t.Errorf("TestDojiGraveStone Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) } } diff --git a/pkg/indicator/v2/pattern/doji_long_legged.go b/pkg/indicator/v2/pattern/doji_long_legged.go index 3191e5e9f4..65c7c9955e 100644 --- a/pkg/indicator/v2/pattern/doji_long_legged.go +++ b/pkg/indicator/v2/pattern/doji_long_legged.go @@ -37,9 +37,9 @@ func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { if four.Close > four.Open { if three.Close > three.Open { if two.Close > two.Open { - if fixedpoint.Abs((one.Close-one.Open)/one.Open) < threshold { - if fixedpoint.Abs((one.High-one.Open)/one.Open) > limit { - if fixedpoint.Abs((one.Close-one.Low)/one.Low) > limit { + if fixedpoint.Abs(one.Close.Sub(one.Open).Div(one.Open)) < threshold { + if fixedpoint.Abs(one.High.Sub(one.Open).Div(one.Open)) > limit { + if fixedpoint.Abs(one.Close.Sub(one.Low).Div(one.Low)) > limit { output = Bear } } @@ -52,9 +52,9 @@ func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { if four.Close < four.Open { if three.Close < three.Open { if two.Close < two.Open { - if fixedpoint.Abs((one.Open-one.Close)/one.Close) < threshold { - if fixedpoint.Abs((one.Low-one.Close)/one.Close) > limit { - if fixedpoint.Abs((one.Open-one.High)/one.High) > limit { + if fixedpoint.Abs(one.Open.Sub(one.Close).Div(one.Close)) < threshold { + if fixedpoint.Abs(one.Low.Sub(one.Close).Div(one.Close)) > limit { + if fixedpoint.Abs(one.Open.Sub(one.High).Div(one.High)) > limit { output = Bull } } @@ -69,3 +69,7 @@ func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { return s } + +func (s *DojiLongLeggedStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji_long_legged_test.go b/pkg/indicator/v2/pattern/doji_long_legged_test.go index 3ea84122a3..38db4b6d08 100644 --- a/pkg/indicator/v2/pattern/doji_long_legged_test.go +++ b/pkg/indicator/v2/pattern/doji_long_legged_test.go @@ -9,10 +9,10 @@ import ( func TestDojiLongLegged(t *testing.T) { ts := []types.KLine{ - {Open: 85, Low: 80, High: 95, Close: 90}, - {Open: 95, Low: 90, High: 105, Close: 100}, - {Open: 105, Low: 100, High: 115, Close: 110}, - {Open: 170, Low: 120, High: 210, Close: 160}, + {Open: n(85), Low: n(80), High: n(95), Close: n(90)}, + {Open: n(95), Low: n(90), High: n(105), Close: n(100)}, + {Open: n(105), Low: n(100), High: n(115), Close: n(110)}, + {Open: n(170), Low: n(120), High: n(210), Close: n(160)}, } stream := &types.StandardStream{} @@ -29,10 +29,10 @@ func TestDojiLongLegged(t *testing.T) { } ts = []types.KLine{ - {Open: 90, Low: 80, High: 95, Close: 85}, - {Open: 100, Low: 90, High: 105, Close: 95}, - {Open: 110, Low: 100, High: 115, Close: 105}, - {Open: 160, Low: 120, High: 210, Close: 170}, + {Open: n(90), Low: n(80), High: n(95), Close: n(85)}, + {Open: n(100), Low: n(90), High: n(105), Close: n(95)}, + {Open: n(110), Low: n(100), High: n(115), Close: n(105)}, + {Open: n(160), Low: n(120), High: n(210), Close: n(170)}, } ind = DojiLongLegged(kLines) diff --git a/pkg/indicator/v2/pattern/doji_star.go b/pkg/indicator/v2/pattern/doji_star.go index b61103876d..95bac42ec4 100644 --- a/pkg/indicator/v2/pattern/doji_star.go +++ b/pkg/indicator/v2/pattern/doji_star.go @@ -1,6 +1,7 @@ package pattern import ( + "github.com/c9s/bbgo/pkg/fixedpoint" v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +13,7 @@ type DojiStarStream struct { } // maxDiff is the maximum deviation between a and b to consider them approximately equal -func DojiStar(source v2.KLineSubscription, maxDiff float64) *DojiStarStream { +func DojiStar(source v2.KLineSubscription, direction Direction, maxDiff float64) *DojiStarStream { s := &DojiStarStream{ Float64Series: types.NewFloat64Series(), window: 3, @@ -28,37 +29,41 @@ func DojiStar(source v2.KLineSubscription, maxDiff float64) *DojiStarStream { s.PushAndEmit(output) return } - var ( - three = source.Last(2) - two = source.Last(1) - one = source.Last(0) - firstMidpoint = (three.Open + three.Close) / 2 - isFirstBearish = three.Close < three.Open - isThirdBullish = one.Close > one.Open - gapExists = two.High < three.Low && - two.Low < three.Low && - one.Open > two.High && - two.Close < one.Open - doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two) + dojiExists = doji.Last(1) == Bull ) - var dojiExists = doji.Last(0) == Bull - if isFirstBearish && dojiExists && isThirdBullish && gapExists && doesCloseAboveFirstMidpoint { - output = Bull + if direction == Bullish { + var ( + isFirstBearish = three.Close < three.Open + isThirdBullish = one.Close > one.Open + gapExists = two.High < three.Low && + two.Low < three.Low && + one.Open > two.High && + two.Close < one.Open + doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + ) + + if isFirstBearish && dojiExists && isThirdBullish && gapExists && doesCloseAboveFirstMidpoint { + output = Bull + } } else { var ( - isFirstBullish = two.Close > two.Open + isFirstBullish = three.Close > three.Open isThirdBearish = one.Open > one.Close + gapExists = two.High > three.High && + two.Low > three.High && + one.Open < two.Low && + two.Close > one.Open + doesCloseBelowFirstMidpoint = one.Close < firstMidpoint ) - gapExists = two.High > three.High && - two.Low > three.High && - one.Open < two.Low && - two.Close > one.Open - var doesCloseBelowFirstMidpoint = one.Close < firstMidpoint + if isFirstBullish && dojiExists && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { output = Bear } - } s.PushAndEmit(output) @@ -67,3 +72,7 @@ func DojiStar(source v2.KLineSubscription, maxDiff float64) *DojiStarStream { return s } + +func (s *DojiStarStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/doji_star_test.go b/pkg/indicator/v2/pattern/doji_star_test.go index 7e1650453f..3ec28b72fc 100644 --- a/pkg/indicator/v2/pattern/doji_star_test.go +++ b/pkg/indicator/v2/pattern/doji_star_test.go @@ -13,9 +13,10 @@ func TestDojiStar(t *testing.T) { {Open: n(22.20), Low: n(21.87), High: n(22.40), Close: n(22.22)}, {Open: n(21.60), Low: n(19.30), High: n(22.05), Close: n(19.45)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := DojiStar(kLines, 0.01) + ind := DojiStar(kLines, Bearish, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -31,7 +32,9 @@ func TestDojiStar(t *testing.T) { {Open: n(20.30), Low: n(20.10), High: n(20.45), Close: n(20.30)}, {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(21.58)}, } - ind = DojiStar(kLines, 0.01) + stream = &types.StandardStream{} + kLines = v2.KLines(stream, "", "") + ind = DojiStar(kLines, Bullish, 0.01) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/doji_test.go b/pkg/indicator/v2/pattern/doji_test.go index 8f4d87265a..d5cbc22220 100644 --- a/pkg/indicator/v2/pattern/doji_test.go +++ b/pkg/indicator/v2/pattern/doji_test.go @@ -11,30 +11,31 @@ func TestDoji(t *testing.T) { ts := []types.KLine{ {Open: n(30.10), Low: n(32.10), High: n(30.13), Close: n(28.10)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := Doji(kLines, 0.01) + ind := Doji(kLines, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) } - expectedBear := -1.0 + hasPattern := 1.0 - if ind.Last(0) != expectedBear { - t.Errorf("TestDojiGraveStone Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + if ind.Last(0) == hasPattern { + t.Errorf("TestDoji Bear unexpected result: got %v want %v", ind.Last(0), hasPattern) } ts = []types.KLine{ {Open: n(30.10), Low: n(30.11), High: n(30.10), Close: n(30.09)}, } - ind = Doji(kLines, 0.01) + ind = Doji(kLines, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) } - expectedBull := 1.0 + hasPattern = 1.0 - if ind.Last(0) != expectedBull { - t.Errorf("TestDojiGraveStone Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + if ind.Last(0) != hasPattern { + t.Errorf("TestDoji Bull unexpected result: got %v want %v", ind.Last(0), hasPattern) } } diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap.go b/pkg/indicator/v2/pattern/downside_tazuki_gap.go index ccefb90d8c..c117e00e7c 100644 --- a/pkg/indicator/v2/pattern/downside_tazuki_gap.go +++ b/pkg/indicator/v2/pattern/downside_tazuki_gap.go @@ -14,7 +14,7 @@ type TazukiGapStream struct { func TazukiGap(source v2.KLineSubscription) *TazukiGapStream { s := &TazukiGapStream{ Float64Series: types.NewFloat64Series(), - window: 2, + window: 3, } source.AddSubscriber(func(kLine types.KLine) { @@ -50,3 +50,7 @@ func TazukiGap(source v2.KLineSubscription) *TazukiGapStream { return s } + +func (s *TazukiGapStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go b/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go index d2fd4b64a7..00d69da423 100644 --- a/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go +++ b/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go @@ -15,7 +15,7 @@ func TestTazukiGap(t *testing.T) { } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := Doji(kLines, 0.01) + ind := TazukiGap(kLines) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/engulfing.go b/pkg/indicator/v2/pattern/engulfing.go index 0481ac8fcf..f5b6f06922 100644 --- a/pkg/indicator/v2/pattern/engulfing.go +++ b/pkg/indicator/v2/pattern/engulfing.go @@ -55,3 +55,7 @@ func Engulfing(source v2.KLineSubscription) *EngulfingStream { return s } + +func (s *EngulfingStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/engulfing_test.go b/pkg/indicator/v2/pattern/engulfing_test.go index 07929545bb..90db9e8c7f 100644 --- a/pkg/indicator/v2/pattern/engulfing_test.go +++ b/pkg/indicator/v2/pattern/engulfing_test.go @@ -9,8 +9,8 @@ import ( func TestEngulfing(t *testing.T) { ts := []types.KLine{ - {Open: 80, Low: 75, High: 95, Close: 90}, - {Open: 100, Low: 65, High: 105, Close: 70}, + {Open: n(80), Low: n(75), High: n(95), Close: n(90)}, + {Open: n(100), Low: n(65), High: n(105), Close: n(70)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -26,8 +26,8 @@ func TestEngulfing(t *testing.T) { } ts = []types.KLine{ - {Open: 90, Low: 75, High: 95, Close: 80}, - {Open: 70, Low: 65, High: 105, Close: 100}, + {Open: n(90), Low: n(75), High: n(95), Close: n(80)}, + {Open: n(70), Low: n(65), High: n(105), Close: n(100)}, } ind = Engulfing(kLines) diff --git a/pkg/indicator/v2/pattern/hammerstick.go b/pkg/indicator/v2/pattern/hammerstick.go deleted file mode 100644 index 598600bcc9..0000000000 --- a/pkg/indicator/v2/pattern/hammerstick.go +++ /dev/null @@ -1,65 +0,0 @@ -package pattern - -import ( - "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/types" -) - -type HammerStickStream struct { - *types.Float64Series - inverted bool - window int -} - -func HammerStick(source v2.KLineSubscription, multiplier float64, inverted ...bool) *HammerStickStream { - var i bool - if len(inverted) > 0 { - i = true - } - - s := &HammerStickStream{ - Float64Series: types.NewFloat64Series(), - window: 2, - inverted: i, - } - - source.AddSubscriber(func(kLine types.KLine) { - var ( - i = source.Length() - output = Neutral - ) - if i < s.window { - s.PushAndEmit(output) - return - } - var ( - one = source.Last(0) - oc = one.Open - one.Close - co = one.Close - one.Open - isBearishHammer = one.Open > one.Close && - fixedpoint.ApproxEqual(one.Open, one.High, multiplier) && - oc >= 2*(one.Close-one.Low) - isBearishInvertedHammer = one.Open > one.Close && - fixedpoint.ApproxEqual(one.Close, one.Low, multiplier) && - oc <= 2*(one.High-one.Open) - isBullishHammer = one.Close > one.Open && - fixedpoint.ApproxEqual(one.Close, one.High, multiplier) && - co <= 2*(one.Open-one.Low) - isBullishInvertedHammer = one.Close > one.Open && - fixedpoint.ApproxEqual(one.Open, one.Low, multiplier) && - co <= 2*(one.High-one.Close) - ) - - if !s.inverted && isBearishHammer || s.inverted && isBearishInvertedHammer { - output = Bear - } else if !s.inverted && isBullishHammer || s.inverted && isBullishInvertedHammer { - output = Bull - } - - s.PushAndEmit(output) - - }) - - return s -} diff --git a/pkg/indicator/v2/pattern/hammerstick_test.go b/pkg/indicator/v2/pattern/hammerstick_test.go deleted file mode 100644 index 7e561bd83c..0000000000 --- a/pkg/indicator/v2/pattern/hammerstick_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package pattern - -import ( - "testing" - - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/types" -) - -func TestHammerStick(t *testing.T) { - ts := []types.KLine{ - {Open: n(30.10), Low: n(10.06), High: n(30.10), Close: n(26.13)}, - } - stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") - ind := HammerStick(kLines, 0.01) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - expectedBear := -1.0 - - if ind.Last(0) != expectedBear { - t.Errorf("TestHammerStick Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) - } - - ts = []types.KLine{ - {Open: n(26.13), Low: n(30.10), High: n(30.10), Close: n(10.06)}, - } - ind = HammerStick(kLines, 0.01) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - expectedBull := 1.0 - - if ind.Last(0) != expectedBull { - t.Errorf("TestHammerStick Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) - } -} - -func TestHammerStickInverted(t *testing.T) { - ts := []types.KLine{ - {Open: n(30.10), Low: n(26.13), High: n(52.06), Close: n(26.13)}, - } - stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") - ind := HammerStick(kLines, 0.01) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - expectedBear := -1.0 - - if ind.Last(0) != expectedBear { - t.Errorf("TestHammerStick Inverted Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) - } - - ts = []types.KLine{ - {Open: n(26.13), Low: n(30.10), High: n(52.06), Close: n(30.10)}, - } - ind = HammerStick(kLines, 0.01) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - expectedBull := -1.0 - - if ind.Last(0) != expectedBull { - t.Errorf("TestHammerStick Inverted Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) - } -} diff --git a/pkg/indicator/v2/pattern/harami.go b/pkg/indicator/v2/pattern/harami.go index 6c1a72444c..cde9183df4 100644 --- a/pkg/indicator/v2/pattern/harami.go +++ b/pkg/indicator/v2/pattern/harami.go @@ -54,3 +54,7 @@ func Harami(source v2.KLineSubscription) *HaramiStream { return s } + +func (s *HaramiStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/harami_cross.go b/pkg/indicator/v2/pattern/harami_cross.go index 2069f68368..8fc1f078ea 100644 --- a/pkg/indicator/v2/pattern/harami_cross.go +++ b/pkg/indicator/v2/pattern/harami_cross.go @@ -12,7 +12,7 @@ type HaramiCrossStream struct { window int } -func HaramiCross(source v2.KLineSubscription, maxDiff float64) *HaramiCrossStream { +func HaramiCross(source v2.KLineSubscription, direction Direction, maxDiff float64) *HaramiCrossStream { s := &HaramiCrossStream{ Float64Series: types.NewFloat64Series(), window: 2, @@ -28,24 +28,28 @@ func HaramiCross(source v2.KLineSubscription, maxDiff float64) *HaramiCrossStrea return } var ( - two = source.Last(1) - one = source.Last(0) - isSecondDayDoji = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) - isBullishHaramiCrossPattern = two.Open > one.Open && - two.Close > one.Open && - two.Close > one.Close && - two.Open < one.Low && - two.High < one.High + two = source.Last(1) + one = source.Last(0) + isLastDoji = fixedpoint.ApproxEqual(one.Open, one.Close, maxDiff) ) - if isBullishHaramiCrossPattern && isSecondDayDoji { - output = Bull + if direction == Bullish { + var ( + isBullishHaramiCrossPattern = two.Open > one.Open && + two.Close < one.Open && + two.Close < one.Close && + two.Open > one.Low && + two.High > one.High + ) + if isBullishHaramiCrossPattern && isLastDoji { + output = Bull + } } else { var isBearishHaramiCrossPattern = two.Open < one.Open && - two.Close < one.Open && - two.Close < one.Close && - two.Open > one.Low && + two.Close > one.Open && + two.Close > one.Close && + two.Open < one.Low && two.High > one.High - if isBearishHaramiCrossPattern && isSecondDayDoji { + if isBearishHaramiCrossPattern && isLastDoji { output = Bear } } @@ -56,3 +60,7 @@ func HaramiCross(source v2.KLineSubscription, maxDiff float64) *HaramiCrossStrea return s } + +func (s *HaramiCrossStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/harami_cross_test.go b/pkg/indicator/v2/pattern/harami_cross_test.go index 9095afc286..2d77f17472 100644 --- a/pkg/indicator/v2/pattern/harami_cross_test.go +++ b/pkg/indicator/v2/pattern/harami_cross_test.go @@ -14,7 +14,7 @@ func TestHaramiCross(t *testing.T) { } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := HaramiCross(kLines, 0.01) + ind := HaramiCross(kLines, Bearish, 0.01) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -29,7 +29,8 @@ func TestHaramiCross(t *testing.T) { {Open: n(25.13), Low: n(21.7), High: n(25.80), Close: n(22.14)}, {Open: n(23.45), Low: n(23.07), High: n(24.59), Close: n(23.45)}, } - ind = HaramiCross(kLines, 0.01) + + ind = HaramiCross(kLines, Bullish, 0.01) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/harami_test.go b/pkg/indicator/v2/pattern/harami_test.go index 5bbcf8a5f5..54c105d59e 100644 --- a/pkg/indicator/v2/pattern/harami_test.go +++ b/pkg/indicator/v2/pattern/harami_test.go @@ -9,8 +9,8 @@ import ( func TestHarami(t *testing.T) { ts := []types.KLine{ - {Open: 100, Low: 95, High: 125, Close: 120}, - {Open: 110, Low: 100, High: 115, Close: 105}, + {Open: n(100), Low: n(95), High: n(125), Close: n(120)}, + {Open: n(110), Low: n(100), High: n(115), Close: n(105)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -26,8 +26,8 @@ func TestHarami(t *testing.T) { } ts = []types.KLine{ - {Open: 120, Low: 95, High: 125, Close: 100}, - {Open: 105, Low: 100, High: 115, Close: 110}, + {Open: n(120), Low: n(95), High: n(125), Close: n(100)}, + {Open: n(105), Low: n(100), High: n(115), Close: n(110)}, } ind = Harami(kLines) diff --git a/pkg/indicator/v2/pattern/head_shoulders.go b/pkg/indicator/v2/pattern/head_shoulders.go new file mode 100644 index 0000000000..9b11fa0e06 --- /dev/null +++ b/pkg/indicator/v2/pattern/head_shoulders.go @@ -0,0 +1,59 @@ +package pattern + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type HeadShoulderStream struct { + *types.Float64Series + + max *v2.MaxValueStream + min *v2.MinValueStream + window int +} + +// Basic Head-Shoulder Detection +func HeadShoulderSimple(source v2.KLineSubscription) *HeadShoulderStream { + var ( + window = 3 + high = v2.HighPrices(source) + low = v2.LowPrices(source) + s = &HeadShoulderStream{ + Float64Series: types.NewFloat64Series(), + max: v2.MaxValue(high, window), + min: v2.MinValue(low, window), + window: window, + } + ) + + source.AddSubscriber(func(kLine types.KLine) { + var ( + i = source.Length() + output = Neutral + ) + if i < s.window { + s.PushAndEmit(output) + return + } + if s.min.Last(1) < low.Last(2) && + s.min.Last(1) < low.Last(0) && + low.Last(1) > low.Last(2) && + low.Last(1) > low.Last(0) { + output = Bull // inverse head/shoulder pattern + } else if s.max.Last(1) > high.Last(2) && + s.max.Last(1) > high.Last(0) && + high.Last(1) < high.Last(2) && + high.Last(1) < high.Last(0) { + output = Bear // head/shoulder pattern + } + + s.PushAndEmit(output) + }) + + return s +} + +func (s *HeadShoulderStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/head_shoulders_test.go b/pkg/indicator/v2/pattern/head_shoulders_test.go new file mode 100644 index 0000000000..f6dda70522 --- /dev/null +++ b/pkg/indicator/v2/pattern/head_shoulders_test.go @@ -0,0 +1,56 @@ +package pattern + +import ( + "testing" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestHeadShoulderSimple(t *testing.T) { + ts := []types.KLine{ + {Open: n(90), Low: n(80), High: n(95), Close: n(90)}, + {Open: n(85), Low: n(75), High: n(90), Close: n(85)}, + {Open: n(80), Low: n(70), High: n(85), Close: n(80)}, + {Open: n(90), Low: n(80), High: n(95), Close: n(90)}, + {Open: n(85), Low: n(75), High: n(90), Close: n(85)}, + {Open: n(80), Low: n(70), High: n(85), Close: n(80)}, + {Open: n(75), Low: n(65), High: n(80), Close: n(75)}, + {Open: n(80), Low: n(70), High: n(85), Close: n(80)}, + {Open: n(85), Low: n(75), High: n(90), Close: n(85)}, + {Open: n(90), Low: n(80), High: n(95), Close: n(90)}, + } + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := HeadShoulderSimple(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + expectedBear := -1.0 + + if ind.Last(2) != expectedBear { + t.Errorf("TestHeadShoulder unexpected result: got %v want %v", ind.Last(2), expectedBear) + } + inverse := []types.KLine{ + {Open: n(20), Low: n(15), High: n(25), Close: n(20)}, + {Open: n(25), Low: n(20), High: n(30), Close: n(25)}, + {Open: n(30), Low: n(25), High: n(35), Close: n(30)}, + {Open: n(20), Low: n(15), High: n(25), Close: n(20)}, + {Open: n(25), Low: n(20), High: n(30), Close: n(25)}, + {Open: n(30), Low: n(25), High: n(35), Close: n(30)}, + {Open: n(35), Low: n(30), High: n(40), Close: n(35)}, + {Open: n(30), Low: n(25), High: n(35), Close: n(30)}, + {Open: n(25), Low: n(20), High: n(30), Close: n(25)}, + {Open: n(20), Low: n(15), High: n(25), Close: n(20)}, + } + for _, candle := range inverse { + stream.EmitKLineClosed(candle) + } + + expectedBull := 1.0 + + if ind.Last(2) != expectedBull { + t.Errorf("TestInverseHeadShoulder unexpected result: got %v want %v", ind.Last(2), expectedBull) + } +} diff --git a/pkg/indicator/v2/pattern/kicking.go b/pkg/indicator/v2/pattern/kicking.go index 40e4573e48..3f26ee48d0 100644 --- a/pkg/indicator/v2/pattern/kicking.go +++ b/pkg/indicator/v2/pattern/kicking.go @@ -68,3 +68,7 @@ func Kicking(source v2.KLineSubscription, maxDiff float64) *KickingStream { return s } + +func (s *KickingStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/kicking_test.go b/pkg/indicator/v2/pattern/kicking_test.go index fe0348d164..7a5e1ca68c 100644 --- a/pkg/indicator/v2/pattern/kicking_test.go +++ b/pkg/indicator/v2/pattern/kicking_test.go @@ -9,8 +9,8 @@ import ( func TestKicking(t *testing.T) { ts := []types.KLine{ - {Open: 100, Low: 100, High: 120, Close: 120}, - {Open: 90, Low: 70, High: 90, Close: 70}, + {Open: n(100), Low: n(100), High: n(120), Close: n(120)}, + {Open: n(90), Low: n(70), High: n(90), Close: n(70)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -26,8 +26,8 @@ func TestKicking(t *testing.T) { } ts = []types.KLine{ - {Open: 90, Low: 70, High: 90, Close: 70}, - {Open: 100, Low: 100, High: 120, Close: 120}, + {Open: n(90), Low: n(70), High: n(90), Close: n(70)}, + {Open: n(100), Low: n(100), High: n(120), Close: n(120)}, } ind = Kicking(kLines, 0.01) diff --git a/pkg/indicator/v2/pattern/marubozu.go b/pkg/indicator/v2/pattern/marubozu.go index 7f0a82c4ab..9f1a156106 100644 --- a/pkg/indicator/v2/pattern/marubozu.go +++ b/pkg/indicator/v2/pattern/marubozu.go @@ -45,3 +45,7 @@ func Marubozu(source v2.KLineSubscription, maxDiff float64) *MarubozuStream { return s } + +func (s *MarubozuStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/marubozu_test.go b/pkg/indicator/v2/pattern/marubozu_test.go index 2cb241e1cd..e920916823 100644 --- a/pkg/indicator/v2/pattern/marubozu_test.go +++ b/pkg/indicator/v2/pattern/marubozu_test.go @@ -9,7 +9,7 @@ import ( func TestMarubozu(t *testing.T) { ts := []types.KLine{ - {Open: 200, Low: 100, High: 200, Close: 100}, + {Open: n(200), Low: n(100), High: n(200), Close: n(100)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -25,7 +25,7 @@ func TestMarubozu(t *testing.T) { } ts = []types.KLine{ - {Open: 100, Low: 100, High: 200, Close: 200}, + {Open: n(100), Low: n(100), High: n(200), Close: n(200)}, } ind = Marubozu(kLines, 0.01) diff --git a/pkg/indicator/v2/pattern/meeting_lines.go b/pkg/indicator/v2/pattern/meeting_lines.go index 24f792eae4..164484c857 100644 --- a/pkg/indicator/v2/pattern/meeting_lines.go +++ b/pkg/indicator/v2/pattern/meeting_lines.go @@ -60,3 +60,7 @@ func MeetingLines(source v2.KLineSubscription) *MeetingLinesStream { return s } + +func (s *MeetingLinesStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/meeting_lines_test.go b/pkg/indicator/v2/pattern/meeting_lines_test.go index 7d96097314..67da02dc60 100644 --- a/pkg/indicator/v2/pattern/meeting_lines_test.go +++ b/pkg/indicator/v2/pattern/meeting_lines_test.go @@ -9,9 +9,9 @@ import ( func TestMeetingLines(t *testing.T) { ts := []types.KLine{ - {Open: 85, Low: 85, High: 100, Close: 95}, - {Open: 95, Low: 90, High: 120, Close: 115}, - {Open: 130, Low: 105, High: 140, Close: 110}, + {Open: n(85), Low: n(85), High: n(100), Close: n(95)}, + {Open: n(95), Low: n(90), High: n(120), Close: n(115)}, + {Open: n(130), Low: n(105), High: n(140), Close: n(110)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -27,9 +27,9 @@ func TestMeetingLines(t *testing.T) { } ts = []types.KLine{ - {Open: 200, Low: 180, High: 210, Close: 190}, - {Open: 180, Low: 140, High: 195, Close: 150}, - {Open: 110, Low: 105, High: 160, Close: 155}, + {Open: n(200), Low: n(180), High: n(210), Close: n(190)}, + {Open: n(180), Low: n(140), High: n(195), Close: n(150)}, + {Open: n(110), Low: n(105), High: n(160), Close: n(155)}, } ind = MeetingLines(kLines) diff --git a/pkg/indicator/v2/pattern/morning_evening_star.go b/pkg/indicator/v2/pattern/morning_evening_star.go index e3bd3dd1d5..df5e5fe2e6 100644 --- a/pkg/indicator/v2/pattern/morning_evening_star.go +++ b/pkg/indicator/v2/pattern/morning_evening_star.go @@ -1,6 +1,7 @@ package pattern import ( + "github.com/c9s/bbgo/pkg/fixedpoint" v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +12,7 @@ type MorningOrEveningStarStream struct { window int } -func MorningOrEveningStar(source v2.KLineSubscription) *MorningOrEveningStarStream { +func MorningOrEveningStar(source v2.KLineSubscription, direction Direction) *MorningOrEveningStarStream { s := &MorningOrEveningStarStream{ Float64Series: types.NewFloat64Series(), window: 3, @@ -27,34 +28,38 @@ func MorningOrEveningStar(source v2.KLineSubscription) *MorningOrEveningStarStre return } var ( - three = source.Last(2) - two = source.Last(1) - one = source.Last(0) - firstMidpoint = (three.Open + three.Close) / 2 - isFirstBearish = three.Close < three.Open - hasSmallBody = three.Low > two.Low && - three.Low > two.High - isThirdBullish = one.Close > one.Open - gapExists = two.High < three.Low && - two.Low < three.Low && - one.Open > two.High && - two.Close < one.Open - doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two) ) - if isFirstBearish && hasSmallBody && gapExists && isThirdBullish && doesCloseAboveFirstMidpoint { - output = Bull // morning star + if direction == Bullish { + var ( + isFirstBearish = three.Close < three.Open + hasSmallBody = three.Low > two.Low && + three.Low > two.High + isThirdBullish = one.Open < one.Close + gapExists = two.High < three.Low && + two.Low < three.Low && + one.Open > two.High && + two.Close < one.Open + doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + ) + if isFirstBearish && hasSmallBody && gapExists && isThirdBullish && doesCloseAboveFirstMidpoint { + output = Bull // morning star + } } else { var ( - isFirstBullish = three.Close > three.Open - isThirdBearish = one.Open > one.Close + isFirstBullish = three.Close > three.Open + hasSmallBody = three.High < two.Low && + three.High < two.High + isThirdBearish = one.Open > one.Close + gapExists = two.High > three.High && + two.Low > three.High && + one.Open < two.Low && + two.Close > one.Open doesCloseBelowFirstMidpoint = one.Close < firstMidpoint ) - hasSmallBody = three.High < two.Low && - three.High < two.High - gapExists = two.High > three.High && - two.Low > three.High && - one.Open < two.Low && - two.Close > one.Open if isFirstBullish && hasSmallBody && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { output = Bear // evening star } @@ -66,3 +71,7 @@ func MorningOrEveningStar(source v2.KLineSubscription) *MorningOrEveningStarStre return s } + +func (s *MorningOrEveningStarStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/morning_evening_star_test.go b/pkg/indicator/v2/pattern/morning_evening_star_test.go index c15269b324..2952950696 100644 --- a/pkg/indicator/v2/pattern/morning_evening_star_test.go +++ b/pkg/indicator/v2/pattern/morning_evening_star_test.go @@ -9,13 +9,14 @@ import ( func TestMorningOrEveningStar(t *testing.T) { ts := []types.KLine{ - {Open: n(22.20), Low: n(20.65), High: n(22.50), Close: n(20.80)}, - {Open: n(20.30), Low: n(19.60), High: n(20.45), Close: n(19.60)}, - {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(20.40)}, + {Open: n(18.35), Low: n(18.13), High: n(21.60), Close: n(21.30)}, + {Open: n(22.20), Low: n(21.87), High: n(22.70), Close: n(22.52)}, + {Open: n(21.60), Low: n(19.30), High: n(22.05), Close: n(19.45)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := MorningOrEveningStar(kLines) + ind := MorningOrEveningStar(kLines, Bearish) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -23,15 +24,17 @@ func TestMorningOrEveningStar(t *testing.T) { expectedBear := -1.0 if ind.Last(0) != expectedBear { - t.Errorf("TestMorningOrEveningStar Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + t.Errorf("TestEveningStar Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) } ts = []types.KLine{ - {Open: n(18.35), Low: n(18.13), High: n(21.60), Close: n(21.30)}, - {Open: n(22.20), Low: n(21.87), High: n(22.70), Close: n(22.52)}, - {Open: n(21.60), Low: n(19.30), High: n(22.05), Close: n(19.45)}, + {Open: n(22.20), Low: n(20.65), High: n(22.50), Close: n(20.80)}, + {Open: n(20.30), Low: n(19.60), High: n(20.45), Close: n(19.80)}, + {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(21.58)}, } - ind = MorningOrEveningStar(kLines) + stream = &types.StandardStream{} + kLines = v2.KLines(stream, "", "") + ind = MorningOrEveningStar(kLines, Bullish) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -39,6 +42,6 @@ func TestMorningOrEveningStar(t *testing.T) { expectedBull := 1.0 if ind.Last(0) != expectedBull { - t.Errorf("TestMorningOrEveningStar Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) + t.Errorf("TestMorningStar unexpected result: got %v want %v", ind.Last(0), expectedBull) } } diff --git a/pkg/indicator/v2/pattern/pattern.go b/pkg/indicator/v2/pattern/pattern.go index 64e39028a4..941c78a64e 100644 --- a/pkg/indicator/v2/pattern/pattern.go +++ b/pkg/indicator/v2/pattern/pattern.go @@ -2,6 +2,15 @@ package pattern import "github.com/c9s/bbgo/pkg/fixedpoint" +// OrderSide represents the side of an order: Buy (long) or Sell (short). +type Direction int + +const ( + MaxNumOfPattern = 5_000 + Bullish Direction = iota + 1 + Bearish +) + var ( Neutral = .0 Bull = 1.0 @@ -11,5 +20,5 @@ var ( ) func n(n float64) fixedpoint.Value { - return fixedpoint.NewFromFloat(n) + return fixedpoint.NewFromFloat(float64(n)) } diff --git a/pkg/indicator/v2/pattern/piercing_line.go b/pkg/indicator/v2/pattern/piercing_line.go index 80eb0e226f..44c3ffa8cf 100644 --- a/pkg/indicator/v2/pattern/piercing_line.go +++ b/pkg/indicator/v2/pattern/piercing_line.go @@ -30,7 +30,7 @@ func PiercingLine(source v2.KLineSubscription) *PiercingLineStream { two = source.Last(1) one = source.Last(0) firstMidpoint = (two.Open + two.Close) / 2 - isDowntrend = one.Close < two.Low + isDowntrend = one.Low < two.Low isFirstBearish = two.Close < two.Open isSecondBullish = one.Close > one.Open isPiercingLine = two.Low > one.Open && @@ -46,3 +46,7 @@ func PiercingLine(source v2.KLineSubscription) *PiercingLineStream { return s } + +func (s *PiercingLineStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/piercing_line_test.go b/pkg/indicator/v2/pattern/piercing_line_test.go index c42553e8ba..51c25c0c18 100644 --- a/pkg/indicator/v2/pattern/piercing_line_test.go +++ b/pkg/indicator/v2/pattern/piercing_line_test.go @@ -12,6 +12,7 @@ func TestPiercingLine(t *testing.T) { {Open: n(42.70), Low: n(41.45), High: n(42.82), Close: n(41.60)}, {Open: n(41.33), Low: n(41.15), High: n(42.50), Close: n(42.34)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") ind := PiercingLine(kLines) @@ -19,9 +20,9 @@ func TestPiercingLine(t *testing.T) { for _, candle := range ts { stream.EmitKLineClosed(candle) } - expectedBear := -1.0 + expectedBull := 1.0 - if ind.Last(0) != expectedBear { - t.Errorf("TestPiercingLine Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) + if ind.Last(0) != expectedBull { + t.Errorf("TestPiercingLine Bull unexpected result: got %v want %v", ind.Last(0), expectedBull) } } diff --git a/pkg/indicator/v2/pattern/separating_lines.go b/pkg/indicator/v2/pattern/separating_lines.go index 5f402c8628..31009d993b 100644 --- a/pkg/indicator/v2/pattern/separating_lines.go +++ b/pkg/indicator/v2/pattern/separating_lines.go @@ -65,3 +65,7 @@ func SeparatingLines(source v2.KLineSubscription, maxDiff float64) *SeparatingLi return s } + +func (s *SeparatingLinesStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/separating_lines_test.go b/pkg/indicator/v2/pattern/separating_lines_test.go index 11ee59649a..190885c54c 100644 --- a/pkg/indicator/v2/pattern/separating_lines_test.go +++ b/pkg/indicator/v2/pattern/separating_lines_test.go @@ -9,9 +9,9 @@ import ( func TestSeparatingLines(t *testing.T) { ts := []types.KLine{ - {Open: 200, Low: 160, High: 210, Close: 170}, - {Open: 150, Low: 140, High: 190, Close: 180}, - {Open: 152, Low: 120, High: 152, Close: 130}, + {Open: n(200), Low: n(160), High: n(210), Close: n(170)}, + {Open: n(150), Low: n(140), High: n(190), Close: n(180)}, + {Open: n(152), Low: n(120), High: n(152), Close: n(130)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -27,9 +27,9 @@ func TestSeparatingLines(t *testing.T) { } ts = []types.KLine{ - {Open: 50, Low: 40, High: 80, Close: 70}, - {Open: 100, Low: 70, High: 110, Close: 80}, - {Open: 102, Low: 102, High: 130, Close: 120}, + {Open: n(50), Low: n(40), High: n(80), Close: n(70)}, + {Open: n(100), Low: n(70), High: n(110), Close: n(80)}, + {Open: n(102), Low: n(102), High: n(130), Close: n(120)}, } ind = SeparatingLines(kLines, 0.01) diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines.go b/pkg/indicator/v2/pattern/side_by_side_whitelines.go index b3e92d7e4d..8a20c14dcf 100644 --- a/pkg/indicator/v2/pattern/side_by_side_whitelines.go +++ b/pkg/indicator/v2/pattern/side_by_side_whitelines.go @@ -78,3 +78,7 @@ func SideBySideWhiteLines(source v2.KLineSubscription, maxDiff float64) *SideByS return s } + +func (s *SideBySideWhiteLinesStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go b/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go index 0f01e53e3b..504629cfb4 100644 --- a/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go +++ b/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go @@ -9,10 +9,10 @@ import ( func TestSideBySideWhiteLines(t *testing.T) { ts := []types.KLine{ - {Open: 130, Low: 110, High: 140, Close: 120}, - {Open: 110, Low: 85, High: 115, Close: 90}, - {Open: 50, Low: 45, High: 75, Close: 70}, - {Open: 50, Low: 42, High: 77, Close: 68}, + {Open: n(130), Low: n(110), High: n(140), Close: n(120)}, + {Open: n(110), Low: n(85), High: n(115), Close: n(90)}, + {Open: n(50), Low: n(45), High: n(75), Close: n(70)}, + {Open: n(50), Low: n(42), High: n(77), Close: n(68)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -28,10 +28,10 @@ func TestSideBySideWhiteLines(t *testing.T) { } ts = []types.KLine{ - {Open: 70, Low: 60, High: 90, Close: 80}, - {Open: 100, Low: 90, High: 130, Close: 120}, - {Open: 150, Low: 140, High: 210, Close: 185}, - {Open: 150, Low: 135, High: 200, Close: 190}, + {Open: n(70), Low: n(60), High: n(90), Close: n(80)}, + {Open: n(100), Low: n(90), High: n(130), Close: n(120)}, + {Open: n(150), Low: n(140), High: n(210), Close: n(185)}, + {Open: n(150), Low: n(135), High: n(200), Close: n(190)}, } ind = SideBySideWhiteLines(kLines, 0.01) diff --git a/pkg/indicator/v2/pattern/spinning_top.go b/pkg/indicator/v2/pattern/spinning_top.go index ebd2db6771..24b949e4ef 100644 --- a/pkg/indicator/v2/pattern/spinning_top.go +++ b/pkg/indicator/v2/pattern/spinning_top.go @@ -10,29 +10,35 @@ type SpinningTopStream struct { *types.Float64Series } -func SpinningTop(source v2.KLineSubscription) *SpinningTopStream { +func SpinningTop(source v2.KLineSubscription, direction Direction) *SpinningTopStream { s := &SpinningTopStream{ Float64Series: types.NewFloat64Series(), } source.AddSubscriber(func(kLine types.KLine) { var ( - output = Neutral - one = source.Last(0) - bodyLength = fixedpoint.Abs(one.Close - one.Open) - upperShadowLength = fixedpoint.Abs(one.High - one.Close) - lowerShadowLength = fixedpoint.Abs(one.Open - one.Low) - isSpinningTop = bodyLength < upperShadowLength && - bodyLength < lowerShadowLength + output = Neutral + one = source.Last(0) + bodyLength = fixedpoint.Abs(one.Close - one.Open) ) - - if isSpinningTop { - output = Bull + if direction == Bullish { + var ( + upperShadowLength = fixedpoint.Abs(one.High - one.Close) + lowerShadowLength = fixedpoint.Abs(one.Open - one.Low) + isSpinningTop = bodyLength < upperShadowLength && + bodyLength < lowerShadowLength + ) + + if isSpinningTop { + output = Bull + } } else { - upperShadowLength = fixedpoint.Abs(one.High - one.Open) - lowerShadowLength = fixedpoint.Abs(one.High - one.Low) - var isBearishSpinningTop = bodyLength < upperShadowLength && - bodyLength < lowerShadowLength + var ( + upperShadowLength = fixedpoint.Abs(one.High - one.Open) + lowerShadowLength = fixedpoint.Abs(one.High - one.Low) + isBearishSpinningTop = bodyLength < upperShadowLength && + bodyLength < lowerShadowLength + ) if isBearishSpinningTop { output = Bear } @@ -44,3 +50,7 @@ func SpinningTop(source v2.KLineSubscription) *SpinningTopStream { return s } + +func (s *SpinningTopStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/spinning_top_test.go b/pkg/indicator/v2/pattern/spinning_top_test.go index a9bd598ca5..24b2c21c4f 100644 --- a/pkg/indicator/v2/pattern/spinning_top_test.go +++ b/pkg/indicator/v2/pattern/spinning_top_test.go @@ -13,7 +13,7 @@ func TestSpinningTop(t *testing.T) { } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") - ind := SpinningTop(kLines) + ind := SpinningTop(kLines, Bearish) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -27,7 +27,7 @@ func TestSpinningTop(t *testing.T) { ts = []types.KLine{ {Open: n(20.62), Low: n(20.34), High: n(20.75), Close: n(20.50)}, } - ind = SpinningTop(kLines) + ind = SpinningTop(kLines, Bullish) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/three_crows.go b/pkg/indicator/v2/pattern/three_crows.go index e379133c8d..0e4840afc4 100644 --- a/pkg/indicator/v2/pattern/three_crows.go +++ b/pkg/indicator/v2/pattern/three_crows.go @@ -37,11 +37,13 @@ func ThreeCrows(source v2.KLineSubscription) *ThreeCrowsStream { three = source.Last(2) two = source.Last(1) one = source.Last(0) - isDownTrend = three.Low > two.Low && two.Low > three.Low + isDownTrend = three.Low > two.Low && two.Low > one.Low isAllBearish = three.Open > three.Close && two.Open > two.Close && one.Open > one.Close opensWithinPreviousBody = three.Open > two.Open && - two.Open > three.Close && one.Open > two.Open + two.Open > three.Close && + two.Open > one.Open && + one.Open > two.Close ) if isDownTrend && isAllBearish && opensWithinPreviousBody { @@ -54,3 +56,7 @@ func ThreeCrows(source v2.KLineSubscription) *ThreeCrowsStream { return s } + +func (s *ThreeCrowsStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/three_crows_test.go b/pkg/indicator/v2/pattern/three_crows_test.go index 17b7f645f4..335410ec36 100644 --- a/pkg/indicator/v2/pattern/three_crows_test.go +++ b/pkg/indicator/v2/pattern/three_crows_test.go @@ -3,8 +3,6 @@ package pattern import ( "testing" - "github.com/davecgh/go-spew/spew" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -24,7 +22,6 @@ func TestThreeCrows(t *testing.T) { } expectedBear := -1.0 - spew.Dump(ind) if ind.Last(0) != expectedBear { t.Errorf("TestThreeCrows Bear unexpected result: got %v want %v", ind.Last(0), expectedBear) } diff --git a/pkg/indicator/v2/pattern/three_line_strike.go b/pkg/indicator/v2/pattern/three_line_strike.go index 6eaa3a68b9..46ca551ecc 100644 --- a/pkg/indicator/v2/pattern/three_line_strike.go +++ b/pkg/indicator/v2/pattern/three_line_strike.go @@ -71,3 +71,7 @@ func ThreeLineStrike(source v2.KLineSubscription) *ThreeLineStrikeStream { return s } + +func (s *ThreeLineStrikeStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/three_line_strike_test.go b/pkg/indicator/v2/pattern/three_line_strike_test.go index 40573d475b..9402714b87 100644 --- a/pkg/indicator/v2/pattern/three_line_strike_test.go +++ b/pkg/indicator/v2/pattern/three_line_strike_test.go @@ -9,10 +9,10 @@ import ( func TestThreeLineStrike(t *testing.T) { ts := []types.KLine{ - {Open: 98, Low: 77, High: 100, Close: 80}, - {Open: 90, Low: 68, High: 95, Close: 73}, - {Open: 82, Low: 65, High: 86, Close: 67}, - {Open: 62, Low: 59, High: 103, Close: 101}, + {Open: n(98), Low: n(77), High: n(100), Close: n(80)}, + {Open: n(90), Low: n(68), High: n(95), Close: n(73)}, + {Open: n(82), Low: n(65), High: n(86), Close: n(67)}, + {Open: n(62), Low: n(59), High: n(103), Close: n(101)}, } stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") @@ -28,10 +28,10 @@ func TestThreeLineStrike(t *testing.T) { } ts = []types.KLine{ - {Open: 70, Low: 60, High: 100, Close: 90}, - {Open: 80, Low: 75, High: 110, Close: 105}, - {Open: 95, Low: 93, High: 120, Close: 115}, - {Open: 125, Low: 50, High: 130, Close: 55}, + {Open: n(70), Low: n(60), High: n(100), Close: n(90)}, + {Open: n(80), Low: n(75), High: n(110), Close: n(105)}, + {Open: n(95), Low: n(93), High: n(120), Close: n(115)}, + {Open: n(125), Low: n(50), High: n(130), Close: n(55)}, } ind = ThreeLineStrike(kLines) diff --git a/pkg/indicator/v2/pattern/three_white_soldiers.go b/pkg/indicator/v2/pattern/three_white_soldiers.go index 33ec9fc797..78c31677be 100644 --- a/pkg/indicator/v2/pattern/three_white_soldiers.go +++ b/pkg/indicator/v2/pattern/three_white_soldiers.go @@ -40,12 +40,18 @@ func ThreeWhiteSoldiers(source v2.KLineSubscription) *ThreeWhiteSoldiersStream { two.High > one.Open && one.Open < two.Close ) + if isUpTrend && isAllBullish && doesOpenWithinPreviousBody { output = Bull } + s.PushAndEmit(output) }) return s } + +func (s *ThreeWhiteSoldiersStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfPattern) +} diff --git a/pkg/indicator/v2/pattern/three_white_soldiers_test.go b/pkg/indicator/v2/pattern/three_white_soldiers_test.go index 92902eb807..c31a2b845c 100644 --- a/pkg/indicator/v2/pattern/three_white_soldiers_test.go +++ b/pkg/indicator/v2/pattern/three_white_soldiers_test.go @@ -10,9 +10,10 @@ import ( func TestThreeWhiteSoldiers(t *testing.T) { ts := []types.KLine{ {Open: n(21.12), Low: n(20.85), High: n(21.83), Close: n(21.65)}, - {Open: n(21.48), Low: n(21.36), High: n(21.36), Close: n(22.20)}, - {Open: n(21.80), Low: n(21.66), High: n(21.66), Close: n(22.65)}, + {Open: n(21.48), Low: n(21.36), High: n(22.40), Close: n(22.20)}, + {Open: n(21.80), Low: n(21.66), High: n(22.80), Close: n(22.65)}, } + stream := &types.StandardStream{} kLines := v2.KLines(stream, "", "") ind := ThreeWhiteSoldiers(kLines) diff --git a/pkg/indicator/v2/price.go b/pkg/indicator/v2/price.go index 6f48439e04..5f7d9eab9a 100644 --- a/pkg/indicator/v2/price.go +++ b/pkg/indicator/v2/price.go @@ -69,3 +69,6 @@ func Volumes(source KLineSubscription) *PriceStream { func HLC3(source KLineSubscription) *PriceStream { return Price(source, types.KLineHLC3Mapper) } +func HL2(source KLineSubscription) *PriceStream { + return Price(source, types.KLineHL2Mapper) +} diff --git a/pkg/indicator/v2/squared_average.go b/pkg/indicator/v2/squared_average.go new file mode 100644 index 0000000000..e3625f4d13 --- /dev/null +++ b/pkg/indicator/v2/squared_average.go @@ -0,0 +1,37 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +type SquaredAverageStream struct { + *types.Float64Series + max *MaxValueStream + window int +} + +func SquaredAverage(source types.Float64Source, window int) *SquaredAverageStream { + s := &SquaredAverageStream{ + Float64Series: types.NewFloat64Series(), + max: MaxValue(source, window), + window: window, + } + + s.Bind(source, s) + + return s +} + +func (s *SquaredAverageStream) Calculate(v float64) float64 { + var ( + max = s.max.Last(0) + percentageDrawdown = (v - max) / max * 100 + squaredAverage = percentageDrawdown * percentageDrawdown + ) + + return squaredAverage +} + +func (s *SquaredAverageStream) Truncate() { + s.Slice = s.Slice.Truncate(s.window) +} diff --git a/pkg/indicator/v2/subtract_test.go b/pkg/indicator/v2/subtract_test.go index e9fab879b6..b8b3662c45 100644 --- a/pkg/indicator/v2/subtract_test.go +++ b/pkg/indicator/v2/subtract_test.go @@ -2,39 +2,34 @@ package indicatorv2 import ( "testing" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) func Test_v2_Subtract(t *testing.T) { - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - closePrices := ClosePrices(kLines) - toDiff := []DiffValue{ - { - Minuend: dec.New(10), - Subtrahend: dec.New(8), - }, - { - Minuend: dec.New(9), - Subtrahend: dec.New(9), - }, - { - Minuend: dec.New(8), - Subtrahend: dec.New(10), - }, - } - - diff := Subtract(fastEMA, slowEMA) - - for i := .0; i < 50.0; i++ { - stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(19_000.0 + i)}) - } - - assert.Equal(t, []float64{2, 0, -2}, dec.FloatSlice(2, diff.Series()...)) + // stream := &types.StandardStream{} + // kLines := KLines(stream, "", "") + // closePrices := ClosePrices(kLines) + // toDiff := []DiffValue{ + // { + // Minuend: dec.New(10), + // Subtrahend: dec.New(8), + // }, + // { + // Minuend: dec.New(9), + // Subtrahend: dec.New(9), + // }, + // { + // Minuend: dec.New(8), + // Subtrahend: dec.New(10), + // }, + // } + + // diff := Subtract(fastEMA, slowEMA) + + // for i := .0; i < 50.0; i++ { + // stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(19_000.0 + i)}) + // } + + // assert.Equal(t, []float64{2, 0, -2}, dec.FloatSlice(2, diff.Series()...)) // t.Logf("fastEMA: %+v", fastEMA.Slice) // t.Logf("slowEMA: %+v", slowEMA.Slice) diff --git a/pkg/indicator/v2/trend/alma.go b/pkg/indicator/v2/trend/alma.go index 17a9820df5..1a6e1f8e1a 100644 --- a/pkg/indicator/v2/trend/alma.go +++ b/pkg/indicator/v2/trend/alma.go @@ -4,9 +4,8 @@ package trend import ( - "github.com/thecolngroup/gou/dec" + "math" - "github.com/c9s/bbgo/pkg/fixedpoint" v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -23,9 +22,9 @@ type ALMAStream struct { // embedded struct *types.Float64Series - sample *types.Float64Series - offset fixedpoint.Value - sigma fixedpoint.Value + sample []float64 + offset float64 + sigma float64 window int } @@ -33,16 +32,19 @@ type ALMAStream struct { // Ported from https://www.tradingview.com/pine-script-reference/#fun_alma // NewALMA creates a new ALMA indicator with default parameters. func ALMA(source types.Float64Source, window int) *ALMAStream { - return ALMAWithSigma(window, DefaultALMAOffset, DefaultALMASigma) + return ALMAWithSigma(source, window, DefaultALMAOffset, DefaultALMASigma) } // NewALMAWithSigma creates a new ALMA indicator with the given offset and sigma. -func ALMAWithSigma(window int, offset, sigma float64) *ALMAStream { - return &ALMAStream{ - window: window, - offset: fixedpoint.NewFromFloat(offset), - sigma: fixedpoint.NewFromFloat(sigma), +func ALMAWithSigma(source types.Float64Source, window int, offset, sigma float64) *ALMAStream { + s := &ALMAStream{ + Float64Series: types.NewFloat64Series(), + window: window, + offset: offset, + sigma: sigma, } + s.Bind(source, s) + return s } func (s *ALMAStream) Calculate(v float64) float64 { @@ -53,22 +55,23 @@ func (s *ALMAStream) Calculate(v float64) float64 { return v } var ( - length = fixedpoint.NewFromInt(int64(s.window)) - two = fixedpoint.Two - norm, sum fixedpoint.Value - offset = s.offset.Mul(length.Sub(fixedpoint.One)) - m = offset.Floor() - sig = length.Div(s.sigma) + length = float64(s.window) + norm, sum float64 + offset = s.offset * (length - 1) + m = math.Floor(offset) + sig = length / s.sigma ) - for i := 0; i < s.sample.Length(); i++ { - index := fixedpoint.NewFromInt(int64(i)) - pow := index.Sub(m).Pow(two).Div(sig.Pow(two).Mul(two)) - weight := fixedpoint.Exp(dec.New(-1).Mul(pow)) - norm = norm.Add(weight) - sum = fixedpoint.NewFromFloat(s.sample.Last(i)) - sum = sum.Mul(weight).Add(sum) + for i := 0; i < len(s.sample); i++ { + pow := math.Pow(float64(i)-m, 2) / (math.Pow(sig, 2) * 2) + weight := math.Exp(-1 * pow) + norm += weight + sum += s.sample[i] * weight } - ma := sum.Div(norm) + ma := sum / norm - return ma.Float64() + return ma +} + +func (s *ALMAStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/trend/alma_test.go b/pkg/indicator/v2/trend/alma_test.go index 9bf32227c1..b0a3def7c3 100644 --- a/pkg/indicator/v2/trend/alma_test.go +++ b/pkg/indicator/v2/trend/alma_test.go @@ -23,7 +23,7 @@ func TestALMA(t *testing.T) { name: "Valid sample", giveV: []float64{10, 89, 20, 43, 44, 33, 19}, giveLength: 3, - want: 32.680479063242394, + want: 32.68047906324239, }, { name: "0 length window", diff --git a/pkg/indicator/v2/trend/aroon.go b/pkg/indicator/v2/trend/aroon.go deleted file mode 100644 index 48cc9e452f..0000000000 --- a/pkg/indicator/v2/trend/aroon.go +++ /dev/null @@ -1,100 +0,0 @@ -package trend - -import ( - "math" - - "github.com/c9s/bbgo/pkg/types" -) - -// Aroon Indicator - -// The [Aroon](https://pkg.go.dev/github.com/cinar/indicator#Aroon) function calculates -// a technical indicator that is used to identify trend changes in the price of a stock, -// as well as the strength of that trend. It consists of two lines, Aroon Up, and Aroon Down. -// The Aroon Up line measures the strength of the uptrend, and the Aroon Down measures -// the strength of the downtrend. When Aroon Up is above Aroon Down, it indicates bullish price, -// and when Aroon Down is above Aroon Up, it indicates bearish price. - -// ``` -// -// Aroon Up = ((25 - Period Since Last 25 Period High) / 25) * 100 -// Aroon Down = ((25 - Period Since Last 25 Period Low) / 25) * 100 -// -// ``` -type AroonStream struct { - *types.Float64Series - - window, lowIndex int - direction float64 -} - -// AroonUpIndicator returns a derivative indicator that will return a value based on -// the number of ticks since the highest price in the window -// https://www.investopedia.com/terms/a/aroon.asp -// -// Note: this indicator should be constructed with a either a HighPriceIndicator or a derivative thereof -func AroonUpIndicator(source types.Float64Source, window int) *AroonStream { - s := &AroonStream{ - Float64Series: types.NewFloat64Series(), - window: window, - lowIndex: -1, - direction: -1.0, - } - s.Bind(source, s) - return s -} - -// AroonDownIndicator returns a derivative indicator that will return a value based on -// the number of ticks since the lowest price in the window -// https://www.investopedia.com/terms/a/aroon.asp -// -// Note: this indicator should be constructed with a either a LowPriceIndicator or a derivative thereof -func AroonDownIndicator(source types.Float64Source, window int) *AroonStream { - s := &AroonStream{ - Float64Series: types.NewFloat64Series(), - window: window, - lowIndex: -1, - direction: 1.0, - } - s.Bind(source, s) - return s -} - -func (s *AroonStream) Calculate(v float64) float64 { - if s.Length() < s.window-1 { - return 0 - } - - var ( - index = s.Length() - 1 - pSince = index - s.findLowIndex(index) - aroon = float64(s.window-pSince) / float64(s.window*100) - ) - - return aroon -} - -func (s *AroonStream) findLowIndex(index int) int { - if s.lowIndex < 1 || s.lowIndex < index-s.window { - lv := math.MaxFloat64 - lowIndex := -1 - for i := (index + 1) - s.window; i <= index; i++ { - value := s.Last(i) * s.direction - if value < lv { - lv = value - lowIndex = i - } - } - - return lowIndex - } - - v1 := s.Last(0) * s.direction - v2 := s.Last(s.lowIndex) * s.direction - - if v1 < v2 { - return index - } - - return s.lowIndex -} diff --git a/pkg/indicator/v2/trend/aroon_test.go b/pkg/indicator/v2/trend/aroon_test.go deleted file mode 100644 index 9e3c633b8b..0000000000 --- a/pkg/indicator/v2/trend/aroon_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package trend - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/types" -) - -func TestAroonUpIndicator(t *testing.T) { - t.Run("with < window periods", func(t *testing.T) { - source := types.NewFloat64Series() - aroonUp := AroonUpIndicator(source, 10) - - data := []float64{1} - for _, d := range data { - source.PushAndEmit(d) - } - assert.Equal(t, 0.0, aroonUp.Last(0)) - }) - - t.Run("with > window periods", func(t *testing.T) { - source := types.NewFloat64Series() - aroonUp := AroonUpIndicator(source, 4) - - data := []float64{1, 2, 3, 4, 3, 2, 1} - for _, d := range data { - source.PushAndEmit(d) - } - assert.Equal(t, 100.0, aroonUp.Last(3)) - assert.Equal(t, 75.0, aroonUp.Last(4)) - assert.Equal(t, 50.0, aroonUp.Last(5)) - }) -} - -func TestAroonDownIndicator(t *testing.T) { - t.Run("with < window periods", func(t *testing.T) { - source := types.NewFloat64Series() - aroonDown := AroonDownIndicator(source, 10) - - data := []float64{1} - for _, d := range data { - source.PushAndEmit(d) - } - assert.Equal(t, 0.0, aroonDown.Last(0)) - }) - - t.Run("with > window periods", func(t *testing.T) { - source := types.NewFloat64Series() - aroonDown := AroonDownIndicator(source, 4) - - data := []float64{5, 4, 3, 2, 3, 4, 5} - for _, d := range data { - source.PushAndEmit(d) - } - assert.Equal(t, 100.0, aroonDown.Last(3)) - assert.Equal(t, 75.0, aroonDown.Last(4)) - assert.Equal(t, 50.0, aroonDown.Last(5)) - }) -} diff --git a/pkg/indicator/v2/cci.go b/pkg/indicator/v2/trend/cci.go similarity index 99% rename from pkg/indicator/v2/cci.go rename to pkg/indicator/v2/trend/cci.go index 77ca9e0bf0..b1ea70609d 100644 --- a/pkg/indicator/v2/cci.go +++ b/pkg/indicator/v2/trend/cci.go @@ -1,4 +1,4 @@ -package indicatorv2 +package trend import ( "math" diff --git a/pkg/indicator/v2/cci_test.go b/pkg/indicator/v2/trend/cci_test.go similarity index 91% rename from pkg/indicator/v2/cci_test.go rename to pkg/indicator/v2/trend/cci_test.go index a662553ba2..30291c2ec8 100644 --- a/pkg/indicator/v2/cci_test.go +++ b/pkg/indicator/v2/trend/cci_test.go @@ -1,10 +1,12 @@ -package indicatorv2 +package trend import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" ) /* @@ -23,7 +25,7 @@ func Test_CCI(t *testing.T) { panic(err) } t.Run("random_case", func(t *testing.T) { - price := Price(nil, nil) + price := v2.Price(nil, nil) cci := CCI(price, 16) for _, value := range input { price.PushAndEmit(value) diff --git a/pkg/indicator/v2/trend/sma.go b/pkg/indicator/v2/trend/sma.go index 9e0257b161..297d7d3e61 100644 --- a/pkg/indicator/v2/trend/sma.go +++ b/pkg/indicator/v2/trend/sma.go @@ -4,7 +4,7 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -const MaxNumOfSMA = 5_000 +const MaxNumOfMA = 5_000 type SMAStream struct { *types.Float64Series @@ -29,5 +29,5 @@ func (s *SMAStream) Calculate(v float64) float64 { } func (s *SMAStream) Truncate() { - s.Slice = s.Slice.Truncate(MaxNumOfSMA) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/volatility/chandelier_exit.go b/pkg/indicator/v2/volatility/chandelier_exit.go new file mode 100644 index 0000000000..6b7de2b421 --- /dev/null +++ b/pkg/indicator/v2/volatility/chandelier_exit.go @@ -0,0 +1,62 @@ +package volatility + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// OrderSide represents the side of an order: Buy (long) or Sell (short). +type OrderSide int + +const ( + // Buy (long) + Buy OrderSide = iota + 1 + + // Sell (short) + Sell +) + +type ChandelierExitStream struct { + // embedded struct + *types.Float64Series + + atr *ATRStream + min *v2.MinValueStream + max *v2.MaxValueStream +} + +// Chandelier Exit. It sets a trailing stop-loss based on the Average True Value (ATR). +// +// Chandelier Exit Long = 22-Period SMA High - ATR(22) * 3 +// Chandelier Exit Short = 22-Period SMA Low + ATR(22) * 3 +// +// Returns chandelierExitLong, chandelierExitShort +func ChandelierExit(source v2.KLineSubscription, os OrderSide, window int) *ChandelierExitStream { + s := &ChandelierExitStream{ + atr: ATR2(source, window), + min: v2.MinValue(v2.LowPrices(source), window), + max: v2.MaxValue(v2.HighPrices(source), window)} + + source.AddSubscriber(func(v types.KLine) { + high := s.max.Last(0) + low := s.min.Last(0) + atr := s.atr.Last(0) + var chandelierExit float64 + if os == Buy { + chandelierExit = high - atr*3 + } else { + chandelierExit = low + atr*3 + } + s.PushAndEmit(chandelierExit) + }) + + return s +} + +func ChandelierExitDefault(source v2.KLineSubscription, os OrderSide) *ChandelierExitStream { + return ChandelierExit(source, os, 22) +} + +func (s *ChandelierExitStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volatility/ulcer_index.go b/pkg/indicator/v2/volatility/ulcer_index.go new file mode 100644 index 0000000000..7c0bd19183 --- /dev/null +++ b/pkg/indicator/v2/volatility/ulcer_index.go @@ -0,0 +1,48 @@ +package volatility + +import ( + "math" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/types" +) + +type UlcerIndexStream struct { + *types.Float64Series + sma *trend.SMAStream +} + +// The Ulcer Index (UI) measures downside risk. The index increases in value +// as the price moves farther away from a recent high and falls as the price +// rises to new highs. +// +// High Closings = Max(period, Closings) +// Percentage Drawdown = 100 * ((Closings - High Closings) / High Closings) +// Squared Average = Sma(period, Percent Drawdown * Percent Drawdown) +// Ulcer Index = Sqrt(Squared Average) + +// https://www.investopedia.com/terms/a/UlcerIndex.asp +func UlcerIndex(source types.Float64Source, window int) *UlcerIndexStream { + s := &UlcerIndexStream{ + Float64Series: types.NewFloat64Series(), + sma: trend.SMA(v2.SquaredAverage(source, window), window), + } + + s.Bind(source, s) + + return s +} + +// The default ulcer index with the default period of 14. +func UlcerIndexDefault(source types.Float64Source) *UlcerIndexStream { + return UlcerIndex(source, 14) +} + +func (s *UlcerIndexStream) Calculate(_ float64) float64 { + return math.Sqrt(s.sma.Last(0)) +} + +func (s *UlcerIndexStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volatility/ulcer_index_test.go b/pkg/indicator/v2/volatility/ulcer_index_test.go new file mode 100644 index 0000000000..af616b7e41 --- /dev/null +++ b/pkg/indicator/v2/volatility/ulcer_index_test.go @@ -0,0 +1,23 @@ +package volatility + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestUlcerIndex(t *testing.T) { + closing := []float64{9, 11, 7, 10, 8, 7, 7, 8, 10, 9, 5, 4, 6, 7} + expected := []float64{0, 0, 20.99, 18.74, 20.73, 24.05, 26.17, 26.31, + 24.99, 24.39, 28.49, 32.88, 34.02, 34.19} + + source := types.NewFloat64Series() + ind := UlcerIndexDefault(source) + + for _, d := range closing { + source.PushAndEmit(d) + } + assert.InDeltaSlice(t, expected, ind.Slice, 0.01) +} diff --git a/pkg/indicator/v2/volume/accumulation_distiribution.go b/pkg/indicator/v2/volume/accumulation_distiribution.go index 932d33d494..f710869635 100644 --- a/pkg/indicator/v2/volume/accumulation_distiribution.go +++ b/pkg/indicator/v2/volume/accumulation_distiribution.go @@ -26,16 +26,23 @@ func AccumulationDistribution(source v2.KLineSubscription) *AccumulationDistribu var ( i = s.Slice.Length() output = fixedpoint.NewFromInt(0) + cl = v.Close.Sub(v.Low) + hc = v.High.Sub(v.Close) + hl = v.High.Sub(v.Low) ) if i > 0 { output = fixedpoint.NewFromFloat(s.Slice.Last(0)) } - output += v.Volume * ((v.Close - v.Low) - (v.High-v.Close)/(v.High-v.Low)) + output = output.Add(v.Volume.Mul(cl.Sub(hc).Div(hl))) s.PushAndEmit(output.Float64()) }) return s } + +func (s *AccumulationDistributionStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volume/accumulation_distiribution_test.go b/pkg/indicator/v2/volume/accumulation_distiribution_test.go index 4389129a8a..9077b36f21 100644 --- a/pkg/indicator/v2/volume/accumulation_distiribution_test.go +++ b/pkg/indicator/v2/volume/accumulation_distiribution_test.go @@ -1,20 +1,42 @@ package volume import ( + "encoding/json" "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) func TestAccumulationDistribution(t *testing.T) { - // ts := []types.KLine{ - // {Open: 90, Low: 85, High: 105, Close: 100}, - // } - - // stream := &types.StandardStream{} - // kLines := v2.KLines(stream, "", "") - // ind := AccumulationDistribution(kLines) + high := []byte(`[62.3400,62.0500,62.2700,60.7900,59.9300,61.7500,60.0000,59.0000,59.0700,59.2200,58.7500,58.6500,58.4700,58.2500,58.3500,59.8600,59.5299,62.1000,62.1600,62.6700,62.3800,63.7300,63.8500,66.1500,65.3400,66.4800,65.2300,63.4000,63.1800,62.7000]`) + low := []byte(`[61.3700,60.6900,60.1000,58.6100,58.7120,59.8600,57.9700,58.0200,57.4800,58.3000,57.8276,57.8600,57.9100,57.8333,57.5300,58.5800,58.3000,58.5300,59.8000,60.9300,60.1500,62.2618,63.0000,63.5800,64.0700,65.2000,63.2100,61.8800,61.1100,61.2500]`) + close := []byte(`[62.1500,60.8100,60.4500,59.1800,59.2400,60.2000,58.4800,58.2400,58.6900,58.6500,58.4700,58.0200,58.1700,58.0700,58.1300,58.9400,59.1000,61.9200,61.3700,61.6800,62.0900,62.8900,63.5300,64.0100,64.7700,65.2200,63.2800,62.4000,61.5500,62.6900]`) + volume := []byte(`[7849.025,11692.075,10575.307,13059.128,20733.508,29630.096,17705.294,7259.203,10474.629,5203.714,3422.865,3962.15,4095.905,3766.006,4239.335,8039.979,6956.717,18171.552,22225.894,14613.509,12319.763,15007.69,8879.667,22693.812,10191.814,10074.152,9411.62,10391.69,8926.512,7459.575]`) + buildKLines := func(high, low, close, volume []fixedpoint.Value) (kLines []types.KLine) { + for i := range high { + kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i], Volume: volume[i]}) + } + return kLines + } + var h, l, c, v []fixedpoint.Value + _ = json.Unmarshal(high, &h) + _ = json.Unmarshal(low, &l) + _ = json.Unmarshal(close, &c) + _ = json.Unmarshal(volume, &v) - // for _, candle := range ts { - // stream.EmitKLineClosed(candle) - // } - // expected := []float64{} + expected := []float64{4774, -4855, -12019, -18249, -21006, -39976, -48785, -52785, -47317, -48561, -47216, -49574, -49866, -49354, -47389, -50907, -48813, -32474, -25128, -27144, -18028, -20193, -18000, -33099, -32056, -41816, -50575, -53856, -58988, -51631} + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := AccumulationDistribution(kLines) + k := buildKLines(h, l, c, v) + for _, candle := range k { + stream.EmitKLineClosed(candle) + } + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.5, "Expected AccumulationDistribution.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } } diff --git a/pkg/indicator/v2/volume/negative_volume_index.go b/pkg/indicator/v2/volume/negative_volume_index.go index 3eef117443..5a0cf3dc6a 100644 --- a/pkg/indicator/v2/volume/negative_volume_index.go +++ b/pkg/indicator/v2/volume/negative_volume_index.go @@ -7,7 +7,7 @@ import ( ) // Starting value for NVI. -const NVI_STARTING_VALUE = 1000 +var NVI_STARTING_VALUE = fixedpoint.NewFromInt(1000) // Negative Volume Index (NVI) type NVIStream struct { @@ -29,16 +29,18 @@ func NegativeVolumeIndex(source v2.KLineSubscription) *NVIStream { source.AddSubscriber(func(v types.KLine) { var nvi = fixedpoint.Zero - if s.Slice.Length() == 0 { + if s.Length() == 0 { nvi = NVI_STARTING_VALUE } else { - closing := source.Last(0).Close - prevClose := source.Last(1).Close - lastNVI := fixedpoint.NewFromFloat(s.Slice.Last(0)) - if source.Last(1).Volume < source.Last(0).Volume { - nvi = lastNVI + var ( + prev = source.Last(1) + prevNVI = fixedpoint.NewFromFloat(s.Slice.Last(0)) + ) + if v.Volume > prev.Volume { + nvi = prevNVI } else { - nvi += ((closing - prevClose) / prevClose) * lastNVI + inner := v.Close.Sub(prev.Close).Div(prev.Close) + nvi = prevNVI.Add(inner.Mul(prevNVI)) } } @@ -47,3 +49,7 @@ func NegativeVolumeIndex(source v2.KLineSubscription) *NVIStream { return s } + +func (s *NVIStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volume/negative_volume_index_test.go b/pkg/indicator/v2/volume/negative_volume_index_test.go index 09c1740d15..94e5df2523 100644 --- a/pkg/indicator/v2/volume/negative_volume_index_test.go +++ b/pkg/indicator/v2/volume/negative_volume_index_test.go @@ -5,17 +5,18 @@ import ( "github.com/stretchr/testify/assert" + "github.com/c9s/bbgo/pkg/fixedpoint" v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) func TestNegativeVolumeIndex(t *testing.T) { ts := []types.KLine{ - {Volume: 100, Close: 9}, - {Volume: 110, Close: 11}, - {Volume: 80, Close: 7}, - {Volume: 120, Close: 10}, - {Volume: 90, Close: 8}, + {Volume: n(100), Close: n(9)}, + {Volume: n(110), Close: n(11)}, + {Volume: n(80), Close: n(7)}, + {Volume: n(120), Close: n(10)}, + {Volume: n(90), Close: n(8)}, } stream := &types.StandardStream{} @@ -25,10 +26,15 @@ func TestNegativeVolumeIndex(t *testing.T) { for _, candle := range ts { stream.EmitKLineClosed(candle) } - assert.InDelta(t, 509.09, ind.Last(0), 0.001) - assert.InDelta(t, 636.36, ind.Last(1), 0.001) - assert.InDelta(t, 636.36, ind.Last(2), 0.001) - assert.InDelta(t, 1000.0, ind.Last(3), 0.001) - assert.InDelta(t, 1000.0, ind.Last(4), 0.001) + assert.InDelta(t, 509.09, ind.Last(0), 0.01) + assert.InDelta(t, 636.36, ind.Last(1), 0.01) + assert.InDelta(t, 636.36, ind.Last(2), 0.01) + assert.InDelta(t, 1000.0, ind.Last(3), 0.01) + assert.InDelta(t, 1000.0, ind.Last(4), 0.01) + +} + +func n(n float64) fixedpoint.Value { + return fixedpoint.NewFromFloat(n) } diff --git a/pkg/indicator/v2/window.go b/pkg/indicator/v2/window.go new file mode 100644 index 0000000000..2e5b4892bb --- /dev/null +++ b/pkg/indicator/v2/window.go @@ -0,0 +1,24 @@ +package indicatorv2 + +// Window returns a copied slice of series starting at n index ago. +func Window[T any](series []T, n int) []T { + + ln := len(series) + if ln <= n { + window := make([]T, ln) + copy(window, series) + return window + } + + i := (ln - n) - 1 + window := make([]T, n+1) + copy(window, series[i:]) + + return window +} + +// WindowAppend appends a value to the end of the series and slices it to the window starting at n index ago. +// Semantics of n argument are the same as Window function. +func WindowAppend[T any](series []T, n int, v T) []T { + return Window(append(series, v), n) +} diff --git a/pkg/indicator/v2/lookback_test.go b/pkg/indicator/v2/window_test.go similarity index 68% rename from pkg/indicator/v2/lookback_test.go rename to pkg/indicator/v2/window_test.go index d03380b115..ac12f00bc5 100644 --- a/pkg/indicator/v2/lookback_test.go +++ b/pkg/indicator/v2/window_test.go @@ -1,6 +1,3 @@ -// Copyright 2022 The Coln Group Ltd -// SPDX-License-Identifier: MIT - package indicatorv2 import ( @@ -9,46 +6,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestLookback(t *testing.T) { - tests := []struct { - name string - giveSeries []float64 - giveN int - want float64 - }{ - { - name: "Last value", - giveSeries: []float64{0, 1, 2, 3, 4, 5}, - giveN: 0, - want: 5, - }, - { - name: "First value", - giveSeries: []float64{0, 1, 2, 3, 4, 5}, - giveN: 6, - want: 0, - }, - { - name: "Value", - giveSeries: []float64{0, 1, 2, 3, 4, 5}, - giveN: 2, - want: 3, - }, - { - name: "Index out of range return 0", - giveSeries: []float64{0, 1, 2, 3, 4, 5}, - giveN: 7, - want: 0, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - act := Lookback(tt.giveSeries, tt.giveN) - assert.Equal(t, tt.want, act) - }) - } -} - func TestWindow(t *testing.T) { tests := []struct { name string diff --git a/pkg/report/profit_report.go b/pkg/report/profit_report.go index 065a425011..701d3e3c9e 100644 --- a/pkg/report/profit_report.go +++ b/pkg/report/profit_report.go @@ -2,12 +2,13 @@ package report import ( "fmt" + "strconv" + "github.com/c9s/bbgo/pkg/data/tsv" "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" - "strconv" ) // AccumulatedProfitReport For accumulated profit report output @@ -33,7 +34,7 @@ type AccumulatedProfitReport struct { accumulatedProfitPerInterval *types.Float64Series // Accumulated profit MA - profitMA *indicatorv2.SMAStream + profitMA *trend.SMAStream profitMAPerInterval floats.Slice // Profit of each interval @@ -75,7 +76,7 @@ func (r *AccumulatedProfitReport) Initialize(symbol string, interval types.Inter } r.accumulatedProfitPerInterval = types.NewFloat64Series() - r.profitMA = indicatorv2.SMA(r.accumulatedProfitPerInterval, r.ProfitMAWindow) + r.profitMA = trend.SMA(r.accumulatedProfitPerInterval, r.ProfitMAWindow) } func (r *AccumulatedProfitReport) AddStrategyParameter(title string, value string) { diff --git a/pkg/strategy/bollmaker/dynamic_spread.go b/pkg/strategy/bollmaker/dynamic_spread.go index f236c34eaa..880f8b0e40 100644 --- a/pkg/strategy/bollmaker/dynamic_spread.go +++ b/pkg/strategy/bollmaker/dynamic_spread.go @@ -7,7 +7,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/indicator" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/indicator/v2/volatility" "github.com/c9s/bbgo/pkg/types" ) @@ -29,7 +29,7 @@ type DynamicSpreadSettings struct { } // Initialize dynamic spreads and preload SMAs -func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *indicatorv2.BOLLStream) { +func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *volatility.BOLLStream) { switch { case ds.AmpSpreadSettings != nil: ds.AmpSpreadSettings.initialize(symbol, session) @@ -165,10 +165,10 @@ type DynamicSpreadBollWidthRatioSettings struct { // A positive number. The greater factor, the sharper weighting function. Default set to 1.0 . Sensitivity float64 `json:"sensitivity"` - defaultBoll, neutralBoll *indicatorv2.BOLLStream + defaultBoll, neutralBoll *volatility.BOLLStream } -func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *indicatorv2.BOLLStream) { +func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *volatility.BOLLStream) { ds.neutralBoll = neutralBoll ds.defaultBoll = defaultBoll if ds.Sensitivity <= 0. { diff --git a/pkg/strategy/bollmaker/strategy.go b/pkg/strategy/bollmaker/strategy.go index d8f32b8c25..131eef9349 100644 --- a/pkg/strategy/bollmaker/strategy.go +++ b/pkg/strategy/bollmaker/strategy.go @@ -6,15 +6,14 @@ import ( "math" "sync" - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/util" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/indicator/v2/volatility" "github.com/c9s/bbgo/pkg/types" + "github.com/c9s/bbgo/pkg/util" ) // TODO: @@ -158,10 +157,10 @@ type Strategy struct { groupID uint32 // defaultBoll is the BOLLINGER indicator we used for predicting the price. - defaultBoll *indicatorv2.BOLLStream + defaultBoll *volatility.BOLLStream // neutralBoll is the neutral price section - neutralBoll *indicatorv2.BOLLStream + neutralBoll *volatility.BOLLStream // StrategyController bbgo.StrategyController diff --git a/pkg/strategy/bollmaker/trend.go b/pkg/strategy/bollmaker/trend.go index 0ff0cc9d39..61a4fb2613 100644 --- a/pkg/strategy/bollmaker/trend.go +++ b/pkg/strategy/bollmaker/trend.go @@ -1,8 +1,6 @@ package bollmaker -import ( - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" -) +import "github.com/c9s/bbgo/pkg/indicator/v2/volatility" type PriceTrend string @@ -13,7 +11,7 @@ const ( UnknownTrend PriceTrend = "unknown" ) -func detectPriceTrend(inc *indicatorv2.BOLLStream, price float64) PriceTrend { +func detectPriceTrend(inc *volatility.BOLLStream, price float64) PriceTrend { if inBetween(price, inc.DownBand.Last(0), inc.UpBand.Last(0)) { return NeutralTrend } diff --git a/pkg/strategy/scmaker/strategy.go b/pkg/strategy/scmaker/strategy.go index 389a54b080..e214651243 100644 --- a/pkg/strategy/scmaker/strategy.go +++ b/pkg/strategy/scmaker/strategy.go @@ -13,6 +13,7 @@ import ( "github.com/c9s/bbgo/pkg/fixedpoint" . "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/indicator/v2/trend" + "github.com/c9s/bbgo/pkg/indicator/v2/volatility" "github.com/c9s/bbgo/pkg/risk/riskcontrol" "github.com/c9s/bbgo/pkg/strategy/common" "github.com/c9s/bbgo/pkg/types" @@ -76,7 +77,7 @@ type Strategy struct { // indicators ewma *trend.EWMAStream - boll *BOLLStream + boll *volatility.BOLLStream intensity *IntensityStream positionRiskControl *riskcontrol.PositionRiskControl @@ -202,7 +203,7 @@ func (s *Strategy) initializeIntensityIndicator(session *bbgo.ExchangeSession) { func (s *Strategy) initializePriceRangeBollinger(session *bbgo.ExchangeSession) { kLines := KLines(session.MarketDataStream, s.Symbol, s.PriceRangeBollinger.Interval) closePrices := ClosePrices(kLines) - s.boll = BOLL(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) + s.boll = volatility.BOLL(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) s.preloadKLines(kLines, session, s.Symbol, s.PriceRangeBollinger.Interval) } diff --git a/pkg/types/kline.go b/pkg/types/kline.go index 6bf863c30b..cadb529176 100644 --- a/pkg/types/kline.go +++ b/pkg/types/kline.go @@ -673,6 +673,10 @@ func KLineHLC3Mapper(k KLine) float64 { return k.High.Add(k.Low).Add(k.Close).Div(Three).Float64() } +func KLineHL2Mapper(k KLine) float64 { + return k.High.Add(k.Low).Div(Two).Float64() +} + func MapKLinePrice(kLines []KLine, f KLineValueMapper) (prices []float64) { for _, k := range kLines { prices = append(prices, f(k)) diff --git a/pkg/types/series_float64.go b/pkg/types/series_float64.go index f12e05d584..0baee1ef30 100644 --- a/pkg/types/series_float64.go +++ b/pkg/types/series_float64.go @@ -29,6 +29,22 @@ func (f *Float64Series) Length() int { return len(f.Slice) } +// CrossOver returns true if the latest series values cross above x +func (f *Float64Series) CrossOver(curr, x float64) bool { + if f.Last(1) < x && curr > x { + return true + } + return false +} + +// CrossDown returns true if the latest series values cross below x +func (f *Float64Series) CrossUnder(x float64) bool { + if f.Last(1) > x && f.Last(0) < x { + return true + } + return false +} + func (f *Float64Series) Push(x float64) { f.Slice.Push(x) } From 67c0f6f13a64067669aa311f882aea6bd3f42b73 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Fri, 27 Oct 2023 00:13:13 +0200 Subject: [PATCH 03/17] add psar, vol profile, obv v2 indicators --- pkg/bbgo/indicator_set.go | 4 +- .../csvsource/bybit_tick_downloader.go | 101 + .../csvsource/bybit_tick_to_kline.go | 197 ++ pkg/datasource/csvsource/csv_kline_decoder.go | 153 ++ pkg/datasource/csvsource/csv_kline_reader.go | 65 + .../csvsource/csv_kline_reader_test.go | 155 ++ pkg/datasource/csvsource/read_klines.go | 59 + pkg/datasource/csvsource/read_klines_test.go | 14 + .../csvsource/testdata/BTCUSDT-1h-2021-Q1.csv | 2158 +++++++++++++++++ pkg/datatype/floats/slice.go | 7 + pkg/indicator/v2/price.go | 20 + pkg/indicator/v2/trend/parabolic_sar.go | 120 + pkg/indicator/v2/trend/parabolic_sar_test.go | 67 + pkg/indicator/v2/volume/obv.go | 41 + pkg/indicator/v2/volume/obv_test.go | 38 + .../volume/testdata/BTCUSDT-1m-2022-05-06.csv | 1440 +++++++++++ pkg/indicator/v2/volume/volume_profile.go | 195 ++ .../v2/volume/volume_profile_test.go | 41 + 18 files changed, 4873 insertions(+), 2 deletions(-) create mode 100644 pkg/datasource/csvsource/bybit_tick_downloader.go create mode 100644 pkg/datasource/csvsource/bybit_tick_to_kline.go create mode 100644 pkg/datasource/csvsource/csv_kline_decoder.go create mode 100644 pkg/datasource/csvsource/csv_kline_reader.go create mode 100644 pkg/datasource/csvsource/csv_kline_reader_test.go create mode 100644 pkg/datasource/csvsource/read_klines.go create mode 100644 pkg/datasource/csvsource/read_klines_test.go create mode 100755 pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv create mode 100644 pkg/indicator/v2/trend/parabolic_sar.go create mode 100644 pkg/indicator/v2/trend/parabolic_sar_test.go create mode 100644 pkg/indicator/v2/volume/obv.go create mode 100644 pkg/indicator/v2/volume/obv_test.go create mode 100644 pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv create mode 100644 pkg/indicator/v2/volume/volume_profile.go create mode 100644 pkg/indicator/v2/volume/volume_profile_test.go diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index a1697fefb5..cb3d4bef50 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -88,8 +88,8 @@ func (i *IndicatorSet) EWMA(iw types.IntervalWindow) *trend.EWMAStream { return trend.EWMA2(i.CLOSE(iw.Interval), iw.Window) } -func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *indicatorv2.StochStream { - return indicatorv2.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) +func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *momentum.StochStream { + return momentum.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) } func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *volatility.BOLLStream { diff --git a/pkg/datasource/csvsource/bybit_tick_downloader.go b/pkg/datasource/csvsource/bybit_tick_downloader.go new file mode 100644 index 0000000000..6d37231a1c --- /dev/null +++ b/pkg/datasource/csvsource/bybit_tick_downloader.go @@ -0,0 +1,101 @@ +package csvsource + +import ( + "bytes" + "compress/gzip" + "errors" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" +) + +func Download(symbol string, start time.Time) { + for { + var ( + path = fmt.Sprintf("pkg/datasource/csv/testdata/bybit/%s/", symbol) + fileName = fmt.Sprintf("%s%s.csv", strings.ToUpper(symbol), start.Format("2006-01-02")) + ) + + if fileExists(path + fileName) { + start = start.AddDate(0, 0, 1) + continue + } + + var url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", + strings.ToUpper(symbol), + fileName) + + fmt.Println("fetching ", url) + + err := readCSVFromUrl(url, path, fileName) + if err != nil { + fmt.Println(err) + break + } + + start = start.AddDate(0, 0, 1) + } +} + +func readCSVFromUrl(url, path, fileName string) error { + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + csvContent, err := gUnzipData(body) + if err != nil { + return err + } + + if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { + err := os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + } + + err = os.WriteFile(path+fileName, csvContent, 0666) + if err != nil { + return err + } + + return nil +} + +func gUnzipData(data []byte) (resData []byte, err error) { + b := bytes.NewBuffer(data) + + var r io.Reader + r, err = gzip.NewReader(b) + if err != nil { + return + } + + var resB bytes.Buffer + _, err = resB.ReadFrom(r) + if err != nil { + return + } + + resData = resB.Bytes() + + return +} + +func fileExists(fileName string) bool { + info, err := os.Stat(fileName) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/pkg/datasource/csvsource/bybit_tick_to_kline.go b/pkg/datasource/csvsource/bybit_tick_to_kline.go new file mode 100644 index 0000000000..1daca70494 --- /dev/null +++ b/pkg/datasource/csvsource/bybit_tick_to_kline.go @@ -0,0 +1,197 @@ +package csvsource + +import ( + "encoding/csv" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +var klines []types.KLine + +type BybitCsvTick struct { + Timestamp int64 `json:"timestamp"` + Symbol string `json:"symbol"` + Side string `json:"side"` + TickDirection string `json:"tickDirection"` + Size fixedpoint.Value `json:"size"` + Price fixedpoint.Value `json:"price"` + HomeNotional fixedpoint.Value `json:"homeNotional"` + ForeignNotional fixedpoint.Value `json:"foreignNotional"` +} + +func ConvertTicksToKlines(symbol string, interval time.Duration) error { + err := filepath.Walk( + fmt.Sprintf("pkg/datasource/csv/testdata/bybit/%s/", symbol), + func(path string, info os.FileInfo, err error) error { + if err != nil { + fmt.Println(err) + return err + } + fmt.Printf("dir: %v: name: %s\n", info.IsDir(), path) + if !info.IsDir() { + file, err := os.Open(path) + if err != nil { + return err + } + reader := csv.NewReader(file) + data, err := reader.ReadAll() + if err != nil { + return err + } + for idx, row := range data { + // skip header + if idx == 0 { + continue + } + if idx == 1 { + continue + } + timestamp, err := strconv.ParseInt(strings.Split(row[0], ".")[0], 10, 64) + if err != nil { + return err + } + size, err := strconv.ParseFloat(row[3], 64) + if err != nil { + return err + } + price, err := strconv.ParseFloat(row[4], 64) + if err != nil { + return err + } + homeNotional, err := strconv.ParseFloat(row[5], 64) + if err != nil { + return err + } + foreignNotional, err := strconv.ParseFloat(row[9], 64) + if err != nil { + return err + } + ConvertBybitCsvTickToCandles(BybitCsvTick{ + Timestamp: int64(timestamp), + Symbol: row[1], + Side: row[2], + Size: fixedpoint.NewFromFloat(size), + Price: fixedpoint.NewFromFloat(price), + TickDirection: row[5], + HomeNotional: fixedpoint.NewFromFloat(homeNotional), + ForeignNotional: fixedpoint.NewFromFloat(foreignNotional), + }, interval) + } + } + return nil + }) + if err != nil { + return err + } + + return WriteKlines(fmt.Sprintf("pkg/datasource/csv/testdata/%s_%s.csv", symbol, interval.String()), klines) +} + +// WriteKlines write csv to path. +func WriteKlines(path string, prices []types.KLine) (err error) { + file, err := os.Create(path) + if err != nil { + return errors.Wrap(err, "failed to open file") + } + defer func() { + err = file.Close() + if err != nil { + panic("failed to close file") + } + }() + w := csv.NewWriter(file) + defer w.Flush() + // Using Write + for _, record := range prices { + row := []string{strconv.Itoa(int(record.StartTime.UnixMilli())), dtos(record.Open), dtos(record.High), dtos(record.Low), dtos(record.Close), dtos(record.Volume)} + if err := w.Write(row); err != nil { + return errors.Wrap(err, "writing record to file") + } + } + if err != nil { + return err + } + + return nil +} + +func dtos(n fixedpoint.Value) string { + return fmt.Sprintf("%f", n.Float64()) +} + +func ConvertBybitCsvTickToCandles(tick BybitCsvTick, interval time.Duration) { + var ( + currentCandle = types.KLine{} + high = fixedpoint.Zero + low = fixedpoint.Zero + tickTimeStamp = time.Unix(tick.Timestamp, 0) + ) + isOpen, isCLose, openTime := detCandleStart(tickTimeStamp, interval) + + if isOpen { + klines = append(klines, types.KLine{ + StartTime: types.NewTimeFromUnix(openTime.Unix(), 0), + Open: tick.Price, + High: tick.Price, + Low: tick.Price, + Close: tick.Price, + Volume: tick.HomeNotional, + }) + return + } + + currentCandle = klines[len(klines)-1] + + if tick.Price > currentCandle.High { + high = tick.Price + } else { + high = currentCandle.High + } + + if tick.Price < currentCandle.Low { + low = tick.Price + } else { + low = currentCandle.Low + } + + kline := types.KLine{ + StartTime: currentCandle.StartTime, + Open: currentCandle.Open, + High: high, + Low: low, + Close: tick.Price, + Volume: currentCandle.Volume.Add(tick.HomeNotional), + } + if isCLose { + klines = append(klines, kline) + } else { + klines[len(klines)-1] = kline + } +} + +func detCandleStart(ts time.Time, interval time.Duration) (isOpen, isClose bool, t time.Time) { + if len(klines) == 0 { + start := time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour()+1, 0, 0, 0, ts.Location()) + if t.Minute() < int(interval.Minutes()) { // supported intervals 5 10 15 30 + start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), int(interval.Minutes()), 0, 0, ts.Location()) + } + return true, false, start + } else { + current := klines[len(klines)-1] + end := current.StartTime.Time().Add(interval) + if end.After(ts) { + return false, true, end + } + } + + return false, false, t +} diff --git a/pkg/datasource/csvsource/csv_kline_decoder.go b/pkg/datasource/csvsource/csv_kline_decoder.go new file mode 100644 index 0000000000..904dc06018 --- /dev/null +++ b/pkg/datasource/csvsource/csv_kline_decoder.go @@ -0,0 +1,153 @@ +package csvsource + +import ( + "encoding/csv" + "errors" + "fmt" + "strconv" + "time" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +// MetaTraderTimeFormat is the time format expected by the MetaTrader decoder when cols [0] and [1] are used. +const MetaTraderTimeFormat = "02/01/2006 15:04" + +var ( + // ErrNotEnoughColumns is returned when the CSV price record does not have enough columns. + ErrNotEnoughColumns = errors.New("not enough columns") + + // ErrInvalidTimeFormat is returned when the CSV price record does not have a valid time unix milli format. + ErrInvalidTimeFormat = errors.New("cannot parse time string") + + // ErrInvalidPriceFormat is returned when the CSV price record does not prices in expected format. + ErrInvalidPriceFormat = errors.New("OHLC prices must be in valid decimal format") + + // ErrInvalidVolumeFormat is returned when the CSV price record does not have a valid volume format. + ErrInvalidVolumeFormat = errors.New("volume must be in valid float format") +) + +// CSVKlineDecoder is an extension point for CSVKlineReader to support custom file formats. +type CSVKlineDecoder func(record []string, interval time.Duration) (types.KLine, error) + +// NewBinanceCSVKlineReader creates a new CSVKlineReader for Binance CSV files. +func NewBinanceCSVKlineReader(csv *csv.Reader) *CSVKlineReader { + return &CSVKlineReader{ + csv: csv, + decoder: BinanceCSVKlineDecoder, + } +} + +// BinanceCSVKlineDecoder decodes a CSV record from Binance or Bybit into a Kline. +func BinanceCSVKlineDecoder(record []string, interval time.Duration) (types.KLine, error) { + var ( + k, empty types.KLine + err error + ) + + if len(record) < 5 { + return k, ErrNotEnoughColumns + } + + msec, err := strconv.ParseInt(record[0], 10, 64) + if err != nil { + return empty, ErrInvalidTimeFormat + } + k.StartTime = types.NewTimeFromUnix(time.UnixMilli(msec).Unix(), 0) + open, err := strconv.ParseFloat(record[1], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Open = fixedpoint.NewFromFloat(open) + + high, err := strconv.ParseFloat(record[2], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.High = fixedpoint.NewFromFloat(high) + + low, err := strconv.ParseFloat(record[3], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Low = fixedpoint.NewFromFloat(low) + + close, err := strconv.ParseFloat(record[4], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Close = fixedpoint.NewFromFloat(close) + + if len(record) > 5 { + vol, err := strconv.ParseFloat(record[5], 64) + if err != nil { + return empty, ErrInvalidVolumeFormat + } + k.Volume = fixedpoint.NewFromFloat(vol) + } + + return k, nil +} + +// NewMetaTraderCSVKlineReader creates a new CSVKlineReader for MetaTrader CSV files. +func NewMetaTraderCSVKlineReader(csv *csv.Reader) *CSVKlineReader { + csv.Comma = ';' + return &CSVKlineReader{ + csv: csv, + decoder: MetaTraderCSVKlineDecoder, + } +} + +// MetaTraderCSVKlineDecoder decodes a CSV record from MetaTrader into a Kline. +func MetaTraderCSVKlineDecoder(record []string, interval time.Duration) (types.KLine, error) { + var ( + k, empty types.KLine + err error + ) + + if len(record) < 6 { + return k, ErrNotEnoughColumns + } + + tStr := fmt.Sprintf("%s %s", record[0], record[1]) + t, err := time.Parse(MetaTraderTimeFormat, tStr) + if err != nil { + return empty, ErrInvalidTimeFormat + } + k.StartTime = types.NewTimeFromUnix(t.Unix(), 0) + + open, err := strconv.ParseFloat(record[2], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Open = fixedpoint.NewFromFloat(open) + + high, err := strconv.ParseFloat(record[3], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.High = fixedpoint.NewFromFloat(high) + + low, err := strconv.ParseFloat(record[4], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Low = fixedpoint.NewFromFloat(low) + + close, err := strconv.ParseFloat(record[5], 64) + if err != nil { + return empty, ErrInvalidPriceFormat + } + k.Close = fixedpoint.NewFromFloat(close) + + if len(record) > 5 { + vol, err := strconv.ParseFloat(record[6], 64) + if err != nil { + return empty, ErrInvalidVolumeFormat + } + k.Volume = fixedpoint.NewFromFloat(vol) + } + + return k, nil +} diff --git a/pkg/datasource/csvsource/csv_kline_reader.go b/pkg/datasource/csvsource/csv_kline_reader.go new file mode 100644 index 0000000000..ca8c7a891b --- /dev/null +++ b/pkg/datasource/csvsource/csv_kline_reader.go @@ -0,0 +1,65 @@ +package csvsource + +import ( + "encoding/csv" + "io" + "time" + + "github.com/c9s/bbgo/pkg/types" +) + +var _ KlineReader = (*CSVKlineReader)(nil) + +// CSVKlineReader is a KlineReader that reads from a CSV file. +type CSVKlineReader struct { + csv *csv.Reader + decoder CSVKlineDecoder +} + +// MakeCSVKlineReader is a factory method type that creates a new CSVKlineReader. +type MakeCSVKlineReader func(csv *csv.Reader) *CSVKlineReader + +// NewCSVKlineReader creates a new CSVKlineReader with the default Binance decoder. +func NewCSVKlineReader(csv *csv.Reader) *CSVKlineReader { + return &CSVKlineReader{ + csv: csv, + decoder: BinanceCSVKlineDecoder, + } +} + +// NewCSVKlineReaderWithDecoder creates a new CSVKlineReader with the given decoder. +func NewCSVKlineReaderWithDecoder(csv *csv.Reader, decoder CSVKlineDecoder) *CSVKlineReader { + return &CSVKlineReader{ + csv: csv, + decoder: decoder, + } +} + +// Read reads the next Kline from the underlying CSV data. +func (r *CSVKlineReader) Read(interval time.Duration) (types.KLine, error) { + var k types.KLine + + rec, err := r.csv.Read() + if err != nil { + return k, err + } + + return r.decoder(rec, interval) +} + +// ReadAll reads all the Klines from the underlying CSV data. +func (r *CSVKlineReader) ReadAll(interval time.Duration) ([]types.KLine, error) { + var ks []types.KLine + for { + k, err := r.Read(interval) + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + ks = append(ks, k) + } + + return ks, nil +} diff --git a/pkg/datasource/csvsource/csv_kline_reader_test.go b/pkg/datasource/csvsource/csv_kline_reader_test.go new file mode 100644 index 0000000000..076a93cb7f --- /dev/null +++ b/pkg/datasource/csvsource/csv_kline_reader_test.go @@ -0,0 +1,155 @@ +package csvsource + +import ( + "encoding/csv" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +var assertKlineEq = func(t *testing.T, exp, act types.KLine) { + assert.Equal(t, exp.StartTime, act.StartTime) + assert.True(t, exp.Open == act.Open) + assert.True(t, exp.High == act.High) + assert.True(t, exp.Low == act.Low) + assert.True(t, exp.Close == act.Close) + assert.Equal(t, exp.Volume, act.Volume) +} + +func TestCSVKlineReader_ReadWithBinanceDecoder(t *testing.T) { + tests := []struct { + name string + give string + want types.KLine + err error + }{ + { + name: "Read DOHLCV", + give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", + want: types.KLine{ + StartTime: types.NewTimeFromUnix(1609459200000, 0), + Open: fixedpoint.NewFromFloat(28923.63), + High: fixedpoint.NewFromFloat(29031.34), + Low: fixedpoint.NewFromFloat(28690.17), + Close: fixedpoint.NewFromFloat(28995.13), + Volume: fixedpoint.NewFromFloat(2311.81144500)}, + err: nil, + }, + { + name: "Read DOHLC", + give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000", + want: types.KLine{ + StartTime: types.NewTimeFromUnix(1609459200000, 0), + Open: fixedpoint.NewFromFloat(28923.63), + High: fixedpoint.NewFromFloat(29031.34), + Low: fixedpoint.NewFromFloat(28690.17), + Close: fixedpoint.NewFromFloat(28995.13), + Volume: fixedpoint.NewFromFloat(0)}, + err: nil, + }, + { + name: "Not enough columns", + give: "1609459200000,28923.63000000,29031.34000000", + want: types.KLine{}, + err: ErrNotEnoughColumns, + }, + { + name: "Invalid time format", + give: "23/12/2021,28923.63000000,29031.34000000,28690.17000000,28995.13000000", + want: types.KLine{}, + err: ErrInvalidTimeFormat, + }, + { + name: "Invalid price format", + give: "1609459200000,sixty,29031.34000000,28690.17000000,28995.13000000", + want: types.KLine{}, + err: ErrInvalidPriceFormat, + }, + { + name: "Invalid volume format", + give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,vol", + want: types.KLine{}, + err: ErrInvalidVolumeFormat, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reader := NewBinanceCSVKlineReader(csv.NewReader(strings.NewReader(tt.give))) + kline, err := reader.Read(time.Hour) + assert.Equal(t, tt.err, err) + assertKlineEq(t, tt.want, kline) + }) + } +} + +func TestCSVKlineReader_ReadAllWithDefaultDecoder(t *testing.T) { + records := []string{ + "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", + "1609459300000,28928.63000000,30031.34000000,22690.17000000,28495.13000000,3000.00", + } + reader := NewCSVKlineReader(csv.NewReader(strings.NewReader(strings.Join(records, "\n")))) + klines, err := reader.ReadAll(time.Hour) + assert.NoError(t, err) + assert.Len(t, klines, 2) +} + +func TestCSVKlineReader_ReadWithMetaTraderDecoder(t *testing.T) { + + tests := []struct { + name string + give string + want types.KLine + err error + }{ + { + name: "Read DOHLCV", + give: "11/12/2008;16:00;779.527679;780.964756;777.527679;779.964756;5", + want: types.KLine{ + StartTime: types.NewTimeFromUnix(time.Date(2008, 12, 11, 16, 0, 0, 0, time.UTC).Unix(), 0), + Open: fixedpoint.NewFromFloat(779.527679), + High: fixedpoint.NewFromFloat(780.964756), + Low: fixedpoint.NewFromFloat(777.527679), + Close: fixedpoint.NewFromFloat(779.964756), + Volume: fixedpoint.NewFromFloat(5)}, + err: nil, + }, + { + name: "Not enough columns", + give: "1609459200000;28923.63000000;29031.34000000", + want: types.KLine{}, + err: ErrNotEnoughColumns, + }, + { + name: "Invalid time format", + give: "23/12/2021;t;28923.63000000;29031.34000000;28690.17000000;28995.13000000", + want: types.KLine{}, + err: ErrInvalidTimeFormat, + }, + { + name: "Invalid price format", + give: "11/12/2008;00:00;sixty;29031.34000000;28690.17000000;28995.13000000", + want: types.KLine{}, + err: ErrInvalidPriceFormat, + }, + { + name: "Invalid volume format", + give: "11/12/2008;00:00;779.527679;780.964756;777.527679;779.964756;vol", + want: types.KLine{}, + err: ErrInvalidVolumeFormat, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reader := NewMetaTraderCSVKlineReader(csv.NewReader(strings.NewReader(tt.give))) + kline, err := reader.Read(time.Hour) + assert.Equal(t, tt.err, err) + assertKlineEq(t, tt.want, kline) + }) + } +} diff --git a/pkg/datasource/csvsource/read_klines.go b/pkg/datasource/csvsource/read_klines.go new file mode 100644 index 0000000000..bee351ab77 --- /dev/null +++ b/pkg/datasource/csvsource/read_klines.go @@ -0,0 +1,59 @@ +package csvsource + +import ( + "encoding/csv" + "io/fs" + "os" + "path/filepath" + "time" + + "github.com/c9s/bbgo/pkg/types" +) + +// KlineReader is an interface for reading candlesticks. +type KlineReader interface { + Read(interval time.Duration) (types.KLine, error) + ReadAll(interval time.Duration) ([]types.KLine, error) +} + +// ReadKlinesFromCSV reads all the .csv files in a given directory or a single file into a slice of Klines. +// Wraps a default CSVKlineReader with Binance decoder for convenience. +// For finer grained memory management use the base kline reader. +func ReadKlinesFromCSV(path string, interval time.Duration) ([]types.KLine, error) { + return ReadKlinesFromCSVWithDecoder(path, interval, MakeCSVKlineReader(NewBinanceCSVKlineReader)) +} + +// ReadKlinesFromCSVWithDecoder permits using a custom CSVKlineReader. +func ReadKlinesFromCSVWithDecoder(path string, interval time.Duration, maker MakeCSVKlineReader) ([]types.KLine, error) { + var prices []types.KLine + + err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if filepath.Ext(path) != ".csv" { + return nil + } + file, err := os.Open(path) + if err != nil { + return err + } + //nolint:errcheck // Read ops only so safe to ignore err return + defer file.Close() + reader := maker(csv.NewReader(file)) + klines, err := reader.ReadAll(interval) + if err != nil { + return err + } + prices = append(prices, klines...) + return nil + }) + if err != nil { + return nil, err + } + + return prices, nil +} diff --git a/pkg/datasource/csvsource/read_klines_test.go b/pkg/datasource/csvsource/read_klines_test.go new file mode 100644 index 0000000000..109828dc5e --- /dev/null +++ b/pkg/datasource/csvsource/read_klines_test.go @@ -0,0 +1,14 @@ +package csvsource + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestReadKlinesFromCSV(t *testing.T) { + prices, err := ReadKlinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) + assert.NoError(t, err) + assert.Len(t, prices, 2158) +} diff --git a/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv b/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv new file mode 100755 index 0000000000..c61915e335 --- /dev/null +++ b/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv @@ -0,0 +1,2158 @@ +1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500,1609462799999,66768830.34010008,58389,1215.35923800,35103542.78288276,0 +1609462800000,28995.13000000,29470.00000000,28960.35000000,29409.99000000,5403.06847100,1609466399999,158357816.81805722,103896,3160.04170100,92613991.93555293,0 +1609466400000,29410.00000000,29465.26000000,29120.03000000,29194.65000000,2384.23156000,1609469999999,69842653.67342030,57646,1203.43350600,35252749.90832606,0 +1609470000000,29195.25000000,29367.00000000,29150.02000000,29278.40000000,1461.34507700,1609473599999,42760776.72551646,42510,775.91566600,22705547.98307977,0 +1609473600000,29278.41000000,29395.00000000,29029.40000000,29220.31000000,2038.04680300,1609477199999,59614637.30352874,55414,1003.34283400,29346381.88020654,0 +1609477200000,29220.31000000,29235.28000000,29084.11000000,29187.01000000,1469.95626200,1609480799999,42864538.70435811,41800,679.84674200,19827190.29247262,0 +1609480800000,29187.01000000,29270.00000000,29077.32000000,29174.35000000,1420.72629100,1609484399999,41446013.01819005,46400,699.14267600,20398322.75992173,0 +1609484400000,29174.35000000,29191.98000000,28806.54000000,29092.83000000,2380.18091800,1609487999999,69034619.09489940,53158,1054.72099100,30598457.40248306,0 +1609488000000,29092.84000000,29178.03000000,28872.24000000,29000.01000000,2008.16573900,1609491599999,58274190.69862189,55012,1022.06617000,29662447.72598589,0 +1609491600000,29000.01000000,29307.73000000,28970.00000000,29202.21000000,2022.05602200,1609495199999,59006512.26098600,43674,1208.47757800,35272717.35224266,0 +1609495200000,29202.21000000,29344.97000000,29152.88000000,29223.82000000,1944.25584100,1609498799999,56881923.87605724,46783,1014.53831900,29683027.81899852,0 +1609498800000,29223.82000000,29402.57000000,29212.44000000,29313.49000000,2309.22771700,1609502399999,67680909.41227815,49883,1309.01281600,38371497.60008983,0 +1609502400000,29313.49000000,29600.00000000,29150.00000000,29233.49000000,4191.91516100,1609505999999,123253838.23617110,82845,2333.30675300,68649197.19260735,0 +1609506000000,29233.49000000,29470.00000000,29200.00000000,29464.79000000,2211.29829000,1609509599999,64952612.17843147,51420,1102.40410000,32385604.78507834,0 +1609509600000,29464.79000000,29530.00000000,29266.15000000,29327.84000000,2612.67217000,1609513199999,76824362.53364532,63341,1251.80870900,36813212.09859227,0 +1609513200000,29327.83000000,29391.00000000,29030.14000000,29188.67000000,2779.06389400,1609516799999,81232002.48765679,71966,1262.58015300,36922103.13134250,0 +1609516800000,29188.67000000,29360.00000000,29125.00000000,29300.57000000,1490.32948400,1609520399999,43610391.87454118,41586,774.31247700,22657543.68634492,0 +1609520400000,29300.79000000,29339.76000000,28937.00000000,29079.64000000,2504.97709900,1609523999999,73023440.33533108,58010,1019.11805100,29715488.81612700,0 +1609524000000,29077.59000000,29259.98000000,28624.57000000,29072.70000000,4226.43004100,1609527599999,122480565.74309262,88856,1801.54203200,52236804.42358850,0 +1609527600000,29072.70000000,29125.32000000,28950.00000000,29029.04000000,1629.22872100,1609531199999,47324728.28361069,49038,752.04501500,21847593.00496335,0 +1609531200000,29029.04000000,29279.72000000,28880.37000000,29200.96000000,1838.54908200,1609534799999,53590098.13888548,52949,960.22896300,27992651.84744214,0 +1609534800000,29200.97000000,29289.82000000,29130.00000000,29160.39000000,1447.22964100,1609538399999,42285361.51600605,34181,776.32409300,22684651.47220357,0 +1609538400000,29163.17000000,29326.74000000,29104.57000000,29262.32000000,1127.03589700,1609541999999,32972283.53778708,37533,552.48585500,16165226.57121833,0 +1609542000000,29262.32000000,29338.89000000,29228.14000000,29331.69000000,971.12338500,1609545599999,28443882.37070015,28620,523.74728700,15341792.07335345,0 +1609545600000,29331.70000000,29338.59000000,28946.53000000,29197.48000000,2638.15937900,1609549199999,76856531.55900287,56787,1247.24618700,36330827.26651437,0 +1609549200000,29197.93000000,29400.00000000,29100.00000000,29359.47000000,1891.99724900,1609552799999,55385402.78970417,41136,960.49200100,28127469.61077394,0 +1609552800000,29359.46000000,29469.00000000,29320.01000000,29323.82000000,1704.83013700,1609556399999,50111457.75322650,34864,919.10250700,27018817.34672662,0 +1609556400000,29323.82000000,29382.49000000,29256.85000000,29351.95000000,1158.04176100,1609559999999,33963115.16512242,33338,563.83224300,16536321.44525508,0 +1609560000000,29351.95000000,29396.00000000,29220.00000000,29349.63000000,988.71107000,1609563599999,28985783.95102539,36593,513.99851400,15069817.63238660,0 +1609563600000,29349.63000000,29590.00000000,29349.63000000,29589.99000000,2778.87823100,1609567199999,81957934.92152147,48203,1889.25015400,55722199.46021065,0 +1609567200000,29589.99000000,29745.00000000,29450.00000000,29709.07000000,3030.24082000,1609570799999,89791157.01909066,61113,1919.61728100,56884432.27238282,0 +1609570800000,29709.06000000,29820.50000000,29623.31000000,29750.00000000,3067.81272400,1609574399999,91222945.57779763,56853,1999.91714500,59479642.41147299,0 +1609574400000,29751.47000000,29849.11000000,29640.00000000,29844.51000000,2358.08824100,1609577999999,70213292.48882387,55194,1185.87901000,35308597.74347598,0 +1609578000000,29844.52000000,29899.00000000,29578.05000000,29612.87000000,3188.49737500,1609581599999,94891130.35379542,63645,1490.10338400,44368671.01529736,0 +1609581600000,29612.88000000,29829.00000000,29473.91000000,29680.99000000,2315.18233700,1609585199999,68694488.75869353,49466,1119.01804200,33209227.51330484,0 +1609585200000,29679.51000000,29780.53000000,29622.79000000,29755.00000000,1365.03665500,1609588799999,40570945.42355006,29571,598.18892600,17778425.81689583,0 +1609588800000,29754.99000000,30888.00000000,29741.39000000,30604.03000000,12772.56604400,1609592399999,387025691.68456484,200036,7693.61308900,232831158.19322058,0 +1609592400000,30604.03000000,31561.87000000,30521.00000000,31541.17000000,9182.42970300,1609595999999,284862696.67061101,155703,5000.51248100,155171075.80361159,0 +1609596000000,31546.06000000,31567.89000000,31065.00000000,31290.53000000,6447.78389700,1609599599999,201609364.53663465,115280,3104.82695800,97083027.72110683,0 +1609599600000,31290.53000000,31800.00000000,31236.37000000,31691.29000000,5626.19375500,1609603199999,177435149.22325535,97954,2936.49097300,92602951.94086850,0 +1609603200000,31691.09000000,33000.00000000,31616.42000000,32482.28000000,15432.28518600,1609606799999,500065150.69207718,243515,7704.18957300,249664588.17049993,0 +1609606800000,32484.28000000,32935.00000000,32394.77000000,32856.96000000,6402.18070100,1609610399999,209101591.46210164,106138,3400.89904700,111088781.87106785,0 +1609610400000,32856.95000000,33300.00000000,32421.00000000,32999.98000000,7170.29541200,1609613999999,235363454.12117517,107993,3731.00286900,122570325.41192683,0 +1609614000000,32999.98000000,33220.00000000,32690.00000000,33027.20000000,5844.85649900,1609617599999,192991798.29034694,100521,3074.28482400,101527404.04491779,0 +1609617600000,33027.20000000,33061.37000000,30550.00000000,30667.22000000,15733.28311200,1609621199999,504482345.09340442,213120,7147.18982200,229365443.72211530,0 +1609621200000,30669.43000000,32005.94000000,30300.00000000,31694.59000000,10395.12064200,1609624799999,326513926.94158377,161944,5285.50818400,165946681.21302372,0 +1609624800000,31693.53000000,32311.92000000,31424.96000000,32145.66000000,3879.06209400,1609628399999,124189288.57427153,91572,1766.47715100,56575341.60307028,0 +1609628400000,32143.53000000,32246.67000000,31500.00000000,32178.33000000,4622.34033800,1609631999999,147557520.62016068,85383,2194.66488100,70073494.65701959,0 +1609632000000,32176.45000000,32497.80000000,31962.99000000,32447.94000000,3346.06214100,1609635599999,108006253.42272902,63472,1758.75207800,56783635.03682368,0 +1609635600000,32447.95000000,32790.07000000,32201.00000000,32585.09000000,3401.15220700,1609639199999,110773399.69333609,70692,1770.81858900,57671008.07579552,0 +1609639200000,32583.04000000,32884.09000000,32550.00000000,32741.67000000,2017.20975900,1609642799999,66039545.22800387,48226,1010.49816300,33089617.80521227,0 +1609642800000,32741.68000000,32756.00000000,32404.00000000,32573.87000000,2125.87880000,1609646399999,69347477.45908845,46215,899.91924100,29356251.53461650,0 +1609646400000,32576.11000000,33250.00000000,32450.00000000,33192.53000000,3436.07098400,1609649999999,112792746.66880588,60917,2045.68522700,67209328.65906662,0 +1609650000000,33192.53000000,34180.00000000,33109.44000000,33758.67000000,10355.07031500,1609653599999,350167811.09683042,176812,5513.67143800,186390893.19406770,0 +1609653600000,33758.67000000,34110.05000000,33651.12000000,33967.13000000,4526.91097400,1609657199999,153551636.94704574,95086,2360.33759000,80068532.23998821,0 +1609657200000,33967.13000000,34778.11000000,33737.19000000,34452.34000000,7968.07402300,1609660799999,273877823.02471700,135337,3835.12822700,131801254.42768407,0 +1609660800000,34451.78000000,34670.41000000,33757.29000000,34367.68000000,6146.77411200,1609664399999,210713141.05225317,110795,2947.24110400,101077763.49754152,0 +1609664400000,34367.35000000,34588.88000000,33800.00000000,34190.55000000,6052.67897200,1609667999999,206713459.38775728,114590,2746.05092500,93808940.47277085,0 +1609668000000,34189.98000000,34350.00000000,33403.00000000,33877.96000000,6335.22664200,1609671599999,214615660.03475803,120518,3038.83693400,102960933.70594279,0 +1609671600000,33877.96000000,34450.00000000,33787.55000000,34413.53000000,4116.85314100,1609675199999,140535081.14537481,92262,2255.03787400,76986787.81280623,0 +1609675200000,34413.53000000,34600.00000000,33928.75000000,34103.72000000,4546.28348100,1609678799999,155830593.73039518,89900,2266.26171700,77715495.36382322,0 +1609678800000,34103.73000000,34385.02000000,33800.00000000,33880.00000000,4373.73837600,1609682399999,149031480.84569385,87957,2050.56080100,69890174.70069015,0 +1609682400000,33877.98000000,34150.00000000,33450.00000000,33811.54000000,5928.80556300,1609685999999,200638151.95697655,112757,2900.71102100,98139759.78261895,0 +1609686000000,33811.54000000,33873.45000000,32727.00000000,33506.62000000,8391.24975700,1609689599999,279582888.95484869,140091,3792.71472900,126401018.81240185,0 +1609689600000,33505.15000000,33822.69000000,32650.00000000,32676.74000000,7983.73912500,1609693199999,266031558.97452663,129178,3881.70200600,129341713.44537748,0 +1609693200000,32676.75000000,33333.33000000,32454.73000000,32909.27000000,7447.80916300,1609696799999,244812012.99385249,135756,3643.79336400,119852164.82576344,0 +1609696800000,32907.51000000,33031.57000000,32267.00000000,32769.76000000,4707.19994300,1609700399999,153750662.05561621,94512,2355.51975900,76959635.32715938,0 +1609700400000,32769.79000000,32930.00000000,32455.71000000,32772.21000000,2288.43941200,1609703999999,74825548.95742354,73266,1072.31709100,35065540.58420238,0 +1609704000000,32775.10000000,33816.00000000,32727.10000000,33726.21000000,5420.67818300,1609707599999,181382884.16276131,111426,2919.38549700,97677133.65780773,0 +1609707600000,33725.72000000,33861.92000000,33506.00000000,33558.34000000,2123.06799200,1609711199999,71508817.93767056,76216,1052.73779500,35464167.05367330,0 +1609711200000,33559.06000000,33661.10000000,33000.00000000,33119.14000000,2841.03309300,1609714799999,94606664.88271222,74965,1251.99851100,41712740.73810901,0 +1609714800000,33119.14000000,33600.00000000,32600.00000000,33000.05000000,5077.56059200,1609718399999,168463124.87883950,108752,2380.65319000,79003943.17790337,0 +1609718400000,33000.05000000,33111.44000000,32400.25000000,32843.88000000,4792.20683100,1609721999999,157090780.02866342,102303,2337.32205000,76640069.54148755,0 +1609722000000,32843.89000000,33327.00000000,32602.47000000,33191.04000000,3390.02387200,1609725599999,111723279.13155555,77232,1619.89909700,53373905.14610674,0 +1609725600000,33191.05000000,33588.00000000,32958.38000000,33454.22000000,3180.35078300,1609729199999,105765257.03035539,73174,1565.73680600,52080821.90135500,0 +1609729200000,33454.21000000,33510.71000000,33160.00000000,33505.16000000,3174.20913400,1609732799999,105885637.67106639,74546,1550.96606000,51736216.72372775,0 +1609732800000,33505.15000000,33600.00000000,33186.14000000,33257.55000000,3167.02927300,1609736399999,105695860.81390999,70718,1582.28668800,52806095.53989332,0 +1609736400000,33257.56000000,33315.90000000,32802.25000000,32813.01000000,3990.70088000,1609739999999,132098247.27391540,86995,1912.44957000,63309431.04982456,0 +1609740000000,32813.01000000,33408.00000000,32813.00000000,33100.02000000,4768.76492800,1609743599999,157679676.36409471,93791,2665.12417700,88130614.48937725,0 +1609743600000,33100.02000000,33148.69000000,31505.00000000,32068.84000000,9472.37682800,1609747199999,305928119.96734844,163230,4856.66906300,156851370.47884084,0 +1609747200000,32068.84000000,32567.88000000,31450.00000000,32045.14000000,6529.25324800,1609750799999,209132998.40311764,125127,2998.78773300,96102959.13230930,0 +1609750800000,32045.15000000,32152.15000000,30248.85000000,31038.63000000,11271.89653100,1609754399999,351321935.49618102,173055,5038.68188200,157122742.24963213,0 +1609754400000,31038.35000000,31227.33000000,28130.00000000,30270.76000000,19376.83117900,1609757999999,573629351.31642204,305630,9223.43025700,273302725.96630042,0 +1609758000000,30270.76000000,30900.20000000,29400.00000000,30743.06000000,9413.49006700,1609761599999,283733132.88333011,170181,4539.81272700,136956401.56307816,0 +1609761600000,30742.99000000,31434.07000000,30454.25000000,31219.02000000,8316.88082800,1609765199999,257727418.56933529,153242,3929.17547400,121744030.72879640,0 +1609765200000,31219.03000000,31400.00000000,30600.00000000,31400.00000000,5474.65478700,1609768799999,169692056.80846927,101540,2600.95311600,80643934.90996195,0 +1609768800000,31400.00000000,32167.93000000,31400.00000000,32113.68000000,7479.38358700,1609772399999,237746821.62135450,116397,3581.67988600,113853118.14224021,0 +1609772400000,32113.68000000,32185.67000000,31550.00000000,31745.72000000,5321.62025100,1609775999999,169560823.38397644,99381,2505.70734700,79819154.00419214,0 +1609776000000,31745.71000000,31920.00000000,30723.00000000,31320.31000000,8174.28578300,1609779599999,255043539.07925110,133682,4187.51493100,130621147.14683560,0 +1609779600000,31320.30000000,31523.01000000,30626.36000000,31024.17000000,4962.56272900,1609783199999,153975400.83942578,96732,2613.69739000,81111771.17490149,0 +1609783200000,31022.25000000,31465.44000000,31001.00000000,31165.16000000,3361.43987000,1609786799999,104948080.87133230,73391,1896.89392700,59231323.65317481,0 +1609786800000,31165.16000000,31855.75000000,31104.99000000,31665.51000000,3388.37222100,1609790399999,106758748.38653801,71762,1753.38870200,55257387.68892296,0 +1609790400000,31665.52000000,31830.95000000,31210.00000000,31244.97000000,2850.96308700,1609793999999,89770988.08670449,64911,1329.17277400,41858872.75067731,0 +1609794000000,31244.97000000,31579.00000000,30856.08000000,31014.27000000,3202.45612700,1609797599999,99727509.60811839,74424,1548.02173100,48215339.25595822,0 +1609797600000,31014.27000000,31474.78000000,30950.00000000,31332.05000000,1646.48413800,1609801199999,51480692.96027581,54923,906.95705200,28362489.62653594,0 +1609801200000,31332.05000000,32031.01000000,31150.00000000,31988.71000000,4193.64872800,1609804799999,132893993.10060339,86041,2344.14079000,74303486.15285786,0 +1609804800000,31989.75000000,32853.38000000,31989.74000000,32430.49000000,7707.64341000,1609808399999,250007916.90775211,127581,4569.48199000,148144849.10568232,0 +1609808400000,32430.69000000,32796.00000000,32224.25000000,32786.06000000,4246.96065000,1609811999999,138118302.36451834,83071,2295.49344300,74675015.21841346,0 +1609812000000,32786.05000000,32828.26000000,32221.10000000,32306.64000000,3163.43004400,1609815599999,102893990.21816806,65391,1571.90279200,51120318.98503503,0 +1609815600000,32306.64000000,32536.09000000,31130.86000000,31200.00000000,5695.04449600,1609819199999,181350412.23885364,112880,2751.73680400,87713825.89386314,0 +1609819200000,31190.04000000,31538.45000000,30418.00000000,30858.98000000,7229.48636600,1609822799999,224769397.84667815,157600,3122.03990900,97170832.72847822,0 +1609822800000,30858.98000000,31366.16000000,29900.00000000,30436.25000000,6366.97612400,1609826399999,195158786.10553854,159593,2694.13433100,82666054.53886334,0 +1609826400000,30436.26000000,31270.43000000,29900.00000000,31123.25000000,6611.21073500,1609829999999,202286248.33256154,127994,3659.29882200,111844754.48935623,0 +1609830000000,31123.25000000,31312.03000000,30759.47000000,30817.77000000,2811.38395300,1609833599999,87206069.28127892,71734,1279.15583000,39679285.44614070,0 +1609833600000,30817.78000000,31522.19000000,30817.78000000,31192.09000000,3237.12095700,1609837199999,101016094.16648097,88984,1691.74721800,52801113.11961794,0 +1609837200000,31192.16000000,31821.94000000,31157.90000000,31569.63000000,3935.59797900,1609840799999,124016625.84180410,91763,2077.94349900,65482399.52003036,0 +1609840800000,31569.63000000,31687.11000000,31088.33000000,31345.77000000,3174.76039600,1609844399999,99666137.72028313,81295,1624.61121700,51008190.21588990,0 +1609844400000,31347.73000000,31777.00000000,31284.15000000,31776.66000000,2908.12176800,1609847999999,91671919.09848990,72492,1608.73697700,50727750.80430447,0 +1609848000000,31776.66000000,32057.13000000,31563.84000000,31585.01000000,4161.55133400,1609851599999,132493096.80311255,94633,2278.18509000,72558530.75037737,0 +1609851600000,31585.00000000,31900.00000000,31416.27000000,31460.01000000,2523.02316500,1609855199999,79971740.01184837,64040,1248.02063100,39565656.12394609,0 +1609855200000,31460.11000000,32375.07000000,31111.78000000,32342.33000000,5942.10285400,1609858799999,188316129.32606876,137989,3384.55523600,107337665.44604894,0 +1609858800000,32343.61000000,32374.31000000,31929.41000000,32099.98000000,3616.59901600,1609862399999,116161069.22208343,98120,1862.74385500,59830250.35901147,0 +1609862400000,32099.97000000,32670.00000000,31763.23000000,32469.90000000,4926.17161600,1609865999999,159348378.63575512,114817,2517.10906500,81421262.10859769,0 +1609866000000,32469.90000000,32790.00000000,32254.18000000,32742.73000000,3599.64571800,1609869599999,116970729.32707121,82231,1693.39973600,55049206.49118736,0 +1609869600000,32742.73000000,33433.55000000,32650.03000000,33372.84000000,6647.00992100,1609873199999,219940103.11654606,129769,3830.69609100,126730979.20382337,0 +1609873200000,33372.83000000,34187.09000000,33098.82000000,33697.75000000,8659.33850300,1609876799999,292047625.83670093,179774,4641.04381700,156580281.19993935,0 +1609876800000,33693.80000000,34044.13000000,33318.00000000,33969.17000000,5800.65390700,1609880399999,195673767.39849565,106875,2778.60271100,93787060.66580112,0 +1609880400000,33968.66000000,33996.03000000,33471.94000000,33699.63000000,3682.07415100,1609883999999,124381906.41438341,74894,1702.31561300,57517127.96443939,0 +1609884000000,33699.63000000,34360.00000000,33695.60000000,34183.42000000,4616.40333400,1609887599999,157718468.59895870,113239,2717.78634600,92848224.48505438,0 +1609887600000,34183.43000000,34284.91000000,33650.00000000,33949.53000000,4787.68664100,1609891199999,162432229.83348370,90092,2091.01373200,70934458.77764801,0 +1609891200000,33949.53000000,34107.59000000,33288.00000000,33918.01000000,6106.35192400,1609894799999,205743581.04425707,99660,2516.25996100,84812005.34531709,0 +1609894800000,33918.01000000,34018.93000000,33513.05000000,33811.28000000,3237.65935400,1609898399999,109289337.46651398,62378,1475.38110700,49802826.13141871,0 +1609898400000,33811.28000000,34135.84000000,33768.32000000,33873.30000000,3252.25455600,1609901999999,110509015.75623268,60510,1626.42308100,55274032.44717988,0 +1609902000000,33873.30000000,34170.00000000,33652.00000000,34117.59000000,3183.08804500,1609905599999,107858643.06601506,79479,1672.00819000,56692634.90742621,0 +1609905600000,34116.76000000,35766.58000000,34109.83000000,35325.91000000,12735.41762700,1609909199999,444922768.19202013,211886,7910.03825500,275960969.40718472,0 +1609909200000,35326.82000000,35590.00000000,34510.00000000,34978.91000000,5595.78367600,1609912799999,196115940.87795285,106461,2891.38405100,101402148.66539782,0 +1609912800000,34977.27000000,35229.10000000,34782.44000000,35125.51000000,3923.02640300,1609916399999,137467483.49545430,82118,2054.11388500,71979294.60308102,0 +1609916400000,35125.49000000,35248.63000000,34350.00000000,34676.40000000,3898.73728400,1609919999999,135685914.15764905,90102,1874.10273300,65256486.63670632,0 +1609920000000,34666.80000000,34950.77000000,34015.00000000,34594.28000000,5094.75919600,1609923599999,176018487.58908296,104746,2360.74276200,81573834.44700668,0 +1609923600000,34596.08000000,34607.69000000,33357.90000000,33919.50000000,5753.91297000,1609927199999,195480943.58159614,116923,2559.39339000,86977436.94551326,0 +1609927200000,33919.50000000,34550.00000000,33834.61000000,34417.36000000,3851.57425900,1609930799999,132191268.15797724,81692,1875.01912600,64352205.86680140,0 +1609930800000,34417.37000000,35200.00000000,34342.87000000,34918.53000000,6362.80414200,1609934399999,221652511.71656262,135283,3225.56840900,112395840.12698986,0 +1609934400000,34918.54000000,35088.00000000,34415.61000000,34929.87000000,4569.51466500,1609937999999,158781299.83276104,111089,2339.06150000,81279110.68771631,0 +1609938000000,34929.87000000,35050.00000000,34300.00000000,34550.00000000,4296.27233100,1609941599999,148666291.75269622,101607,2028.18287800,70209071.06286720,0 +1609941600000,34549.99000000,34593.50000000,34052.42000000,34213.46000000,5728.36809500,1609945199999,196539271.47079065,118986,2687.80804700,92234560.97504688,0 +1609945200000,34213.58000000,34790.00000000,34150.00000000,34566.19000000,4050.15684800,1609948799999,139949954.84675728,84656,1858.52932300,64217961.06072499,0 +1609948800000,34566.18000000,35076.42000000,34372.92000000,34612.41000000,6142.98629100,1609952399999,213765663.67000848,119999,2805.93946000,97707179.71105734,0 +1609952400000,34615.98000000,35057.81000000,34562.00000000,34898.52000000,3410.29344000,1609955999999,118876311.09590797,78917,1651.60960300,57594103.95804292,0 +1609956000000,34898.52000000,35245.00000000,34894.22000000,35215.75000000,3704.00848100,1609959599999,130045690.18758426,79341,1818.20697700,63842688.84232041,0 +1609959600000,35215.75000000,35695.00000000,34652.60000000,34816.72000000,5619.20776800,1609963199999,198986931.55874261,127198,2772.62367000,98244633.93981346,0 +1609963200000,34818.95000000,36250.00000000,34280.00000000,36015.88000000,10922.41272400,1609966799999,384838155.99124447,211465,5441.59735300,192130710.80364409,0 +1609966800000,36015.16000000,36470.00000000,35650.00000000,35874.16000000,7481.32434800,1609970399999,269663315.99895945,143699,3530.87547100,127294676.33943071,0 +1609970400000,35869.97000000,36379.99000000,35700.92000000,35989.63000000,2717.84739300,1609973999999,98138204.77164020,84495,1258.44650600,45453405.34245312,0 +1609974000000,35989.64000000,36939.21000000,35949.12000000,36769.36000000,5501.43949000,1609977599999,200767262.24120768,99093,2819.59891400,102944651.96840851,0 +1609977600000,36769.36000000,37287.63000000,36422.71000000,37150.66000000,6259.57897800,1609981199999,231127540.88700173,126956,3276.04372500,121035260.46323515,0 +1609981200000,37150.66000000,37227.61000000,36615.83000000,36871.47000000,4542.03973000,1609984799999,167744153.75912638,92343,2188.22221600,80834008.77942776,0 +1609984800000,36871.47000000,37087.01000000,36456.00000000,36962.37000000,4112.98100900,1609988399999,151378625.95657551,75846,1862.59406500,68560321.70436183,0 +1609988400000,36962.37000000,37699.00000000,36926.53000000,37454.48000000,4747.64690900,1609991999999,177380063.69681458,102236,2489.39129500,93000819.42241232,0 +1609992000000,37452.62000000,37550.00000000,37056.12000000,37450.95000000,4099.95384100,1609995599999,153032050.67556983,93723,1967.84767900,73462310.91837377,0 +1609995600000,37450.95000000,37700.80000000,37100.77000000,37347.20000000,4337.60029100,1609999199999,162305184.42616053,88626,2189.33091400,81931971.65715822,0 +1609999200000,37347.20000000,37439.75000000,36710.00000000,37130.84000000,4095.35114000,1610002799999,151906540.45678327,102410,1749.23592800,64883857.26010562,0 +1610002800000,37130.85000000,37338.72000000,36720.00000000,36859.85000000,3782.27688600,1610006399999,140083390.80394544,91008,1623.22536900,60156275.89779950,0 +1610006400000,36863.04000000,37350.00000000,36300.00000000,37217.55000000,5254.61020900,1610009999999,193767393.70327787,105341,2307.40234300,85144391.17514270,0 +1610010000000,37217.55000000,37500.99000000,36905.00000000,37492.69000000,4407.04559400,1610013599999,163843785.85139342,73931,2244.72536700,83506486.68795209,0 +1610013600000,37492.70000000,37500.00000000,36920.00000000,37045.45000000,3236.82271800,1610017199999,120314344.26502907,73246,1456.95604700,54166648.01214179,0 +1610017200000,37045.45000000,37913.72000000,37038.97000000,37822.09000000,4315.49039700,1610020799999,161597115.72571475,93785,2370.94087800,88851600.37871656,0 +1610020800000,37825.64000000,38200.00000000,37518.00000000,37941.36000000,6363.35906900,1610024399999,241319458.86435367,126651,3103.65779600,117756120.27681301,0 +1610024400000,37941.37000000,38429.00000000,37900.00000000,38161.60000000,5364.34606600,1610027999999,205106242.97582551,109894,2583.94624000,98802410.05574995,0 +1610028000000,38161.60000000,38644.76000000,38079.02000000,38453.97000000,5516.63370100,1610031599999,211915217.15929497,127201,2553.52547300,98119133.15050093,0 +1610031600000,38450.51000000,38970.42000000,38062.75000000,38970.42000000,5401.36264100,1610035199999,208049947.52961345,108411,2618.40335000,100917730.45469424,0 +1610035200000,38970.41000000,39500.00000000,38921.49000000,39120.01000000,8054.61611400,1610038799999,315624646.46786094,152513,4140.22882300,162292200.88514323,0 +1610038800000,39120.01000000,39775.00000000,39101.36000000,39732.92000000,4853.72990500,1610042399999,191791634.74751861,118869,2607.77573300,103049642.73116991,0 +1610042400000,39732.92000000,40365.00000000,36500.00000000,38948.48000000,16920.67287100,1610045999999,656141657.34246253,352801,8352.78240100,324987958.80568612,0 +1610046000000,38907.58000000,39236.12000000,37493.52000000,39062.00000000,9539.54129200,1610049599999,367676058.94426181,178227,4568.73751400,176185972.74372717,0 +1610049600000,39061.99000000,39199.33000000,38352.88000000,39109.38000000,4364.13361200,1610053199999,169359110.49023060,97943,2132.34871100,82796137.61577405,0 +1610053200000,39111.34000000,39882.07000000,38908.11000000,39687.11000000,4533.61478900,1610056799999,178905952.02809147,98626,2237.72931700,88336681.65941423,0 +1610056800000,39687.11000000,39969.00000000,39150.00000000,39665.92000000,2855.62721000,1610060399999,113198084.48035602,94586,1413.94892000,56075175.26137254,0 +1610060400000,39666.00000000,39680.54000000,38541.38000000,39432.28000000,5866.66546500,1610063999999,229001742.14610960,129513,3016.10703200,117730123.85962437,0 +1610064000000,39432.48000000,39699.87000000,38793.23000000,38793.23000000,3387.17488900,1610067599999,133184446.37639539,92545,1535.35775800,60395220.31993304,0 +1610067600000,38793.24000000,39000.00000000,37800.00000000,38681.37000000,5775.38926500,1610071199999,222320078.64383120,118187,2477.23985000,95426783.89717878,0 +1610071200000,38681.38000000,38692.83000000,36500.00000000,37181.74000000,9364.24713500,1610074799999,350671968.12783984,184588,4041.02930300,151433666.58874171,0 +1610074800000,37181.74000000,38460.13000000,37068.40000000,38347.10000000,5036.74691800,1610078399999,191531646.49060035,107958,2279.00721300,86658079.51130932,0 +1610078400000,38347.11000000,38949.97000000,38155.61000000,38668.92000000,5126.66640200,1610081999999,198141885.51559744,92378,2021.91847700,78103095.87348774,0 +1610082000000,38668.92000000,38700.00000000,37895.00000000,37975.25000000,4384.15874300,1610085599999,168179267.74228120,78020,2012.30775600,77208465.01634949,0 +1610085600000,37980.53000000,38685.13000000,37563.92000000,38537.94000000,3989.76181500,1610089199999,152681589.95116749,85138,2001.85591200,76637372.69438687,0 +1610089200000,38538.99000000,39143.80000000,38280.16000000,38930.55000000,4177.46546000,1610092799999,161995711.17798650,91584,2176.84316200,84394619.63586086,0 +1610092800000,38929.56000000,38985.06000000,38414.70000000,38648.95000000,3277.73807000,1610096399999,126726366.48661977,77560,1404.58769600,54299270.78439706,0 +1610096400000,38648.96000000,39374.22000000,38222.00000000,39358.34000000,3995.80383300,1610099999999,155055524.72934390,92046,2098.95693900,81516294.63929747,0 +1610100000000,39358.99000000,41057.79000000,39220.00000000,40721.45000000,10298.22132600,1610103599999,413988645.03214855,192411,5906.62682800,237456218.24972363,0 +1610103600000,40722.71000000,41500.45000000,40345.39000000,41286.67000000,9286.54999900,1610107199999,381339340.10874931,173240,4686.87248800,192530894.29991795,0 +1610107200000,41286.67000000,41785.90000000,40857.37000000,41316.91000000,7590.27892700,1610110799999,314289402.99398151,161233,3735.09226700,154675080.03643654,0 +1610110800000,41318.03000000,41641.83000000,40700.00000000,41311.18000000,5331.45266600,1610114399999,219726996.61805144,102736,2445.95779600,100799684.72757314,0 +1610114400000,41313.24000000,41564.72000000,40970.22000000,41454.13000000,3918.18065100,1610117999999,161743369.58990013,85972,1841.48903700,76024773.29519918,0 +1610118000000,41454.13000000,41950.00000000,39777.00000000,40829.08000000,12863.95161700,1610121599999,525866974.42447445,235224,6229.06949100,254988062.90513028,0 +1610121600000,40829.07000000,41600.00000000,40359.67000000,41303.42000000,6293.05875900,1610125199999,258570569.68834122,125823,3214.27634400,132138012.65968989,0 +1610125200000,41303.41000000,41556.19000000,40888.88000000,41009.07000000,3675.20465500,1610128799999,151525080.93204277,89742,1723.71079700,71085850.10289584,0 +1610128800000,41009.08000000,41153.00000000,39800.00000000,39920.39000000,6673.74778200,1610132399999,269890839.41926600,137300,3102.08551100,125500203.58850049,0 +1610132400000,39920.67000000,40700.00000000,39900.35000000,40365.09000000,3881.07246400,1610135999999,156704308.94925451,89817,1932.09680700,78005779.48646475,0 +1610136000000,40365.09000000,40500.00000000,38888.00000000,39059.15000000,9598.07354700,1610139599999,379934389.42082304,202984,4299.54077700,170262552.06710307,0 +1610139600000,39062.88000000,40116.37000000,38652.00000000,40075.82000000,6171.36420800,1610143199999,243712568.15469437,130312,3138.47475100,124040437.03498383,0 +1610143200000,40075.82000000,40785.00000000,39740.95000000,40674.45000000,3008.04856300,1610146799999,121290642.62703400,94417,1635.90693200,66006341.65049416,0 +1610146800000,40672.02000000,40937.77000000,40465.76000000,40582.81000000,2685.59980500,1610150399999,109371595.53094099,84417,1359.85132400,55388686.91384988,0 +1610150400000,40586.96000000,40976.13000000,39980.27000000,40283.56000000,4382.25498300,1610153999999,177655228.53915624,103817,2141.19214700,86818834.61634393,0 +1610154000000,40286.09000000,40321.92000000,39710.00000000,40198.56000000,4543.73605600,1610157599999,181652860.51564185,96651,2692.28448800,107572784.19722243,0 +1610157600000,40196.51000000,40561.97000000,39500.00000000,39973.00000000,3032.04654100,1610161199999,121509932.94021643,82121,1435.85659600,57585613.15612918,0 +1610161200000,39973.00000000,40376.69000000,39709.61000000,40211.59000000,1917.78678000,1610164799999,76876333.83329589,63739,1008.92029900,40451251.06765757,0 +1610164800000,40209.91000000,40490.00000000,39805.03000000,40206.44000000,1976.48437300,1610168399999,79389762.67386835,61321,1017.80459500,40890105.65787203,0 +1610168400000,40206.43000000,40206.43000000,39154.48000000,39295.37000000,3025.04162500,1610171999999,120011440.79497736,89565,1302.19304900,51661984.99372342,0 +1610172000000,39293.41000000,39627.11000000,38888.00000000,38984.86000000,4352.60593700,1610175599999,170621480.12389127,110337,2071.80838400,81239150.25345556,0 +1610175600000,38978.46000000,39692.00000000,38720.00000000,39638.61000000,3109.88920900,1610179199999,122140688.02104703,82441,1509.83574400,59314191.04526394,0 +1610179200000,39639.21000000,40254.42000000,39290.86000000,40172.14000000,3081.99328900,1610182799999,122880599.47300186,90034,1584.08594000,63156447.14670606,0 +1610182800000,40167.54000000,40790.00000000,40164.03000000,40348.35000000,3653.41544700,1610186399999,147912608.83417118,104095,1909.70882100,77317388.90252549,0 +1610186400000,40348.36000000,40800.00000000,40105.51000000,40376.03000000,3130.35655800,1610189999999,126596569.76688394,79151,1730.68526900,70010726.83355768,0 +1610190000000,40376.03000000,41237.44000000,40256.73000000,40565.77000000,4682.99124700,1610193599999,191114775.55476880,116488,2464.97070500,100614480.25360964,0 +1610193600000,40565.77000000,40912.48000000,40410.01000000,40874.99000000,2732.20120400,1610197199999,111129222.70939649,70238,1257.34703500,51151916.78860784,0 +1610197200000,40874.99000000,41222.00000000,40679.10000000,41051.65000000,3818.65745000,1610200799999,156480184.02975569,101156,2072.39056900,84932555.31609088,0 +1610200800000,41051.66000000,41380.00000000,40700.00000000,40819.01000000,3867.78119200,1610204399999,158901525.79577861,88998,1822.97645100,74917120.30373793,0 +1610204400000,40819.01000000,40953.00000000,40200.00000000,40525.15000000,3364.43316400,1610207999999,136453850.42727688,84201,1463.88630700,59385675.97324527,0 +1610208000000,40525.16000000,40649.96000000,39869.00000000,39995.10000000,3942.09517300,1610211599999,158583517.38012921,101902,1796.07266100,72296374.56676844,0 +1610211600000,39995.09000000,40586.87000000,39985.45000000,40421.40000000,2205.65303100,1610215199999,89095373.96045112,61685,1020.70532900,41227222.26393196,0 +1610215200000,40421.40000000,40800.00000000,40417.36000000,40650.01000000,2109.16468000,1610218799999,85758517.67667532,52834,981.61560500,39911873.45195525,0 +1610218800000,40650.00000000,40880.00000000,40469.40000000,40665.91000000,1864.14249300,1610222399999,75910582.21499661,55768,872.92464400,35551251.89398528,0 +1610222400000,40665.91000000,40781.69000000,40050.00000000,40606.22000000,3330.65176500,1610225999999,134668657.46555306,86204,1391.85841300,56271189.87607031,0 +1610226000000,40610.35000000,40755.00000000,40483.17000000,40718.80000000,2433.80943000,1610229599999,98937085.11211261,74533,1240.05516100,50413543.31466746,0 +1610229600000,40718.81000000,40743.47000000,40120.00000000,40281.09000000,1973.25228700,1610233199999,79649919.17291718,63216,838.83016500,33852664.82209105,0 +1610233200000,40283.73000000,40415.01000000,39928.91000000,40088.22000000,3255.53576100,1610236799999,130848312.14581371,77661,1379.31353200,55446358.85648048,0 +1610236800000,40088.22000000,40736.76000000,40087.15000000,40581.48000000,2697.15194400,1610240399999,109155020.52709842,75975,1543.34335800,62462569.75783142,0 +1610240400000,40581.48000000,41350.00000000,40450.05000000,41141.56000000,4299.15250200,1610243999999,176409335.99983746,113141,2465.14578900,101163164.33525845,0 +1610244000000,41141.55000000,41145.21000000,40814.04000000,40945.28000000,2353.85274600,1610247599999,96509933.21078183,56820,1229.29344600,50403266.36756701,0 +1610247600000,40942.75000000,40991.20000000,40250.00000000,40316.64000000,2477.28851200,1610251199999,100527756.90546729,68596,1059.09531200,42978114.80649500,0 +1610251200000,40320.67000000,40602.29000000,40050.00000000,40342.46000000,2786.99680900,1610254799999,112516572.97811659,70179,1322.10144800,53381207.04924366,0 +1610254800000,40342.46000000,40665.23000000,40260.00000000,40451.84000000,2044.47910700,1610258399999,82813349.32221709,65702,1046.79288200,42400439.71816490,0 +1610258400000,40451.74000000,41073.26000000,40350.00000000,40904.50000000,2194.91295100,1610261999999,89548994.99182704,68652,1216.59895900,49648322.96046531,0 +1610262000000,40904.50000000,41066.62000000,40660.88000000,40978.57000000,2143.46227300,1610265599999,87593443.12207167,63012,1095.48870200,44771683.38289097,0 +1610265600000,40978.57000000,41033.00000000,40555.00000000,40798.29000000,2415.93133500,1610269199999,98459402.84023767,82913,1139.52099300,46443938.63195148,0 +1610269200000,40798.30000000,41060.00000000,40732.00000000,40768.48000000,2642.95874700,1610272799999,108097086.74610234,71415,1009.83609300,41306154.06184283,0 +1610272800000,40768.30000000,40850.00000000,40000.00000000,40429.20000000,5145.08674100,1610276399999,208070825.51832275,124172,2023.15898700,81826579.79037870,0 +1610276400000,40429.19000000,40429.56000000,38888.00000000,39181.76000000,8619.31148000,1610279999999,340819805.54859064,168941,3503.14974300,138513763.62529143,0 +1610280000000,39175.09000000,39777.77000000,38450.00000000,39538.57000000,6929.93683900,1610283599999,272139723.43016981,139744,3065.68497500,120437034.47289807,0 +1610283600000,39538.56000000,40126.00000000,39426.59000000,39800.90000000,3799.31660300,1610287199999,151386269.92626396,83841,1768.26710900,70464133.46351778,0 +1610287200000,39800.89000000,39847.26000000,39247.54000000,39431.59000000,3199.91402300,1610290799999,126603785.26782930,77289,1532.49150500,60635642.53692478,0 +1610290800000,39431.58000000,39934.76000000,39062.91000000,39671.81000000,3219.50221900,1610294399999,127407920.98714545,80993,1611.08045900,63765375.53128484,0 +1610294400000,39671.82000000,39757.55000000,39186.16000000,39234.29000000,2904.11345600,1610297999999,114524017.31947872,74323,1433.07218700,56520726.45947023,0 +1610298000000,39232.76000000,39388.20000000,37200.00000000,38571.86000000,12879.62069600,1610301599999,492818910.76509772,227163,5725.16387600,219203034.08690946,0 +1610301600000,38571.95000000,38778.00000000,37675.30000000,38109.68000000,6090.67144700,1610305199999,232738420.47658579,130643,2884.15394500,110233573.65162313,0 +1610305200000,38106.11000000,38536.65000000,37111.00000000,37456.77000000,4232.50255500,1610308799999,160518393.07414801,108389,1964.25189700,74603321.71036708,0 +1610308800000,37472.40000000,37793.50000000,35111.11000000,37718.88000000,18938.32980400,1610312399999,696190674.07068193,326195,9012.74587700,331599928.90450612,0 +1610312400000,37727.29000000,38288.17000000,37525.22000000,38055.30000000,7661.05957300,1610315999999,290757651.27777476,151403,3699.12353900,140413639.82740624,0 +1610316000000,38052.58000000,39000.00000000,37852.09000000,38428.23000000,4739.66852100,1610319599999,183000874.59129449,117221,2172.01141000,83817517.42345978,0 +1610319600000,38429.85000000,38692.79000000,37935.92000000,38150.02000000,3794.32362000,1610323199999,145426560.60992947,81328,1929.77218200,73983764.27227870,0 +1610323200000,38150.02000000,38264.74000000,36501.00000000,37192.10000000,7568.89448700,1610326799999,282133773.45771687,144478,4049.03584600,150713738.61959097,0 +1610326800000,37192.10000000,37824.00000000,36700.09000000,37237.66000000,4215.99647000,1610330399999,157446432.61687462,94031,2195.03542900,81988122.38789822,0 +1610330400000,37237.67000000,37411.00000000,36123.45000000,36363.94000000,6796.57306400,1610333999999,249081305.98087372,139390,3348.44308500,122747565.18522181,0 +1610334000000,36363.93000000,36697.97000000,33600.00000000,35438.23000000,18753.36008200,1610337599999,656910210.24701858,309583,8535.65073900,299259801.78589244,0 +1610337600000,35438.23000000,35999.95000000,34300.00000000,35544.00000000,9555.24165800,1610341199999,336898762.01782967,189085,4654.26643700,164101044.72751303,0 +1610341200000,35542.92000000,35924.19000000,34500.18000000,34904.73000000,7098.49713400,1610344799999,250190079.36343610,144659,3446.91546700,121480349.82035492,0 +1610344800000,34904.73000000,34904.73000000,32550.00000000,32872.63000000,15763.14870700,1610348399999,531586560.33268066,250357,7453.84691700,251729352.83788592,0 +1610348400000,32843.26000000,34739.98000000,32538.00000000,34375.34000000,12674.17128100,1610351999999,427189376.16139185,229890,6321.17451400,213052770.46448799,0 +1610352000000,34372.25000000,35919.86000000,34249.00000000,35430.00000000,6432.36153600,1610355599999,228082153.68068114,128300,3153.09414200,111822658.95592866,0 +1610355600000,35430.00000000,35788.06000000,34800.00000000,35765.98000000,5625.53336200,1610359199999,198581030.52970092,118919,2941.98205400,103896685.62059100,0 +1610359200000,35765.98000000,36360.00000000,35238.01000000,35367.60000000,6245.55977000,1610362799999,223540104.68064499,130986,3054.14129000,109337398.84658899,0 +1610362800000,35368.81000000,35471.00000000,34020.00000000,34198.56000000,7167.26663200,1610366399999,249203003.73990949,139115,3464.14733200,120441070.62626393,0 +1610366400000,34198.55000000,35110.00000000,33308.01000000,34275.64000000,9904.29308300,1610369999999,339316781.85416521,182659,4717.64529300,161750148.94016634,0 +1610370000000,34273.49000000,34450.00000000,32700.00000000,32813.71000000,12794.35086900,1610373599999,428304476.95230326,203687,5855.69846000,196140187.73780490,0 +1610373600000,32808.92000000,33770.11000000,31115.00000000,33299.12000000,23220.78262900,1610377199999,754881732.25507185,328807,12031.06505200,391224660.24487161,0 +1610377200000,33291.56000000,33679.74000000,31415.90000000,31580.00000000,11202.31877200,1610380799999,363657258.00175475,193457,5400.29706900,175495481.43452390,0 +1610380800000,31582.82000000,32250.00000000,30420.00000000,31777.19000000,20017.08514800,1610384399999,622713357.15522214,315778,9679.56884000,301507822.46929914,0 +1610384400000,31771.77000000,33585.17000000,30701.80000000,32839.87000000,16685.08091700,1610387999999,540672713.18962742,267122,7894.19718000,255803459.28721463,0 +1610388000000,32848.96000000,33300.00000000,32432.32000000,32562.10000000,7184.91161600,1610391599999,236361243.57798098,136615,3790.43763800,124760825.98588440,0 +1610391600000,32562.10000000,32737.40000000,31215.00000000,32254.62000000,7289.18436100,1610395199999,233109852.78429258,153369,3655.36676900,116909537.40918899,0 +1610395200000,32254.63000000,33465.48000000,31408.07000000,33409.80000000,8540.91364700,1610398799999,275831078.34556703,164613,4449.32930400,144024400.07326120,0 +1610398800000,33410.75000000,34466.00000000,33076.05000000,33968.09000000,9804.01167300,1610402399999,332651007.11123541,182255,5079.33151000,172360408.62941284,0 +1610402400000,33962.22000000,34892.74000000,33650.00000000,34359.07000000,5403.70363100,1610405999999,185939943.89889369,134198,2760.00313000,95015878.35947188,0 +1610406000000,34361.16000000,35638.55000000,34361.16000000,35404.47000000,9188.29941400,1610409599999,322597532.80513758,150098,4202.73269300,147552912.49598393,0 +1610409600000,35410.37000000,35547.19000000,34287.34000000,34929.98000000,6612.03638100,1610413199999,230807172.42598563,130795,3379.43976300,117972743.51971113,0 +1610413200000,34929.99000000,35457.00000000,33880.00000000,34289.30000000,5087.44237000,1610416799999,176294252.52681766,109515,2522.24534700,87440367.82923286,0 +1610416800000,34289.30000000,34623.87000000,33677.03000000,34399.99000000,4906.32950600,1610420399999,167606696.70177525,95087,2405.92866700,82152277.26820580,0 +1610420400000,34400.00000000,34998.94000000,34182.24000000,34984.96000000,3550.25392100,1610423999999,123057319.46903642,97055,1765.56306700,61222462.04918094,0 +1610424000000,34984.95000000,35326.42000000,34520.69000000,35287.67000000,4020.85751400,1610427599999,140466119.04782501,102515,2176.63926500,76091017.67610453,0 +1610427600000,35284.05000000,35889.00000000,34971.24000000,35882.68000000,5053.27595400,1610431199999,179047386.94075864,98637,2496.53901800,88471391.55265655,0 +1610431200000,35882.68000000,36348.00000000,35720.43000000,35993.93000000,6584.65752400,1610434799999,237381577.99770093,119516,3174.63784200,114447012.13568810,0 +1610434800000,35998.56000000,36628.00000000,35617.67000000,36413.60000000,6162.13428600,1610438399999,222671027.01391058,112864,3206.00270000,115838913.54437513,0 +1610438400000,36413.60000000,36499.98000000,35587.86000000,35773.24000000,5138.33768500,1610441999999,184973179.98963707,101155,2455.05249800,88358289.26096258,0 +1610442000000,35773.23000000,36150.67000000,35370.21000000,35925.76000000,3783.31674300,1610445599999,135595914.73912248,94262,1896.01760800,67969346.30640587,0 +1610445600000,35925.76000000,36150.71000000,34757.00000000,35085.77000000,6437.92750600,1610449199999,226777326.93409420,143080,3053.71030100,107556709.23632782,0 +1610449200000,35085.76000000,35841.01000000,35084.92000000,35410.99000000,4770.00225200,1610452799999,169178056.75008352,86550,2337.22183900,82904323.55164113,0 +1610452800000,35410.99000000,35688.82000000,34850.00000000,35014.75000000,4399.50968300,1610456399999,155060827.99845856,80069,1928.30580100,67994050.23179785,0 +1610456400000,35012.96000000,35399.70000000,33250.00000000,33291.06000000,10038.22509500,1610459999999,343775108.96552814,161263,4514.77093600,154774045.22594566,0 +1610460000000,33286.00000000,34064.25000000,32531.00000000,33426.47000000,11811.35594900,1610463599999,393694368.81381614,189971,5804.71964800,193539539.39731593,0 +1610463600000,33416.47000000,34285.71000000,33406.88000000,33829.40000000,6681.45394200,1610467199999,226445698.58107617,125863,3258.14012000,110431128.74404150,0 +1610467200000,33829.40000000,35000.00000000,33819.11000000,34998.90000000,5939.78549300,1610470799999,205218579.80101925,116044,2942.49110800,101675429.08899601,0 +1610470800000,34998.91000000,35289.67000000,34560.00000000,35012.53000000,5686.97075900,1610474399999,198481126.85605437,109149,2734.77272400,95495054.88031603,0 +1610474400000,35012.54000000,35550.00000000,34810.01000000,35040.78000000,4048.61314400,1610477999999,142422688.30968393,88596,2127.23197400,74898353.32965495,0 +1610478000000,35040.78000000,35040.79000000,34178.89000000,34685.11000000,3815.68001400,1610481599999,132021423.41342590,83351,1861.99156600,64445308.78823963,0 +1610481600000,34686.10000000,34702.22000000,33730.00000000,34287.95000000,5034.97631600,1610485199999,171715989.97505660,113254,2277.29556100,77663317.90100258,0 +1610485200000,34287.95000000,34877.28000000,33801.04000000,34719.03000000,4053.70405600,1610488799999,139157664.78739752,89121,1897.86131800,65144801.32431527,0 +1610488800000,34721.74000000,35051.02000000,33297.82000000,33743.18000000,3949.37391100,1610492399999,134851382.60556787,100050,1822.63714600,62329465.03725843,0 +1610492400000,33751.70000000,34138.84000000,33260.74000000,34051.24000000,6381.93199200,1610495999999,214601532.84028451,126383,3059.09437900,102917130.95067533,0 +1610496000000,34049.15000000,34049.15000000,32380.00000000,32526.50000000,9275.27934900,1610499599999,306711545.32513445,148548,4062.09829300,134315161.76339754,0 +1610499600000,32526.93000000,33450.00000000,32487.11000000,33124.06000000,6231.71754500,1610503199999,205116100.18111848,110099,3245.50759000,106870415.03421619,0 +1610503200000,33125.30000000,33551.55000000,32566.55000000,33035.21000000,5457.27537100,1610506799999,180313046.83527591,97536,2660.94865200,87969611.41297568,0 +1610506800000,33035.21000000,34375.51000000,32981.94000000,33818.50000000,6460.71206000,1610510399999,218830650.55841690,113365,3444.20441300,116647769.52002588,0 +1610510400000,33818.50000000,33910.00000000,33090.90000000,33183.88000000,3956.30306000,1610513999999,132358668.93296781,81338,2044.29727600,68390711.57166143,0 +1610514000000,33183.89000000,33521.96000000,32800.00000000,33321.75000000,3402.31753600,1610517599999,112789336.11601216,74376,1742.74091500,57788989.11279821,0 +1610517600000,33321.76000000,34212.87000000,33212.12000000,33780.68000000,4919.32255800,1610521199999,166187643.75213094,117208,2638.06412400,89138990.87013726,0 +1610521200000,33780.68000000,35180.67000000,33550.00000000,34986.90000000,6468.36582000,1610524799999,223311028.86666966,129033,3682.46407200,127112455.09418704,0 +1610524800000,34986.90000000,35063.59000000,34438.95000000,34519.19000000,5729.47622900,1610528399999,198712825.27925155,99962,2902.05152600,100651428.88811770,0 +1610528400000,34517.44000000,35107.47000000,34200.00000000,34343.62000000,4738.54255100,1610531999999,164370205.87977076,95053,2503.29439500,86897985.27927657,0 +1610532000000,34343.62000000,35066.64000000,34343.61000000,34923.00000000,4760.85293600,1610535599999,165510800.23160082,108046,2591.48805700,90117223.52421103,0 +1610535600000,34922.99000000,35250.00000000,34242.15000000,34385.48000000,5982.91999400,1610539199999,207938425.33048149,112096,2984.81656300,103839195.82840833,0 +1610539200000,34385.48000000,34512.00000000,34017.00000000,34266.52000000,3585.06836000,1610542799999,122779592.03370346,83868,1721.11541800,58947535.15158035,0 +1610542800000,34266.52000000,34787.24000000,34070.00000000,34575.50000000,3664.90875200,1610546399999,126544042.17738252,77740,1857.50048000,64127856.67519648,0 +1610546400000,34575.51000000,35100.00000000,34216.00000000,34260.70000000,5193.52343100,1610549999999,180511640.73806480,101193,2764.63798900,96139650.51317405,0 +1610550000000,34260.70000000,34850.00000000,34200.00000000,34673.90000000,3658.84742300,1610553599999,126337617.72096771,82393,1653.19455400,57111468.36665218,0 +1610553600000,34673.90000000,34930.00000000,34388.53000000,34783.14000000,2872.01120200,1610557199999,99506730.47508033,74086,1492.52540200,51735243.12673614,0 +1610557200000,34784.98000000,35000.00000000,34652.06000000,34821.48000000,2913.41367000,1610560799999,101556217.35535974,74641,1562.72521500,54486870.61688355,0 +1610560800000,34821.47000000,35901.00000000,34720.00000000,35719.36000000,6649.55774600,1610564399999,235681753.55135671,129664,3974.73777700,140771658.26275286,0 +1610564400000,35719.36000000,36188.00000000,35577.55000000,36002.25000000,5312.21893200,1610567999999,190903832.62323042,102457,2853.20823600,102536581.41240300,0 +1610568000000,36002.24000000,36450.01000000,35704.21000000,36222.07000000,5750.01446700,1610571599999,207658780.19389705,118490,3022.63204300,109210392.15708915,0 +1610571600000,36222.07000000,37427.00000000,36110.76000000,37299.49000000,7450.10466700,1610575199999,273979677.45851544,143713,3862.68716900,141965447.48793870,0 +1610575200000,37291.25000000,37850.00000000,36827.02000000,37203.87000000,6042.03307500,1610578799999,225941892.14352165,145104,2879.92450300,107679972.00628686,0 +1610578800000,37204.09000000,37584.73000000,37000.00000000,37371.38000000,4003.12820400,1610582399999,149324552.65971510,94280,1834.17364400,68420077.69580588,0 +1610582400000,37371.38000000,38172.22000000,37362.49000000,37762.76000000,5781.27225700,1610585999999,218752928.62470529,125605,2990.57619500,113155634.76711500,0 +1610586000000,37766.00000000,37786.62000000,37363.00000000,37451.13000000,3460.03872900,1610589599999,129846558.68611705,84578,1731.43001300,64982225.08561570,0 +1610589600000,37451.13000000,37729.62000000,37071.00000000,37439.51000000,4089.94901900,1610593199999,153050647.78838738,83406,2120.29126200,79352023.77541426,0 +1610593200000,37440.92000000,37505.00000000,37000.00000000,37045.13000000,2807.21378600,1610596799999,104630428.04802116,64054,1319.37063400,49197290.74693892,0 +1610596800000,37045.13000000,37513.58000000,36701.23000000,37504.00000000,3609.73947500,1610600399999,134038926.53281073,73363,1770.23586100,65747717.75811828,0 +1610600400000,37503.99000000,37800.00000000,37299.74000000,37529.11000000,3154.22565500,1610603999999,118466413.78490620,62636,1474.51124200,55389761.43659308,0 +1610604000000,37529.11000000,38100.00000000,37440.00000000,37837.21000000,3705.58775500,1610607599999,140121272.27361156,73541,1841.11684300,69653555.86756475,0 +1610607600000,37837.20000000,38596.92000000,37703.09000000,38198.34000000,5294.80219500,1610611199999,202886480.62769958,107847,2818.31905800,108002404.41945095,0 +1610611200000,38199.52000000,38786.10000000,38192.64000000,38370.01000000,3936.80962600,1610614799999,151677554.87020534,96897,2022.19214400,77922384.37908971,0 +1610614800000,38370.01000000,38464.13000000,37862.04000000,37938.11000000,3551.70614100,1610618399999,135677932.49465849,97054,1679.06573300,64158794.71563468,0 +1610618400000,37938.10000000,38490.49000000,37869.10000000,38487.37000000,3151.65894600,1610621999999,120334877.85367399,85937,1605.13964500,61296323.15928239,0 +1610622000000,38488.05000000,38622.60000000,38060.00000000,38365.86000000,3014.52281600,1610625599999,115498616.33443130,86329,1512.26065700,57954319.17474923,0 +1610625600000,38365.86000000,38427.11000000,37707.00000000,38257.96000000,3638.08289000,1610629199999,138468218.58411391,89563,1592.52655200,60638938.46213643,0 +1610629200000,38257.97000000,39000.00000000,38154.22000000,38977.66000000,5153.84186400,1610632799999,199046530.26004405,118766,2859.33666200,110460004.16808241,0 +1610632800000,38977.98000000,39762.70000000,38788.19000000,39577.53000000,9975.28896800,1610636399999,393260886.42277017,179862,4184.23250200,164786587.25686127,0 +1610636400000,39577.53000000,40100.00000000,39294.70000000,39546.01000000,7213.09520000,1610639999999,286463361.38157997,135839,3777.11504600,150098074.26838017,0 +1610640000000,39546.01000000,40000.00000000,39212.15000000,39286.44000000,5390.89406700,1610643599999,213864590.33463079,115830,2560.81063900,101642939.91878299,0 +1610643600000,39286.43000000,39880.00000000,39286.43000000,39429.81000000,3239.68862200,1610647199999,128303822.32233566,79395,1640.29223400,64970027.83975713,0 +1610647200000,39429.25000000,39620.00000000,39258.10000000,39344.79000000,3097.20586700,1610650799999,122149519.36041288,66716,1705.22407800,67269828.70074482,0 +1610650800000,39344.80000000,39919.11000000,39329.93000000,39876.98000000,3010.85527000,1610654399999,119401522.13828646,68361,1724.85875200,68414756.74563145,0 +1610654400000,39876.97000000,39935.10000000,39312.85000000,39312.86000000,2418.31260500,1610657999999,95797316.08700725,59910,1195.95415800,47393130.01671483,0 +1610658000000,39321.64000000,39585.00000000,38259.25000000,38780.47000000,7841.12752300,1610661599999,303612063.22343891,161031,3857.61463900,149326645.90329549,0 +1610661600000,38782.41000000,39135.17000000,38276.00000000,38988.62000000,3319.71530700,1610665199999,128584606.95524369,95798,1817.75951300,70424340.95387201,0 +1610665200000,38988.61000000,39330.92000000,38733.11000000,39144.50000000,3094.75483800,1610668799999,120891563.15599693,85148,1464.23303000,57204883.53017351,0 +1610668800000,39145.21000000,39747.76000000,39023.24000000,39452.89000000,3774.33060800,1610672399999,149015360.55895156,80654,1813.91433200,71628902.11570069,0 +1610672400000,39452.89000000,39640.00000000,39012.12000000,39175.74000000,2907.10256900,1610675999999,114488133.33169310,67692,1465.81359400,57732152.69891964,0 +1610676000000,39175.73000000,39479.65000000,38800.00000000,39267.76000000,2742.79781200,1610679599999,107593579.36330459,68144,1391.22041700,54571404.28794153,0 +1610679600000,39267.76000000,39349.58000000,38450.00000000,38700.00000000,3549.50605300,1610683199999,137776261.03885600,88794,1751.76455000,67996021.76730338,0 +1610683200000,38700.00000000,38853.09000000,38355.00000000,38425.83000000,2792.04410000,1610686799999,107691922.39219169,64920,1284.01221400,49531729.05208940,0 +1610686800000,38425.82000000,38849.99000000,37808.00000000,37808.90000000,3634.09561100,1610690399999,139288945.37497918,79527,1573.36491600,60341434.86561976,0 +1610690400000,37808.90000000,38098.00000000,37554.94000000,38043.27000000,4123.49372400,1610693999999,156128218.16931174,84166,2003.82903100,75876919.06561176,0 +1610694000000,38044.94000000,38483.82000000,37704.80000000,38473.08000000,3768.17724300,1610697599999,144144283.55090610,91002,1778.55687600,68036440.23177903,0 +1610697600000,38473.07000000,38700.00000000,38153.17000000,38280.20000000,3113.97292700,1610701199999,119590741.84337465,83493,1599.63734500,61442495.48300634,0 +1610701200000,38280.20000000,38718.02000000,38016.17000000,38679.36000000,3356.49966500,1610704799999,128916245.16560998,98018,1767.69312400,67911754.92516476,0 +1610704800000,38677.24000000,38780.00000000,38314.20000000,38441.89000000,2224.43167300,1610708399999,85760838.32974271,79176,1080.72769400,41668853.45542037,0 +1610708400000,38441.89000000,38573.84000000,37923.00000000,38108.88000000,3028.51037900,1610711999999,115607110.50743184,74800,1339.04572500,51120391.63829057,0 +1610712000000,38108.87000000,38194.04000000,37200.00000000,37770.63000000,6046.11154300,1610715599999,227455772.13223086,121039,2849.48956500,107207023.74592949,0 +1610715600000,37770.64000000,37888.88000000,37251.11000000,37683.94000000,4557.68570200,1610719199999,171183584.21508546,102938,2314.71682000,86899329.57806010,0 +1610719200000,37683.93000000,37786.74000000,36641.00000000,36939.49000000,6587.75278600,1610722799999,244381841.17567055,134091,3104.66865700,115187209.27424001,0 +1610722800000,36940.11000000,36999.00000000,35258.00000000,35610.72000000,11637.87487200,1610726399999,421633941.40375609,213976,5856.79331600,212284608.84987149,0 +1610726400000,35610.79000000,36400.00000000,34408.00000000,36151.09000000,16406.90733300,1610729999999,582299642.59025403,286255,7784.64484600,276322903.50920047,0 +1610730000000,36149.47000000,36154.75000000,35350.00000000,35947.31000000,7410.88799700,1610733599999,265150289.62610624,129446,3868.83773800,138492449.66717974,0 +1610733600000,35947.31000000,36433.51000000,34812.23000000,35421.55000000,7136.05529900,1610737199999,254109822.19889123,140400,3353.46969300,119635002.34573689,0 +1610737200000,35421.56000000,35928.69000000,35080.05000000,35217.26000000,4051.58872200,1610740799999,144088610.88903680,96389,2125.58060000,75623155.37661455,0 +1610740800000,35218.94000000,35746.24000000,34801.15000000,35605.70000000,5526.41908500,1610744399999,194574672.96517021,129250,2745.10018600,96708743.86237256,0 +1610744400000,35605.70000000,36431.75000000,35554.13000000,36234.05000000,4285.70884300,1610747999999,154450136.60542600,95751,2264.09355000,81652223.93966391,0 +1610748000000,36233.76000000,36888.00000000,35950.63000000,36600.00000000,3398.85578300,1610751599999,124165898.57420053,86901,1504.96071200,54949284.35710958,0 +1610751600000,36600.00000000,36888.00000000,36401.22000000,36742.22000000,2240.11058700,1610755199999,82093046.67945539,63979,1116.09871900,40903378.66703621,0 +1610755200000,36737.43000000,37428.05000000,36724.17000000,37159.51000000,4169.14680200,1610758799999,155099149.94530764,92947,2105.12438500,78296806.17964554,0 +1610758800000,37159.51000000,37669.00000000,36902.38000000,37005.86000000,4102.25927500,1610762399999,152987555.23908431,86508,2132.30229300,79520839.77875500,0 +1610762400000,37003.76000000,37227.16000000,36000.00000000,36224.51000000,4298.86633900,1610765999999,157512107.31706416,91436,2079.76311600,76218717.77990697,0 +1610766000000,36224.51000000,36738.43000000,35852.93000000,36532.92000000,3426.00050300,1610769599999,124459038.14279918,72075,1759.16558900,63946717.95769295,0 +1610769600000,36532.92000000,36700.00000000,36127.16000000,36574.54000000,2089.28208500,1610773199999,76042648.71232054,51540,1015.36945000,36958454.75759945,0 +1610773200000,36575.37000000,36646.43000000,35520.00000000,35854.37000000,4007.38958500,1610776799999,143871289.02981140,81056,1591.05363700,57154848.42616431,0 +1610776800000,35854.37000000,36377.54000000,35823.80000000,36112.42000000,3043.31762400,1610780399999,109946261.51207760,66774,1574.06351500,56865537.86022015,0 +1610780400000,36110.57000000,36959.61000000,36076.50000000,36574.86000000,3648.98805300,1610783999999,133766788.43464680,83125,1879.86506800,68904117.01046308,0 +1610784000000,36565.74000000,37500.00000000,36375.88000000,37464.30000000,4175.61823900,1610787599999,154678945.75854647,97079,2339.74381000,86717137.69031956,0 +1610787600000,37462.57000000,37666.66000000,37200.00000000,37448.77000000,3311.73910400,1610791199999,123784828.41268273,79132,1713.31390300,64050800.71606176,0 +1610791200000,37448.78000000,37950.00000000,37300.00000000,37410.66000000,4139.97880700,1610794799999,155846935.36351839,96097,1954.08802200,73580342.23717523,0 +1610794800000,37410.67000000,37838.23000000,37179.41000000,37680.00000000,2918.80035000,1610798399999,109448933.45229068,98264,1554.10738400,58282228.87935096,0 +1610798400000,37680.00000000,37886.00000000,36712.00000000,37357.15000000,4677.64126900,1610801999999,174585140.14249301,104964,2235.80570100,83495700.38012370,0 +1610802000000,37357.15000000,37681.99000000,37058.76000000,37143.51000000,3239.40068800,1610805599999,121224096.96841568,85259,1607.28483500,60162129.37671651,0 +1610805600000,37148.15000000,37356.26000000,36671.20000000,37232.19000000,3525.25555700,1610809199999,130637025.55110464,90082,1698.17492600,62944541.75797344,0 +1610809200000,37232.19000000,37680.00000000,36983.05000000,37461.99000000,3462.80146500,1610812799999,129390956.24186780,102346,1880.20838500,70287335.60187390,0 +1610812800000,37463.46000000,37713.94000000,36921.00000000,37231.41000000,3881.93071000,1610816399999,144688348.29183051,109582,1909.52655000,71195606.41501134,0 +1610816400000,37231.42000000,37299.99000000,36800.00000000,36860.97000000,2512.10090800,1610819999999,92955189.33630733,70046,1212.63659400,44877028.64481656,0 +1610820000000,36859.24000000,37165.90000000,36400.00000000,36484.95000000,2411.27980900,1610823599999,88899219.78650335,69608,1127.24738100,41590115.37101633,0 +1610823600000,36484.95000000,36621.30000000,36200.00000000,36376.39000000,3971.87462300,1610827199999,144665412.75847924,88832,2175.88336600,79277640.73861669,0 +1610827200000,36376.39000000,36800.00000000,36235.60000000,36711.16000000,3324.72866000,1610830799999,121573306.03804704,68829,1890.82510200,69120690.03196189,0 +1610830800000,36713.85000000,36717.00000000,35684.82000000,35924.44000000,5744.88333200,1610834399999,207415636.40443184,105481,2039.08095600,73669691.29040968,0 +1610834400000,35910.07000000,36194.53000000,35357.80000000,36121.12000000,3505.76699300,1610837999999,125545020.17201992,93386,1543.87125900,55326157.74147853,0 +1610838000000,36127.20000000,36480.00000000,35900.00000000,35994.98000000,2759.38072800,1610841599999,99816503.13763424,81915,1401.91850900,50716935.38798084,0 +1610841600000,35994.98000000,36472.72000000,35520.00000000,36396.42000000,3726.44550600,1610845199999,134085309.53711128,103985,1957.46251600,70454005.51107439,0 +1610845200000,36396.42000000,36727.26000000,36176.66000000,36715.63000000,2847.94888400,1610848799999,103572557.59243320,67933,1650.65446400,60049202.69903055,0 +1610848800000,36715.63000000,36744.05000000,36235.00000000,36419.68000000,1927.69473800,1610852399999,70310805.17210125,61836,910.16210200,33193187.34334062,0 +1610852400000,36419.68000000,36541.88000000,35978.00000000,36177.00000000,2021.33177900,1610855999999,73300672.04992026,60538,954.06954200,34599084.80359322,0 +1610856000000,36177.00000000,36382.38000000,35822.62000000,35847.46000000,2093.28909600,1610859599999,75569739.26789349,53616,861.15334000,31093493.92495674,0 +1610859600000,35848.25000000,36009.42000000,35475.14000000,35547.13000000,2900.40794500,1610863199999,103507618.16636456,68297,1292.56868700,46142665.28656242,0 +1610863200000,35547.12000000,35733.23000000,35034.96000000,35390.80000000,4077.70544400,1610866799999,144053986.81128709,84419,1762.60951800,62293524.58439225,0 +1610866800000,35390.80000000,35530.00000000,34518.04000000,34760.90000000,5014.08248500,1610870399999,175408790.13568946,99290,2124.19679000,74357513.18585806,0 +1610870400000,34760.91000000,34834.41000000,34300.00000000,34732.83000000,5641.05021700,1610873999999,194956387.86675457,112432,2733.28975600,94489103.56729384,0 +1610874000000,34732.08000000,35188.00000000,34000.00000000,34176.77000000,5570.23129700,1610877599999,192698146.55056793,108778,2619.46937500,90658661.30071936,0 +1610877600000,34176.78000000,35147.84000000,33850.00000000,34818.00000000,5718.02904900,1610881199999,197387959.52060657,106160,3011.33603700,104059630.69026929,0 +1610881200000,34816.26000000,35400.00000000,34727.85000000,35267.17000000,3861.65969400,1610884799999,135399244.37169309,79936,1736.68097000,60903773.65504362,0 +1610884800000,35270.00000000,35545.34000000,34695.46000000,35124.69000000,3962.00267900,1610888399999,139632993.37884855,79678,1847.63214800,65131007.70656315,0 +1610888400000,35124.07000000,35500.00000000,34786.76000000,34841.83000000,2919.10106400,1610891999999,102737842.55470297,71419,1428.30617900,50278587.30064365,0 +1610892000000,34841.82000000,35243.64000000,34666.00000000,34750.02000000,2849.00196600,1610895599999,99574705.54992799,70822,1445.98812800,50544082.45977569,0 +1610895600000,34750.02000000,35973.89000000,34750.01000000,35728.47000000,4341.23544900,1610899199999,154518610.30102425,98607,2360.22110200,83998148.50677575,0 +1610899200000,35728.47000000,36166.47000000,35589.35000000,35910.07000000,3578.88895100,1610902799999,128512404.66708661,85740,1947.54828200,69937489.71982178,0 +1610902800000,35914.98000000,36123.14000000,35603.01000000,35837.22000000,2191.92330500,1610906399999,78599736.12711191,60258,1152.32208700,41321755.02532894,0 +1610906400000,35837.22000000,35920.63000000,35625.40000000,35678.67000000,1484.55684200,1610909999999,53084102.72106789,47902,806.41096800,28836727.69393613,0 +1610910000000,35676.58000000,36000.00000000,35514.99000000,35633.91000000,2043.03718600,1610913599999,73207372.57995978,57800,1072.67926100,38437112.60940556,0 +1610913600000,35633.90000000,36099.00000000,35559.84000000,36072.99000000,1917.72224700,1610917199999,68718611.05380223,54608,997.57090700,35751159.67099339,0 +1610917200000,36073.88000000,36852.50000000,36073.87000000,36542.96000000,3878.40282400,1610920799999,141647926.97089063,90548,2174.17282800,79388133.99001614,0 +1610920800000,36542.97000000,36700.00000000,36000.39000000,36181.16000000,2247.45304400,1610924399999,81931988.77622475,68903,1152.19484600,42011748.13054775,0 +1610924400000,36181.16000000,36417.51000000,35506.00000000,35828.61000000,3344.52569300,1610927999999,120685528.51759374,67137,1514.93872800,54718833.48528231,0 +1610928000000,35824.99000000,36016.70000000,35551.81000000,35964.20000000,3323.90113900,1610931599999,119159712.14498531,63319,1606.90513300,57614951.95602508,0 +1610931600000,35964.19000000,36180.00000000,35605.22000000,36125.44000000,2560.95556400,1610935199999,91877670.63162021,57197,1322.13209400,47415054.10178436,0 +1610935200000,36125.43000000,36208.00000000,35681.96000000,35764.66000000,2306.02756600,1610938799999,82867811.65103600,60994,1157.29079100,41596065.11737584,0 +1610938800000,35764.60000000,35847.18000000,34842.99000000,35106.25000000,4674.31695400,1610942399999,164878873.04280485,93982,1544.60107200,54470419.47523170,0 +1610942400000,35108.27000000,35313.90000000,34908.80000000,35132.11000000,1922.62447200,1610945999999,67496976.81593762,53315,871.84668300,30612537.81032757,0 +1610946000000,35132.11000000,35477.06000000,34800.00000000,35344.50000000,2494.06315100,1610949599999,87599615.70178966,57881,1148.89187000,40354532.34420341,0 +1610949600000,35344.50000000,35464.04000000,35072.69000000,35195.45000000,1597.76843600,1610953199999,56300358.51333952,45158,759.07017700,26751405.12726972,0 +1610953200000,35195.44000000,36278.68000000,35160.30000000,36104.61000000,3917.13156200,1610956799999,140822622.63867726,86613,1950.34315700,70090823.84607675,0 +1610956800000,36100.55000000,36450.00000000,36073.13000000,36233.19000000,2494.36415100,1610960399999,90400248.17710538,66340,1332.56138600,48287025.73379767,0 +1610960400000,36233.19000000,36650.00000000,36204.15000000,36574.61000000,3077.32729200,1610963999999,112164683.74681694,73640,1632.27271800,59494150.02425426,0 +1610964000000,36574.63000000,36633.50000000,36123.53000000,36216.63000000,2686.93417000,1610967599999,97510153.01232437,69740,1357.39864400,49264228.83971603,0 +1610967600000,36216.63000000,36537.00000000,35771.60000000,36442.08000000,3460.54194700,1610971199999,124848234.70607834,79307,1736.56814900,62641263.75389621,0 +1610971200000,36443.91000000,37469.83000000,36385.00000000,36981.40000000,8243.84424300,1610974799999,305775908.81808934,144888,4863.24389000,180322426.51417220,0 +1610974800000,36981.40000000,37050.00000000,36705.00000000,36766.78000000,4234.61810100,1610978399999,156297533.65120046,82229,2534.62857800,93612565.99943434,0 +1610978400000,36764.94000000,36985.00000000,36047.89000000,36449.71000000,3586.75998600,1610981999999,130920505.91913583,84095,1736.07612800,63349921.48594530,0 +1610982000000,36449.71000000,36600.78000000,36122.00000000,36405.98000000,2041.28462400,1610985599999,74258390.05881229,77583,980.46394600,35670262.49537307,0 +1610985600000,36405.99000000,36565.00000000,35831.88000000,36184.31000000,2789.03579100,1610989199999,100823529.48199534,91494,1375.94347200,49748332.70050728,0 +1610989200000,36184.31000000,36300.00000000,35400.00000000,35675.28000000,3638.79865400,1610992799999,129994205.62275856,91631,1696.62878400,60627024.14361091,0 +1610992800000,35675.29000000,35889.99000000,35532.32000000,35755.62000000,2134.48796900,1610996399999,76289046.58898849,68693,1035.27786600,37005168.86009770,0 +1610996400000,35755.62000000,36065.00000000,35695.70000000,35956.14000000,2040.50755300,1610999999999,73280693.30042997,57131,946.07607200,33978503.11621751,0 +1611000000000,35951.83000000,36400.00000000,35755.01000000,36102.79000000,2370.49412700,1611003599999,85609502.56222758,54395,1332.89774200,48150352.06874821,0 +1611003600000,36102.79000000,36296.90000000,35960.00000000,36198.01000000,1386.55487400,1611007199999,50126918.85569934,42491,664.89071200,24040239.99928700,0 +1611007200000,36198.01000000,36529.00000000,36154.65000000,36470.06000000,1403.43502700,1611010799999,51014701.39896737,46332,820.93816000,29849178.95171802,0 +1611010800000,36472.46000000,36777.77000000,36271.18000000,36631.27000000,2312.34139700,1611014399999,84525363.48357894,59318,1214.55882400,44400752.70145878,0 +1611014400000,36622.46000000,36916.66000000,36364.43000000,36676.89000000,2733.81033300,1611017999999,100190042.59582775,70989,1346.26085000,49334299.94502281,0 +1611018000000,36676.89000000,37280.00000000,36644.70000000,36922.44000000,6704.65912700,1611021599999,247774070.39497733,129108,3846.57205200,142188203.13944053,0 +1611021600000,36922.44000000,37014.19000000,36579.94000000,36804.11000000,3367.18661300,1611025199999,123941502.60160400,78744,1744.12188300,64193813.99868738,0 +1611025200000,36804.10000000,36846.06000000,36416.52000000,36465.30000000,2526.73244200,1611028799999,92552256.07429785,61311,1298.45559000,47563786.05688627,0 +1611028800000,36468.31000000,36648.92000000,36233.00000000,36284.71000000,2229.69432800,1611032399999,81295530.87574036,51230,1010.41437500,36848451.16460083,0 +1611032400000,36284.71000000,36538.46000000,36018.09000000,36251.18000000,2305.60782700,1611035999999,83784612.18185242,56140,934.13984000,33946658.77044831,0 +1611036000000,36249.37000000,36753.31000000,36002.01000000,36599.55000000,2938.25636700,1611039599999,107273641.64034685,64862,1415.02029200,51681856.65860550,0 +1611039600000,36599.55000000,37233.87000000,36470.62000000,37168.82000000,3825.66775700,1611043199999,140889599.49682016,92154,1964.40245700,72372674.30573714,0 +1611043200000,37167.92000000,37535.27000000,36897.07000000,37197.72000000,5687.62709000,1611046799999,211869865.95048485,107619,3034.97064100,113065745.48353333,0 +1611046800000,37197.71000000,37448.41000000,37000.08000000,37040.04000000,3275.36236000,1611050399999,122030475.06305307,71236,1724.20623400,64244428.73524604,0 +1611050400000,37040.05000000,37299.51000000,36750.00000000,37110.60000000,3322.07511800,1611053999999,123049352.32166823,69834,1328.51085100,49207075.68565862,0 +1611054000000,37110.60000000,37269.00000000,36811.83000000,37266.49000000,2885.73090900,1611057599999,106901741.58528574,77599,1402.45483700,51962298.25692514,0 +1611057600000,37263.73000000,37449.00000000,36610.00000000,36782.17000000,4108.41496600,1611061199999,152278198.14634400,92100,1730.49855000,64163858.18672526,0 +1611061200000,36782.16000000,37146.87000000,36782.16000000,37082.52000000,2645.54649100,1611064799999,97792760.65281740,67581,1324.55363700,48961142.08308718,0 +1611064800000,37082.52000000,37263.49000000,36913.62000000,36992.33000000,2406.25041700,1611068399999,89277069.58574515,64703,1069.51813800,39705332.19867843,0 +1611068400000,36992.32000000,37350.00000000,36776.50000000,37329.40000000,2806.43485300,1611071999999,104106538.97294504,66943,1404.23361500,52115774.51995613,0 +1611072000000,37329.40000000,37850.00000000,37203.97000000,37366.10000000,5147.02015600,1611075599999,193314306.96778085,126543,2869.30365200,107761235.79806878,0 +1611075600000,37366.09000000,37522.80000000,37015.00000000,37162.40000000,2476.82564300,1611079199999,92216774.40900947,78320,1214.50495400,45227795.62240386,0 +1611079200000,37162.40000000,37162.40000000,36500.00000000,36500.00000000,3818.66238300,1611082799999,140689545.76037489,118795,1692.17083000,62377256.77651533,0 +1611082800000,36500.00000000,36800.00000000,36052.04000000,36279.82000000,4162.25155900,1611086399999,151554221.32889008,114988,1957.58787000,71291448.04910801,0 +1611086400000,36281.66000000,36596.17000000,36100.00000000,36436.26000000,2878.69976000,1611089999999,104712135.13559804,79424,1352.60632600,49213231.43077645,0 +1611090000000,36436.26000000,36777.88000000,36381.91000000,36452.22000000,2721.21472400,1611093599999,99532432.86427794,71077,1212.26831800,44337485.23711049,0 +1611093600000,36452.22000000,36769.23000000,36325.63000000,36632.82000000,1252.40187500,1611097199999,45792766.57334137,51288,625.76904900,22887232.37383150,0 +1611097200000,36632.82000000,36722.71000000,35844.06000000,35891.49000000,3385.17467100,1611100799999,122529058.16513122,76783,1202.13677900,43584625.37491600,0 +1611100800000,35901.94000000,36350.00000000,35610.17000000,36314.04000000,3376.90801800,1611104399999,121611981.70825795,76065,1698.15315300,61156956.22671120,0 +1611104400000,36313.94000000,36415.31000000,36000.00000000,36105.27000000,2185.60381300,1611107999999,79107661.42393211,70193,1077.48775100,39004567.83224275,0 +1611108000000,36105.27000000,36125.86000000,35708.08000000,36080.90000000,2649.68717500,1611111599999,95147817.46514127,69392,1282.47330300,46066789.90461259,0 +1611111600000,36080.90000000,36100.00000000,35000.00000000,35062.49000000,5563.39287800,1611115199999,197187021.19787029,124477,2272.89640800,80605174.15458207,0 +1611115200000,35062.49000000,35440.00000000,34737.00000000,35251.36000000,4580.64004600,1611118799999,160879898.10346283,108135,2104.06392600,73956001.12289178,0 +1611118800000,35252.03000000,35500.01000000,35192.87000000,35477.18000000,2705.03601800,1611122399999,95634099.26116358,71627,1199.81019100,42430522.42932393,0 +1611122400000,35477.18000000,35909.95000000,35133.68000000,35262.93000000,3973.87904500,1611125999999,140868658.81284165,86408,1785.62381700,63336669.13924939,0 +1611126000000,35262.92000000,35884.79000000,35200.00000000,35677.14000000,2748.94867800,1611129599999,97892499.61234258,79497,1386.64800500,49379610.93213742,0 +1611129600000,35672.86000000,35939.12000000,35350.46000000,35475.45000000,2722.80538600,1611133199999,96980265.92600699,86204,1293.43909300,46069195.51314113,0 +1611133200000,35475.46000000,35566.80000000,34500.00000000,34801.83000000,5641.77378600,1611136799999,197316362.11893461,120493,2607.87075100,91216916.63868137,0 +1611136800000,34801.46000000,34979.59000000,34345.11000000,34721.51000000,5228.27214100,1611140399999,181383448.50979843,128848,2720.33736200,94408050.83412549,0 +1611140400000,34721.50000000,34867.99000000,34000.00000000,34426.17000000,5516.47424200,1611143999999,189555636.68479760,139619,2482.03951200,85314827.40123212,0 +1611144000000,34426.17000000,34797.73000000,34020.00000000,34717.66000000,4980.58747900,1611147599999,171988282.93936077,121366,2574.47427300,88944358.51221264,0 +1611147600000,34717.66000000,34983.77000000,34210.00000000,34958.56000000,3863.83288600,1611151199999,133781075.37984111,104474,1813.88878900,62833859.54875768,0 +1611151200000,34958.56000000,35142.18000000,34800.14000000,34873.96000000,3575.82907500,1611154799999,125026667.28062037,84043,1635.95581900,57189524.59525745,0 +1611154800000,34875.87000000,35049.96000000,34067.16000000,34192.17000000,3689.93592300,1611158399999,127624139.98722324,89817,1638.37368800,56695477.13228186,0 +1611158400000,34193.11000000,34733.00000000,33400.00000000,34693.65000000,9164.62629900,1611161999999,312303193.17566532,175841,4045.27824700,137920325.77367834,0 +1611162000000,34694.65000000,35100.01000000,34558.25000000,34849.99000000,3580.94135600,1611165599999,124627004.47361672,89168,1909.51171400,66478899.60394461,0 +1611165600000,34843.52000000,35266.72000000,34765.24000000,35250.61000000,2311.69306900,1611169199999,80828379.66206621,73056,1216.49186900,42547920.77330436,0 +1611169200000,35250.39000000,35311.00000000,34851.23000000,35197.12000000,2620.95376500,1611172799999,92029638.11022864,67359,1406.95759100,49407891.56166645,0 +1611172800000,35197.12000000,35318.39000000,34734.97000000,34957.15000000,1987.73025600,1611176399999,69621129.92197612,74431,955.36540500,33465910.76386969,0 +1611176400000,34957.15000000,35110.82000000,34482.75000000,34892.89000000,2130.64840700,1611179999999,74053301.33840012,61510,1075.47654700,37388219.82147555,0 +1611180000000,34892.90000000,35100.00000000,34748.09000000,34954.86000000,1119.62218200,1611183599999,39153067.93844396,47851,568.32500200,19877160.96407081,0 +1611183600000,34955.94000000,35670.00000000,34798.39000000,35468.23000000,3448.60099500,1611187199999,122119862.48878375,84665,1795.69186100,63595137.25701945,0 +1611187200000,35468.23000000,35600.00000000,35077.35000000,35293.21000000,2017.77200300,1611190799999,71244148.51224691,62415,1021.63117800,36087350.09733232,0 +1611190800000,35293.21000000,35384.20000000,34622.50000000,34784.69000000,2831.35322600,1611194399999,98887264.92537901,74678,1262.77622800,44091985.16186371,0 +1611194400000,34784.69000000,34831.42000000,34364.75000000,34560.12000000,3087.99981800,1611197999999,106807489.54912612,69030,1554.61918500,53775405.41995120,0 +1611198000000,34560.11000000,34821.60000000,34230.76000000,34571.09000000,3058.58303700,1611201599999,105595669.67910814,70428,1473.75077400,50892519.05477928,0 +1611201600000,34572.42000000,34923.07000000,34160.05000000,34246.48000000,3255.93055700,1611205199999,112476080.02982139,76518,1539.42868300,53190056.10502087,0 +1611205200000,34247.92000000,34619.66000000,33971.41000000,34562.70000000,3522.77822700,1611208799999,120817978.88212674,92193,1599.65898900,54904740.12478541,0 +1611208800000,34562.69000000,34805.16000000,34500.36000000,34661.83000000,2361.03375100,1611212399999,81807739.72141545,75006,1199.46049800,41562588.31422136,0 +1611212400000,34661.83000000,35019.01000000,34550.00000000,34624.27000000,2505.29344900,1611215999999,87147969.00878534,63295,1228.59391200,42741599.36104081,0 +1611216000000,34624.27000000,34681.73000000,33195.00000000,33239.00000000,7574.11231900,1611219599999,256464070.98831367,156722,3171.30735400,107516947.59598245,0 +1611219600000,33237.74000000,33500.00000000,32540.00000000,32878.33000000,10141.56880600,1611223199999,334459993.10114840,203209,4561.51833100,150456181.95340321,0 +1611223200000,32880.08000000,33067.87000000,32009.68000000,32826.62000000,7957.20654900,1611226799999,259185487.08244076,168066,3798.64234100,123773284.11724001,0 +1611226800000,32826.63000000,33000.00000000,32153.16000000,32208.62000000,6499.19839800,1611230399999,211753312.32663698,125838,3204.18771100,104419502.87409633,0 +1611230400000,32206.89000000,32693.16000000,31300.00000000,32475.34000000,10991.83004600,1611233999999,351602776.61161555,210145,4995.90744800,159923479.15384346,0 +1611234000000,32474.48000000,32784.31000000,32200.00000000,32304.44000000,4837.42355100,1611237599999,157188043.77176227,111987,2473.43810100,80383165.63062022,0 +1611237600000,32306.39000000,32450.00000000,31037.00000000,31180.19000000,10854.17362800,1611241199999,343341285.95402469,195527,5307.01795700,167967184.25189701,0 +1611241200000,31181.74000000,32047.40000000,31060.81000000,31384.09000000,7812.91775300,1611244799999,246568404.98001047,160355,3964.48055700,125218094.59949896,0 +1611244800000,31384.19000000,32210.38000000,31050.00000000,31083.50000000,7922.45751300,1611248399999,251118366.34818641,152038,3639.73915500,115545814.09881622,0 +1611248400000,31084.98000000,32006.43000000,31038.51000000,31912.38000000,4587.71659700,1611251999999,144988372.99906577,108210,2374.03657900,75112391.40357297,0 +1611252000000,31912.37000000,32101.00000000,31432.64000000,31742.68000000,3560.62585300,1611255599999,113025685.87936468,83931,1872.01061300,59456743.65825674,0 +1611255600000,31744.26000000,32751.24000000,31600.00000000,32468.66000000,5995.57574200,1611259199999,194294216.97572609,130883,2972.32121000,96300929.09307729,0 +1611259200000,32468.66000000,32550.00000000,31862.69000000,31883.01000000,4446.73367500,1611262799999,143406305.30422066,92561,1814.44124300,58508525.20428002,0 +1611262800000,31880.90000000,32131.52000000,31200.00000000,31229.71000000,4096.66507900,1611266399999,129806970.95052316,79250,1825.16546300,57897971.72882060,0 +1611266400000,31224.71000000,31249.02000000,30071.00000000,30913.18000000,9566.50417200,1611269999999,293192620.80555366,198964,3536.58837400,108389286.36409143,0 +1611270000000,30913.17000000,31571.88000000,30579.48000000,30850.13000000,5518.62290900,1611273599999,171603332.11762323,120256,2865.48856400,89124771.25270078,0 +1611273600000,30851.99000000,30863.98000000,29223.03000000,29528.31000000,16556.09618500,1611277199999,494734301.86225019,257851,7490.34896700,223742028.44830141,0 +1611277200000,29524.48000000,30436.26000000,28850.00000000,30068.29000000,17679.88047700,1611280799999,523137082.67972788,257625,8588.39663800,254114235.14214405,0 +1611280800000,30068.29000000,30849.98000000,29781.20000000,30710.91000000,8224.70597000,1611284399999,250104284.40121874,153325,4154.34427500,126324892.96417764,0 +1611284400000,30710.92000000,31029.79000000,30282.97000000,30943.40000000,4353.71025500,1611287999999,133375842.77548401,94621,2257.37116100,69178850.32926977,0 +1611288000000,30943.40000000,31414.00000000,30753.27000000,30919.60000000,5349.74113100,1611291599999,166190726.32666313,103652,2433.86826000,75616126.17399213,0 +1611291600000,30919.59000000,31924.44000000,30711.66000000,31800.93000000,5843.71142700,1611295199999,184028420.51132878,97216,2954.25431800,92987757.57327702,0 +1611295200000,31814.81000000,32152.90000000,31500.26000000,31542.75000000,5707.04325300,1611298799999,181417832.95727041,101619,2327.26440200,74020366.79427423,0 +1611298800000,31542.60000000,31878.20000000,30615.22000000,30842.45000000,5871.33017100,1611302399999,182994945.92512728,113549,2627.26092500,81919904.41999024,0 +1611302400000,30846.59000000,31636.99000000,30500.00000000,31526.30000000,5959.97399200,1611305999999,184580319.09360101,148350,3123.54124000,96718684.26877291,0 +1611306000000,31526.31000000,31799.98000000,31258.94000000,31414.59000000,5197.32705000,1611309599999,163847968.57535826,105289,2724.63723100,85916580.20164027,0 +1611309600000,31412.74000000,31766.01000000,31052.44000000,31386.37000000,4556.22050700,1611313199999,142759014.01477801,96070,2228.28144400,69812436.52517869,0 +1611313200000,31386.37000000,31997.00000000,31375.49000000,31710.88000000,6197.72471400,1611316799999,196955755.04950245,103543,3508.78822400,111526297.53345808,0 +1611316800000,31712.09000000,31995.00000000,31286.00000000,31550.00000000,5176.96354800,1611320399999,163881684.27671369,95270,2748.62371400,87060695.91900743,0 +1611320400000,31550.00000000,32322.56000000,31334.02000000,32141.80000000,6045.55706900,1611323999999,193650798.12282147,111611,2975.38234300,95276300.41957483,0 +1611324000000,32141.80000000,32537.67000000,32132.59000000,32516.74000000,5791.99130300,1611327599999,187566596.45637194,112187,2664.69415800,86304086.50129477,0 +1611327600000,32516.74000000,32767.44000000,32265.66000000,32458.42000000,4727.18649900,1611331199999,153659972.96999938,111537,2339.77124900,76061260.77114846,0 +1611331200000,32462.79000000,32626.00000000,31955.67000000,32377.56000000,4665.55497100,1611334799999,150975577.63273878,93129,2398.24543500,77595982.77464377,0 +1611334800000,32377.56000000,32500.00000000,32070.70000000,32329.25000000,2777.80265900,1611338399999,89671638.37049859,61647,1315.92704100,42485374.92433076,0 +1611338400000,32329.25000000,33322.00000000,32185.44000000,33277.32000000,5488.66573200,1611341999999,179938517.21390338,103780,3001.64580800,98517818.42696697,0 +1611342000000,33275.67000000,33655.79000000,33098.86000000,33589.52000000,4699.14183300,1611345599999,156981142.73572678,97136,2220.53795100,74185015.25059314,0 +1611345600000,33589.52000000,33826.53000000,33320.22000000,33503.20000000,3725.03294500,1611349199999,125120103.06772533,99864,1687.72335500,56695170.71714831,0 +1611349200000,33501.36000000,33668.88000000,33192.13000000,33290.01000000,2586.47012100,1611352799999,86484959.34566229,57890,1214.64288800,40615109.04973645,0 +1611352800000,33290.01000000,33606.16000000,32760.00000000,32835.29000000,2591.01826000,1611356399999,85932081.85096645,63029,1339.60618300,44407872.57019493,0 +1611356400000,32835.29000000,33173.01000000,32580.00000000,32945.17000000,3198.83397700,1611359999999,105306305.80683445,68020,1825.03124500,60078722.79955450,0 +1611360000000,32950.00000000,32974.89000000,32400.00000000,32702.18000000,3359.61255400,1611363599999,109495931.14066298,86521,1596.99420000,52048849.37696274,0 +1611363600000,32702.18000000,32935.08000000,32237.39000000,32706.76000000,3198.93051300,1611367199999,104362190.54273436,75853,1719.87681600,56131036.23762754,0 +1611367200000,32706.77000000,32860.00000000,32053.33000000,32256.17000000,3543.41263800,1611370799999,114730754.32306910,73178,2009.01377100,65064337.26398425,0 +1611370800000,32256.17000000,32612.00000000,32200.00000000,32365.01000000,2109.56632500,1611374399999,68388995.24540523,50704,1124.35221300,36451025.53268562,0 +1611374400000,32365.00000000,32810.00000000,32300.00000000,32582.01000000,2171.59810500,1611377999999,70886156.14103222,61611,1152.39069900,37617353.46885036,0 +1611378000000,32582.01000000,33378.52000000,32267.07000000,33350.60000000,3432.48724800,1611381599999,112750693.87171465,82778,1815.71824000,59676789.75466644,0 +1611381600000,33357.15000000,33456.00000000,32771.99000000,32820.11000000,3459.27026200,1611385199999,114696218.50447876,86917,1632.52496900,54146912.77462088,0 +1611385200000,32820.11000000,33150.00000000,32676.15000000,32931.18000000,2401.16107600,1611388799999,78955447.93697194,64338,1225.14128300,40289472.48523587,0 +1611388800000,32931.17000000,33000.00000000,32597.76000000,32943.24000000,2294.69006100,1611392399999,75242590.24286201,65598,1181.66516100,38742287.83489750,0 +1611392400000,32943.24000000,33104.94000000,32350.00000000,32453.56000000,3494.21218400,1611395999999,114281787.75036651,86858,1682.71062300,55063934.41630740,0 +1611396000000,32453.56000000,32532.37000000,32171.00000000,32344.37000000,2788.78403400,1611399599999,90158382.55879761,90131,1407.31815800,45503163.12264036,0 +1611399600000,32344.37000000,32542.37000000,31511.24000000,31645.49000000,4876.61961600,1611403199999,155421648.79950466,114476,2366.39363100,75389154.51463057,0 +1611403200000,31643.90000000,32001.28000000,31469.25000000,31602.63000000,2832.03585600,1611406799999,89995749.36806307,82125,1482.74167000,47137095.64828731,0 +1611406800000,31604.51000000,32289.25000000,31390.16000000,31865.19000000,3721.34108400,1611410399999,118464339.62025283,95038,2026.49855300,64515115.11558662,0 +1611410400000,31865.19000000,31980.00000000,31650.00000000,31721.74000000,2196.24159200,1611413999999,69824254.71730175,65547,1033.45308100,32862885.30435583,0 +1611414000000,31719.94000000,32180.00000000,31609.05000000,31877.10000000,2104.61671700,1611417599999,67298734.35128252,61911,1092.15660800,34924429.28608447,0 +1611417600000,31877.10000000,32328.03000000,31759.65000000,32121.84000000,2518.06613900,1611421199999,80752741.53370140,79587,1329.27819800,42644211.27737038,0 +1611421200000,32120.31000000,32409.97000000,32044.77000000,32239.09000000,2251.77458200,1611424799999,72497536.19198385,69594,1186.89480500,38215766.98575053,0 +1611424800000,32238.80000000,32345.00000000,31825.00000000,32167.48000000,2438.10419100,1611428399999,78273000.74346228,57407,1114.08513700,35766365.54075967,0 +1611428400000,32169.92000000,32500.00000000,32138.24000000,32348.79000000,2045.51433100,1611431999999,66125445.50675190,51425,995.62414300,32183374.17893218,0 +1611432000000,32348.78000000,32400.00000000,32021.73000000,32191.33000000,1524.95791900,1611435599999,49086641.98185392,44347,719.01656600,23142927.32853177,0 +1611435600000,32192.93000000,32442.68000000,31812.50000000,32344.22000000,2255.05685100,1611439199999,72529349.69565234,61725,1137.58245800,36600018.68789374,0 +1611439200000,32344.21000000,32538.61000000,31966.47000000,32049.97000000,1596.25194500,1611442799999,51491464.30404120,52393,819.23978100,26441108.79739147,0 +1611442800000,32050.03000000,32122.78000000,31835.85000000,32078.00000000,1980.98185200,1611446399999,63388240.68648952,39994,830.10536400,26556559.61817374,0 +1611446400000,32078.00000000,32086.75000000,31630.00000000,31876.35000000,2459.15967200,1611449999999,78349771.12170719,62163,1188.93801600,37879936.69394955,0 +1611450000000,31876.35000000,32084.91000000,31752.81000000,31863.84000000,1404.06207100,1611453599999,44865889.76254837,41407,709.94800200,22689764.91278492,0 +1611453600000,31860.76000000,32300.00000000,31784.66000000,32096.04000000,1774.93647700,1611457199999,56950530.36653801,47793,921.97673500,29583099.90476307,0 +1611457200000,32096.04000000,32480.06000000,32020.00000000,32480.05000000,2128.03865000,1611460799999,68576072.72203130,52268,1164.64489800,37534165.61903892,0 +1611460800000,32480.06000000,32879.99000000,32346.44000000,32811.05000000,4046.60390600,1611464399999,131610409.79547078,73491,1951.99568700,63495065.95413153,0 +1611464400000,32811.77000000,32980.00000000,32720.00000000,32871.98000000,2869.47383800,1611467999999,94248893.12860491,62763,1481.37316600,48658117.69260505,0 +1611468000000,32871.98000000,33071.00000000,32571.52000000,32757.02000000,2415.52054600,1611471599999,79159830.57866500,59405,1275.17520600,41805080.48814390,0 +1611471600000,32757.03000000,32853.09000000,32511.76000000,32801.15000000,1803.94623200,1611475199999,58917815.12901980,47116,899.89054700,29396258.90373397,0 +1611475200000,32797.21000000,33030.00000000,32570.00000000,32630.48000000,2135.76327500,1611478799999,69957475.67965592,52574,1023.22071400,33521420.25830454,0 +1611478800000,32630.48000000,32758.92000000,32541.32000000,32641.58000000,1910.53862500,1611482399999,62405154.10436933,67671,924.56146100,30198367.73958076,0 +1611482400000,32641.57000000,32724.66000000,32465.00000000,32693.74000000,1565.43584300,1611485999999,51027813.77741188,59213,803.08591700,26181675.30674694,0 +1611486000000,32693.73000000,32893.93000000,32693.73000000,32833.37000000,1989.11672800,1611489599999,65191162.98986752,53700,1103.38713400,36164528.22372911,0 +1611489600000,32833.37000000,32931.59000000,32128.15000000,32362.31000000,3068.96485000,1611493199999,99682557.97741842,73034,1319.80156100,42890256.31446244,0 +1611493200000,32362.32000000,32415.37000000,32107.61000000,32227.29000000,2663.86867100,1611496799999,86059202.76695536,73644,1230.45338200,39746471.34880807,0 +1611496800000,32227.30000000,32360.02000000,31929.31000000,32055.71000000,2195.43004700,1611500399999,70638742.72395953,64689,930.90311000,29955282.40894509,0 +1611500400000,32055.72000000,32259.81000000,31858.68000000,31957.05000000,2011.06256700,1611503999999,64500082.81172732,64579,988.13913800,31692082.66396833,0 +1611504000000,31956.90000000,32139.60000000,31500.00000000,31729.07000000,3614.85602400,1611507599999,114835132.79580004,100567,1691.20895300,53752991.40277353,0 +1611507600000,31729.07000000,31986.12000000,31635.42000000,31851.60000000,2263.53497500,1611511199999,72128516.19621104,62475,1010.82686900,32212591.53995736,0 +1611511200000,31851.59000000,31941.56000000,31766.81000000,31831.67000000,1377.99650000,1611514799999,43889526.64037461,40907,657.61149500,20947293.06741376,0 +1611514800000,31831.66000000,31841.47000000,30900.00000000,31306.29000000,5345.53359600,1611518399999,167203010.02797071,112536,2064.37769800,64574402.14883323,0 +1611518400000,31306.29000000,31757.17000000,31250.26000000,31673.26000000,2860.48241700,1611521999999,89998651.57598165,63740,1376.43030200,43326371.19291900,0 +1611522000000,31673.26000000,31977.60000000,31573.31000000,31909.46000000,1744.66586500,1611525599999,55383548.29101627,67110,861.58659600,27352293.07232051,0 +1611525600000,31909.46000000,32348.40000000,31650.00000000,32127.97000000,1991.43316400,1611529199999,63829956.46422534,67277,1078.18369300,34569390.58264187,0 +1611529200000,32127.97000000,32369.59000000,32015.46000000,32259.90000000,2337.61342700,1611532799999,75199917.93817138,58165,1168.39891700,37594214.57639895,0 +1611532800000,32259.45000000,32831.07000000,32175.61000000,32574.71000000,4492.34534200,1611536399999,146277748.43817087,97899,2452.47937700,79854637.15251205,0 +1611536400000,32575.15000000,32908.98000000,32411.77000000,32864.98000000,2900.14700100,1611539999999,94677652.83307504,68427,1496.45393800,48863779.58125962,0 +1611540000000,32864.97000000,32995.00000000,32636.36000000,32768.23000000,2347.98898000,1611543599999,76958546.93813420,56638,1110.53962800,36402424.42384716,0 +1611543600000,32768.23000000,33674.48000000,32580.30000000,33568.18000000,4706.03630500,1611547199999,156151422.42674605,94675,2679.83693300,88871512.80568639,0 +1611547200000,33568.17000000,33797.96000000,33261.00000000,33378.93000000,3754.09528000,1611550799999,125816591.56082466,82214,1816.50876100,60878211.28812918,0 +1611550800000,33378.06000000,33461.53000000,33188.00000000,33331.13000000,2126.57759900,1611554399999,70898446.60639003,51073,1021.87337700,34069625.73534733,0 +1611554400000,33331.13000000,33550.00000000,33150.00000000,33496.22000000,2557.38044100,1611557999999,85283083.54695842,56356,1300.50544100,43381088.39830938,0 +1611558000000,33496.22000000,33562.04000000,33045.00000000,33346.95000000,2786.69845900,1611561599999,92697097.45934045,63322,1424.03303800,47363349.33624157,0 +1611561600000,33347.19000000,33497.88000000,33188.99000000,33448.21000000,2566.70193600,1611565199999,85591925.94627989,63474,1340.55118400,44704047.41718278,0 +1611565200000,33449.72000000,33548.00000000,32800.00000000,32979.10000000,3423.01687200,1611568799999,113489933.49232923,76269,1606.34752200,53270937.84773043,0 +1611568800000,32979.10000000,33166.00000000,32750.09000000,33117.43000000,3417.07831700,1611572399999,112905085.79654864,85289,1955.61686600,64624341.75150900,0 +1611572400000,33119.35000000,33334.57000000,33040.00000000,33185.26000000,1981.51326800,1611575999999,65739353.93602941,66341,1070.32998700,35513475.22375523,0 +1611576000000,33185.25000000,34300.00000000,33050.00000000,34180.01000000,6294.12879000,1611579599999,212886323.99642283,141672,3832.05364200,129697877.57817209,0 +1611579600000,34180.01000000,34693.93000000,34098.59000000,34544.49000000,6947.92097900,1611583199999,239075222.77008129,149518,3681.46629400,126641878.79692544,0 +1611583200000,34544.50000000,34875.00000000,34280.45000000,34467.43000000,4653.60176100,1611586799999,161201191.93781374,121711,2300.94315700,79711508.64811906,0 +1611586800000,34467.43000000,34588.88000000,34202.69000000,34458.31000000,3214.09083500,1611590399999,110499278.35623155,99800,1683.60676500,57886514.36909641,0 +1611590400000,34458.31000000,34600.00000000,33630.57000000,33910.96000000,6140.45596500,1611593999999,208743836.36417970,137781,2930.49663700,99666505.65631162,0 +1611594000000,33910.95000000,34246.66000000,33700.75000000,33784.36000000,3303.04567900,1611597599999,112062093.92618265,88854,1668.43201000,56623803.28719433,0 +1611597600000,33784.35000000,34031.56000000,33519.00000000,33672.46000000,2950.05725800,1611601199999,99735147.24005105,73313,1351.67085300,45707149.29247083,0 +1611601200000,33669.27000000,33788.38000000,33373.92000000,33411.54000000,2213.52882300,1611604799999,74418069.81680985,54008,1000.65621600,33664318.87293048,0 +1611604800000,33411.54000000,33473.92000000,33061.12000000,33470.20000000,3271.37775200,1611608399999,108861348.10978255,72794,1446.31515700,48132100.20679488,0 +1611608400000,33463.51000000,33464.21000000,32155.28000000,32718.08000000,5912.51444300,1611611999999,193088110.56224740,133539,2399.19789400,78313733.17332801,0 +1611612000000,32715.53000000,32732.99000000,31910.00000000,32462.36000000,3761.90324400,1611615599999,121568650.71200311,99590,1579.13921000,51071639.66397406,0 +1611615600000,32462.38000000,32650.00000000,32201.44000000,32254.20000000,2777.02159200,1611619199999,90133125.79093578,71991,1340.47024500,43517573.98559408,0 +1611619200000,32254.19000000,32793.01000000,31758.00000000,32474.33000000,3799.04119800,1611622799999,122995112.44859934,96323,1871.01283900,60625563.53465943,0 +1611622800000,32474.34000000,32827.33000000,32210.01000000,32758.85000000,2324.03540100,1611626399999,75505666.00678688,74824,1149.22513300,37344328.29491923,0 +1611626400000,32754.20000000,32765.41000000,32230.29000000,32307.97000000,2168.25668200,1611629999999,70355766.42979308,49095,989.98170600,32116146.86170193,0 +1611630000000,32307.96000000,32363.93000000,31458.00000000,31518.66000000,4883.73309100,1611633599999,155459040.94181935,99933,2110.30635200,67182895.72751638,0 +1611633600000,31520.25000000,32181.90000000,31424.71000000,32000.01000000,3361.24679200,1611637199999,106920577.72781471,64042,1675.57158400,53297794.59542500,0 +1611637200000,32000.01000000,32312.46000000,31784.87000000,32062.32000000,2272.54862400,1611640799999,72801492.52926790,48016,1083.96112300,34730583.23470090,0 +1611640800000,32062.32000000,32073.99000000,31311.93000000,31581.73000000,4195.64010700,1611644399999,133031257.69910644,72693,2256.37416800,71536865.56268284,0 +1611644400000,31581.72000000,31782.08000000,31100.00000000,31643.61000000,6371.29734500,1611647999999,200257957.23826182,133721,3145.84801800,98940700.72222313,0 +1611648000000,31643.61000000,31981.99000000,31527.86000000,31896.97000000,2952.73564400,1611651599999,93778498.57264109,77599,1638.24476300,52032050.42180451,0 +1611651600000,31896.97000000,32075.00000000,31373.00000000,31804.77000000,3370.06145600,1611655199999,106741240.98747532,93953,1724.66652700,54634662.34633121,0 +1611655200000,31804.78000000,32450.00000000,31804.78000000,32246.68000000,4058.11986800,1611658799999,130588141.14958126,105841,2202.45517100,70869033.88374717,0 +1611658800000,32247.20000000,32249.98000000,31650.00000000,31796.95000000,2789.97458400,1611662399999,89144115.28256051,72409,1365.48711000,43633950.49891846,0 +1611662400000,31798.65000000,31972.73000000,31229.45000000,31296.94000000,3784.60423700,1611665999999,119599343.36135748,86449,1717.09552100,54279771.19734403,0 +1611666000000,31297.76000000,31920.00000000,31201.00000000,31718.97000000,3556.69465000,1611669599999,112183332.02280718,97781,1818.98332500,57378450.80679835,0 +1611669600000,31718.96000000,31780.60000000,30837.37000000,31257.73000000,6500.21259100,1611673199999,203008820.63261017,135499,2347.97559600,73403789.93890130,0 +1611673200000,31259.29000000,31885.02000000,31252.00000000,31750.23000000,3825.06075200,1611676799999,120817179.77570862,78114,1898.18083400,59957131.00159764,0 +1611676800000,31750.24000000,32122.81000000,31300.69000000,31985.30000000,6316.90126400,1611680399999,200793919.95069850,119851,3685.14131800,117244983.40339768,0 +1611680400000,31985.29000000,32235.00000000,31895.61000000,32184.36000000,2854.44547200,1611683999999,91533624.62957267,83847,1615.95169000,51825367.61913205,0 +1611684000000,32184.36000000,32350.00000000,31861.22000000,32224.50000000,2862.28621200,1611687599999,91942478.25470840,77588,1567.97705900,50373972.28764533,0 +1611687600000,32222.88000000,32403.88000000,32035.93000000,32208.33000000,2678.41918000,1611691199999,86275160.12000351,67942,1280.81507800,41259222.84870607,0 +1611691200000,32208.33000000,32395.00000000,31855.71000000,31986.99000000,2630.68342900,1611694799999,84511924.14518184,70669,1345.47349000,43242137.56002237,0 +1611694800000,31986.98000000,32322.23000000,31900.00000000,31987.13000000,1967.18320000,1611698399999,63164405.71139185,58423,951.14259600,30551043.82136939,0 +1611698400000,31987.13000000,32733.81000000,31890.00000000,32733.81000000,2170.30170200,1611701999999,70022546.23138569,62256,1324.19642800,42754895.13901649,0 +1611702000000,32733.81000000,32921.88000000,32454.84000000,32467.77000000,3278.72342900,1611705599999,107113762.64550759,83524,1636.24548800,53462757.55776008,0 +1611705600000,32464.01000000,32557.29000000,31880.00000000,32335.70000000,3512.77489000,1611709199999,113116385.94697308,72906,1770.25696200,57019173.60195106,0 +1611709200000,32335.71000000,32457.79000000,31955.39000000,32084.60000000,2849.98627400,1611712799999,91671544.50842356,60468,1275.84325000,41033343.45955774,0 +1611712800000,32084.88000000,32263.56000000,31758.92000000,31802.36000000,1970.04962100,1611716399999,63250143.61413279,49155,892.03947200,28649765.00274336,0 +1611716400000,31802.17000000,31916.66000000,31568.28000000,31800.86000000,2041.55994100,1611719999999,64850477.88120768,50328,1007.09673400,31996378.96584142,0 +1611720000000,31801.27000000,32030.28000000,31518.19000000,31864.36000000,1767.21326600,1611723599999,56091342.52528747,47510,887.97474700,28187968.04034165,0 +1611723600000,31866.97000000,31918.71000000,31365.41000000,31503.41000000,2446.34493400,1611727199999,77252810.79085218,78238,1264.00732300,39918906.61170516,0 +1611727200000,31503.42000000,31725.00000000,31350.00000000,31669.98000000,1968.81529500,1611730799999,62202611.41267428,51026,1036.75297700,32751332.23815783,0 +1611730800000,31669.98000000,31890.19000000,31547.41000000,31743.33000000,1912.29469700,1611734399999,60688595.08070834,45948,985.90966900,31293675.10798831,0 +1611734400000,31743.33000000,31749.28000000,31142.33000000,31172.11000000,3088.05994600,1611737999999,97052704.12030284,74442,1276.13919800,40127193.29886190,0 +1611738000000,31172.11000000,31290.00000000,30755.00000000,31201.05000000,5108.52499400,1611741599999,158617441.94178951,103350,2327.34152900,72306404.54268296,0 +1611741600000,31201.06000000,31400.00000000,31080.77000000,31376.90000000,2985.39232800,1611745199999,93325548.70631928,61071,1637.11901800,51184515.34493097,0 +1611745200000,31376.89000000,31615.38000000,30578.94000000,30639.05000000,4942.27402000,1611748799999,154059980.08608101,97493,2339.21186400,72987526.79243921,0 +1611748800000,30635.74000000,30888.00000000,30336.18000000,30759.03000000,5893.37674200,1611752399999,180578478.16806915,108428,2755.26121500,84451897.61136676,0 +1611752400000,30759.02000000,31057.00000000,30245.00000000,30275.30000000,4235.13187900,1611755999999,129745802.16209073,100889,2030.89102200,62247811.72995071,0 +1611756000000,30275.30000000,30520.00000000,29241.72000000,29573.15000000,9777.52588800,1611759599999,291793511.02371413,170979,4353.54803400,129922906.22249881,0 +1611759600000,29573.98000000,30464.93000000,29390.00000000,30322.61000000,6452.91178000,1611763199999,193367167.81476704,123867,3299.96288200,98903048.55543292,0 +1611763200000,30322.59000000,30948.00000000,30216.37000000,30529.57000000,5435.25258300,1611766799999,166467704.67978587,105703,2663.67509500,81597631.48247285,0 +1611766800000,30529.56000000,30845.81000000,30101.43000000,30514.34000000,4037.44367600,1611770399999,122955580.66566653,112339,2006.01672900,61100958.32188968,0 +1611770400000,30508.51000000,30537.50000000,29500.00000000,29709.79000000,4509.67311200,1611773999999,135093736.86313464,99460,2082.04083900,62372915.77181508,0 +1611774000000,29719.93000000,30850.00000000,29712.94000000,30740.33000000,5614.82069900,1611777599999,171246692.67050478,104151,2886.28168100,88037680.83821065,0 +1611777600000,30731.57000000,31556.00000000,30512.19000000,31520.20000000,5934.23090800,1611781199999,184980691.65305210,114222,3501.03725100,109130057.95780681,0 +1611781200000,31520.20000000,31649.99000000,30735.01000000,30958.00000000,3361.40379400,1611784799999,104772762.19722421,75496,1666.01137100,51942714.87607684,0 +1611784800000,30958.01000000,31051.46000000,30325.01000000,30519.93000000,2605.66407600,1611788399999,79921344.45363453,68057,1127.33609800,34605182.16323387,0 +1611788400000,30517.37000000,30727.14000000,30084.24000000,30366.15000000,3461.23636800,1611791999999,104978362.67516341,90427,1592.62667800,48310796.58255527,0 +1611792000000,30362.19000000,30728.57000000,29842.10000000,30671.86000000,3868.31654600,1611795599999,117054689.37539712,81664,1747.83946200,52915454.00577287,0 +1611795600000,30676.28000000,30917.53000000,30370.79000000,30881.94000000,2527.68074500,1611799199999,77365697.08750051,59183,1205.58418700,36914442.79162532,0 +1611799200000,30880.57000000,31214.51000000,30788.30000000,30981.72000000,3021.34740900,1611802799999,93728146.72616530,64100,1469.43157500,45591825.05542701,0 +1611802800000,30987.85000000,31526.78000000,30902.81000000,31404.25000000,4735.03456800,1611806399999,147776428.52334001,95757,2428.21758500,75832437.04657155,0 +1611806400000,31406.90000000,31590.00000000,31045.70000000,31300.73000000,2910.72013000,1611809999999,91045847.13369675,61002,1639.73028800,51299999.47010108,0 +1611810000000,31300.72000000,31800.00000000,31057.96000000,31729.16000000,3279.91959400,1611813599999,102985645.32916172,68625,1778.59539900,55867573.92583334,0 +1611813600000,31729.16000000,31876.63000000,31521.37000000,31564.58000000,3487.71079000,1611817199999,110633373.76520400,73535,1923.99057300,61032793.83926356,0 +1611817200000,31564.75000000,31597.76000000,31080.00000000,31170.53000000,2809.48377000,1611820799999,87885465.19554526,59569,1301.11485300,40706674.33640486,0 +1611820800000,31170.20000000,31303.15000000,31001.55000000,31070.47000000,2699.22237800,1611824399999,84068402.83496546,62325,1163.08740200,36231724.59398582,0 +1611824400000,31070.47000000,31483.44000000,30812.26000000,31466.91000000,3531.47764800,1611827999999,109938694.57514089,72682,1752.03560700,54557757.94370371,0 +1611828000000,31473.33000000,31585.39000000,31030.00000000,31490.29000000,3025.90313700,1611831599999,94762331.47706407,84078,1563.88615100,48984039.72156385,0 +1611831600000,31490.29000000,31600.00000000,31178.80000000,31437.37000000,2607.58697000,1611835199999,81896616.46288308,77818,1311.48633800,41193889.20267538,0 +1611835200000,31437.37000000,31713.43000000,31273.54000000,31477.95000000,3396.26217800,1611838799999,107019921.32660812,98129,1712.41802500,53958558.19706346,0 +1611838800000,31477.95000000,31840.00000000,31161.96000000,31775.12000000,3636.18646600,1611842399999,114583718.01587223,84674,1932.72159100,60900470.42713106,0 +1611842400000,31775.12000000,32150.00000000,31612.52000000,31830.53000000,5513.94787800,1611845999999,175852428.14608458,107453,2910.14176000,92837710.28595129,0 +1611846000000,31829.74000000,32203.38000000,31680.69000000,31926.49000000,5860.37828200,1611849599999,187319000.48965448,137637,2930.27020600,93676052.34067863,0 +1611849600000,31926.49000000,32436.58000000,31650.00000000,32425.71000000,5459.95176300,1611853199999,174979094.42632400,118755,2765.68610600,88676542.00008285,0 +1611853200000,32425.71000000,32490.00000000,32160.06000000,32281.49000000,3534.23954200,1611856799999,114139227.61665858,79831,1618.83931500,52281239.28715444,0 +1611856800000,32281.50000000,32670.00000000,32103.44000000,32633.68000000,3997.53631800,1611860399999,129390876.29705323,82800,2106.13135100,68179431.72715845,0 +1611860400000,32633.69000000,32747.78000000,32458.81000000,32564.71000000,3898.14149900,1611863999999,126986355.88489445,73041,1749.66309400,56998310.43247672,0 +1611864000000,32564.71000000,32900.00000000,32392.34000000,32577.96000000,3598.00013000,1611867599999,117534541.55066396,77268,1663.73508600,54357576.37967870,0 +1611867600000,32577.97000000,33295.55000000,32577.96000000,33183.53000000,4305.94392900,1611871199999,141857003.13632579,97440,2239.11979300,73774812.24859383,0 +1611871200000,33183.53000000,33488.66000000,33126.02000000,33469.67000000,3851.03859700,1611874799999,128353179.79633502,91267,1732.40747000,57737459.77379364,0 +1611874800000,33469.67000000,33783.98000000,33026.00000000,33364.86000000,7065.11535000,1611878399999,236396528.89314326,152027,3421.64910900,114449381.45237988,0 +1611878400000,33368.18000000,34310.00000000,33330.93000000,34150.23000000,10164.38794700,1611881999999,345112507.44377908,207142,5135.00011800,174298460.27402762,0 +1611882000000,34150.23000000,34304.52000000,33666.66000000,33906.57000000,5122.46825100,1611885599999,173979318.36195852,125764,2417.60149500,82095038.73639524,0 +1611885600000,33906.56000000,34201.14000000,33770.00000000,33969.20000000,4650.64856600,1611889199999,157806808.79234403,94579,2271.82590900,77102225.48866917,0 +1611889200000,33969.21000000,34114.95000000,33501.00000000,33733.58000000,6809.20237700,1611892799999,230537722.15599612,128676,3106.65151700,105194192.07641148,0 +1611892800000,33728.99000000,33934.48000000,32750.47000000,33062.82000000,8609.93510300,1611896399999,285624020.41362311,163110,3953.49072900,131091008.23035347,0 +1611896400000,33062.81000000,33193.57000000,32755.56000000,32980.32000000,5689.53301300,1611899999999,187802687.24984144,120363,2966.04463000,97909176.58797633,0 +1611900000000,32980.31000000,32982.33000000,32330.55000000,32483.74000000,7328.13660200,1611903599999,239141992.70319997,145868,3846.76354500,125570682.19706879,0 +1611903600000,32483.74000000,32626.98000000,31915.40000000,32266.35000000,6736.55427100,1611907199999,217124621.14715226,122552,3271.97864900,105463553.25990469,0 +1611907200000,32266.36000000,36600.00000000,32006.91000000,36240.24000000,19312.82747900,1611910799999,657349614.70597752,314310,11284.72753600,384612824.48788561,0 +1611910800000,36223.22000000,37990.00000000,34591.83000000,36877.16000000,32057.76917100,1611914399999,1170981431.47062844,554876,17431.61514800,636387876.26687176,0 +1611914400000,36875.50000000,37200.00000000,35489.41000000,36617.23000000,13351.73985200,1611917999999,485592406.11867599,264211,6468.65620000,235322265.94527225,0 +1611918000000,36617.23000000,37208.94000000,36421.93000000,37025.32000000,9995.03390400,1611921599999,368826783.70134898,182894,5084.05537200,187641109.49586396,0 +1611921600000,37023.83000000,37869.00000000,36534.42000000,37840.07000000,9895.61771500,1611925199999,367797382.70437782,205392,5196.60684500,193285505.17302355,0 +1611925200000,37842.07000000,38531.90000000,36979.32000000,38250.03000000,10190.52174200,1611928799999,384835263.32981755,206694,5557.87250300,210117231.77740116,0 +1611928800000,38250.01000000,38448.39000000,36456.78000000,37058.49000000,12376.77874500,1611932399999,463253682.69542364,223669,5751.44460100,215145357.36227601,0 +1611932400000,37058.49000000,37517.80000000,36700.00000000,37129.40000000,7119.86094900,1611935999999,264499608.70012400,150952,3343.45212100,124213712.30964436,0 +1611936000000,37129.40000000,37569.00000000,35808.00000000,36039.18000000,10309.64505600,1611939599999,380518661.93210766,181421,4906.66653900,181310643.96024192,0 +1611939600000,36038.73000000,36429.00000000,35564.00000000,35741.23000000,8064.31665900,1611943199999,290408716.86866321,178297,4104.19546100,147809776.45541420,0 +1611943200000,35741.23000000,35999.99000000,34600.00000000,35202.46000000,11212.39791800,1611946799999,394534372.45788041,166071,4992.43351100,175775312.10928092,0 +1611946800000,35204.22000000,35357.14000000,33500.00000000,34318.57000000,11414.90901700,1611950399999,391476682.66882703,190951,5427.95899000,186147612.09310751,0 +1611950400000,34322.50000000,34953.87000000,33843.22000000,34574.61000000,7664.13703300,1611953999999,264479532.26727039,145519,3509.15036700,121096451.76548034,0 +1611954000000,34574.61000000,34813.00000000,34120.00000000,34635.53000000,4701.56414300,1611957599999,162228512.71159393,102055,2226.10051000,76828681.43282444,0 +1611957600000,34628.68000000,35354.94000000,34250.00000000,34485.98000000,4078.62701900,1611961199999,142225092.01062971,120324,1862.82567900,64988703.44031910,0 +1611961200000,34485.98000000,34640.19000000,33700.00000000,34252.20000000,4970.39309400,1611964799999,169455913.61722583,107659,2420.12987200,82533632.71161126,0 +1611964800000,34246.28000000,34861.56000000,34214.91000000,34250.10000000,4446.39087000,1611968399999,153652340.31386364,108002,2364.30163800,81699824.25484977,0 +1611968400000,34250.10000000,34933.00000000,33927.00000000,34123.05000000,3869.44940000,1611971999999,133177861.93823476,91508,1985.97610600,68382971.95114120,0 +1611972000000,34123.06000000,34443.96000000,33674.70000000,33862.51000000,3988.19733700,1611975599999,135885410.39249829,85158,1972.40666300,67218238.12695476,0 +1611975600000,33861.55000000,34000.00000000,32825.00000000,33273.36000000,6807.71918700,1611979199999,226871612.32579531,131311,3133.19562100,104463104.11760685,0 +1611979200000,33273.36000000,33656.08000000,33001.52000000,33503.13000000,4185.93672300,1611982799999,139795812.00459418,89067,1937.42725100,64717170.69286870,0 +1611982800000,33503.14000000,33986.40000000,33174.55000000,33503.72000000,3638.46455700,1611986399999,122187543.51567719,99237,1855.85789100,62336044.68677898,0 +1611986400000,33503.72000000,33850.00000000,33137.80000000,33809.79000000,3684.99384300,1611989999999,123147576.69048441,108504,1828.75987900,61128398.26324755,0 +1611990000000,33809.79000000,34200.00000000,33400.00000000,34046.80000000,3867.91882500,1611993599999,130607799.65151298,107115,1995.22358400,67389101.16798405,0 +1611993600000,34046.82000000,34358.97000000,33775.44000000,33887.50000000,4900.02089400,1611997199999,167229239.26552966,89241,2351.89074300,80258089.04546266,0 +1611997200000,33883.85000000,34424.70000000,33809.39000000,34253.18000000,3386.81273500,1612000799999,115712942.60375289,79768,1685.20636400,57574926.30557272,0 +1612000800000,34253.17000000,34392.00000000,33870.95000000,34299.82000000,3971.80079200,1612004399999,135598002.40291819,97114,1900.18351600,64880317.76623992,0 +1612004400000,34299.82000000,34328.59000000,33510.00000000,33660.40000000,3646.87237900,1612007999999,123663790.64396261,87720,1728.40181800,58605167.08020547,0 +1612008000000,33660.40000000,33832.78000000,33410.63000000,33751.77000000,3003.42375300,1612011599999,101034454.78274613,78627,1589.95115000,53492405.44195036,0 +1612011600000,33751.77000000,34349.63000000,33666.67000000,34237.69000000,3019.37515900,1612015199999,102524279.83412895,80155,1641.17662500,55754425.62086473,0 +1612015200000,34237.69000000,34400.00000000,34000.00000000,34234.73000000,2997.76987400,1612018799999,102418819.17762771,91670,1599.60347400,54654070.77868259,0 +1612018800000,34234.73000000,34500.00000000,34057.22000000,34210.20000000,2959.94267800,1612022399999,101381388.78716153,83146,1570.31052800,53798757.52340426,0 +1612022400000,34210.18000000,34262.35000000,33520.00000000,33956.70000000,5589.95477700,1612025999999,189129789.50111192,162431,2668.91398100,90307049.67197864,0 +1612026000000,33956.70000000,34290.44000000,33943.00000000,34253.67000000,3332.80790500,1612029599999,113757762.40424967,115663,1737.18038300,59292355.51246802,0 +1612029600000,34252.02000000,34351.00000000,34110.12000000,34340.00000000,2258.74787800,1612033199999,77330554.26582136,70939,1185.85715800,40602779.26883419,0 +1612033200000,34340.00000000,34400.02000000,34028.87000000,34286.50000000,2047.94488100,1612036799999,70129136.65266194,63075,1027.61323600,35193610.38665192,0 +1612036800000,34286.50000000,34449.69000000,34080.00000000,34154.63000000,2018.49347200,1612040399999,69243326.64227957,62882,1013.15066700,34758584.21722212,0 +1612040400000,34157.50000000,34690.00000000,33966.40000000,34675.53000000,2087.95795500,1612043999999,71593702.94556996,62418,1155.23465400,39650016.31621405,0 +1612044000000,34675.53000000,34800.00000000,34516.78000000,34526.13000000,2094.79261100,1612047599999,72560499.44122176,82322,1041.79435600,36091461.55313465,0 +1612047600000,34525.88000000,34553.51000000,34164.78000000,34262.88000000,3083.89285500,1612051199999,105866416.75467381,73967,1448.84981300,49732530.90332009,0 +1612051200000,34262.89000000,34342.69000000,33850.00000000,34066.84000000,2644.82454900,1612054799999,90175038.25134254,78953,1255.21886900,42806497.69141891,0 +1612054800000,34066.84000000,34249.99000000,33940.00000000,34194.00000000,1867.10397600,1612058399999,63655356.52616395,55965,901.56706500,30735495.27642211,0 +1612058400000,34193.29000000,34238.00000000,33681.00000000,33750.00000000,2644.01293500,1612061999999,89553777.53771814,60467,1206.13579700,40854036.82787826,0 +1612062000000,33748.69000000,34042.00000000,33655.00000000,33930.21000000,1980.01672200,1612065599999,67158112.67791061,52167,1019.47386200,34583012.46039532,0 +1612065600000,33930.22000000,34127.65000000,33794.27000000,34034.31000000,1805.95175100,1612069199999,61338223.41763807,47859,901.53663300,30622644.98494255,0 +1612069200000,34034.30000000,34056.64000000,33678.46000000,33756.39000000,1919.90662400,1612072799999,64929411.25863169,63877,901.74071800,30495524.95514881,0 +1612072800000,33757.17000000,33857.88000000,33571.42000000,33655.86000000,1945.82559400,1612076399999,65600207.94435328,47790,930.32602000,31366164.26940287,0 +1612076400000,33655.85000000,33846.27000000,33450.00000000,33607.98000000,2065.00471500,1612079999999,69515828.35365876,52990,986.38347400,33218178.43936213,0 +1612080000000,33607.68000000,33832.94000000,33312.12000000,33596.72000000,2711.80689800,1612083599999,91112581.94067643,62435,1392.43016500,46799966.82858392,0 +1612083600000,33596.72000000,33769.93000000,33270.00000000,33301.70000000,2439.99427700,1612087199999,81773282.46528828,61860,1149.48063500,38531385.05985345,0 +1612087200000,33300.01000000,33744.88000000,33205.00000000,33653.68000000,2544.01392700,1612090799999,85311143.11480684,66211,1289.51975600,43255464.17454825,0 +1612090800000,33652.23000000,33784.40000000,33469.38000000,33563.23000000,1965.17830200,1612094399999,66078553.26019094,56862,996.18671100,33496992.17475449,0 +1612094400000,33563.24000000,34220.00000000,33366.29000000,33974.05000000,4152.45212000,1612097999999,140704742.42162135,89675,2244.35105400,76054246.78438007,0 +1612098000000,33974.05000000,34050.00000000,33607.95000000,33692.92000000,2291.02209100,1612101599999,77417451.86772917,67210,1058.56889400,35773756.47719697,0 +1612101600000,33691.49000000,33735.54000000,33318.02000000,33330.71000000,2924.24989400,1612105199999,98028927.06121184,71653,1316.14808200,44130251.32737339,0 +1612105200000,33330.72000000,33470.00000000,32554.00000000,32862.66000000,6617.93451100,1612108799999,218037468.51139443,133310,2887.50033900,95114203.83659416,0 +1612108800000,32862.65000000,33073.55000000,32555.00000000,32891.86000000,3707.19492000,1612112399999,121964680.76611902,82287,1714.22150800,56423575.18170762,0 +1612112400000,32891.86000000,33077.90000000,32200.00000000,32302.31000000,4790.61473300,1612115999999,156494910.95577298,101275,2143.45840500,70054838.61757502,0 +1612116000000,32302.32000000,32849.71000000,32171.67000000,32450.30000000,3929.77849000,1612119599999,127769211.17755456,95100,1914.82971200,62262815.18062214,0 +1612119600000,32449.53000000,32926.25000000,32400.27000000,32808.80000000,3396.97812500,1612123199999,111186671.44357629,79192,1617.39626500,52940950.71833745,0 +1612123200000,32807.29000000,32931.55000000,32461.23000000,32853.73000000,2968.31519700,1612126799999,97119658.90147466,72031,1330.33925900,43546588.71877033,0 +1612126800000,32853.73000000,32899.39000000,32515.00000000,32560.73000000,2336.55316500,1612130399999,76465178.41548618,79137,1108.39197200,36275448.49838342,0 +1612130400000,32561.35000000,33088.88000000,32559.85000000,32974.10000000,1874.80796500,1612133999999,61632662.65925331,60768,888.21922300,29205489.37903717,0 +1612134000000,32974.10000000,33255.49000000,32933.54000000,33092.98000000,3218.73890300,1612137599999,106617964.82843901,67990,1327.02294000,43955023.65788233,0 +1612137600000,33092.97000000,33106.33000000,32296.16000000,32546.27000000,4383.92612200,1612141199999,142737162.71050398,98763,2074.60006900,67502334.30717597,0 +1612141200000,32546.32000000,33560.90000000,32476.34000000,33430.29000000,3713.64949200,1612144799999,122901565.64866951,76863,1958.69177400,64820477.07485389,0 +1612144800000,33425.19000000,33830.00000000,33222.88000000,33649.73000000,3694.93162900,1612148399999,124101642.97642446,70196,2026.27061300,68048628.28106551,0 +1612148400000,33646.37000000,33776.81000000,33470.00000000,33573.97000000,2882.14179500,1612151999999,96898863.58231833,65467,1502.16471600,50506662.36382209,0 +1612152000000,33573.25000000,33943.55000000,33423.43000000,33558.25000000,3206.05432800,1612155599999,107985187.41969644,82376,1739.63260100,58612443.43947073,0 +1612155600000,33560.91000000,33888.33000000,33429.36000000,33755.40000000,2593.02037900,1612159199999,87162686.10827070,77102,1429.27879800,48049426.93847586,0 +1612159200000,33753.59000000,34427.00000000,33284.24000000,33518.89000000,6222.25895500,1612162799999,210377110.91915361,128607,3252.07960100,110039887.36561705,0 +1612162800000,33518.88000000,33885.39000000,33390.12000000,33803.97000000,3328.87882900,1612166399999,111983571.65304035,82926,1639.38870500,55169920.19953022,0 +1612166400000,33802.60000000,34500.00000000,33589.23000000,34477.31000000,5058.23727000,1612169999999,171793699.65688623,114044,2658.75611900,90308550.73893042,0 +1612170000000,34475.57000000,34717.27000000,34268.62000000,34354.47000000,5654.14105500,1612173599999,195106370.41513305,116712,2909.97244600,100421427.90252032,0 +1612173600000,34354.46000000,34539.94000000,34012.41000000,34163.28000000,4235.26065700,1612177199999,145043190.37158130,102798,2138.94071500,73268266.30953945,0 +1612177200000,34163.28000000,34400.00000000,33935.47000000,34183.33000000,4573.86889000,1612180799999,156247039.91294781,110371,2411.24058200,82367159.94215582,0 +1612180800000,34183.33000000,34460.00000000,33590.00000000,33770.23000000,5761.08894000,1612184399999,196167710.12255972,94637,2842.24857600,96774325.81179573,0 +1612184400000,33770.23000000,34050.00000000,33655.00000000,33702.25000000,4848.93435600,1612187999999,164142743.39168623,95479,2501.54189600,84685143.75421217,0 +1612188000000,33702.25000000,33866.49000000,33400.00000000,33532.81000000,4147.49669800,1612191599999,139437968.36318677,70535,1956.32836600,65799272.08513261,0 +1612191600000,33535.51000000,33638.99000000,33160.00000000,33160.17000000,2721.18660300,1612195199999,91002423.81062862,60911,1153.35365200,38584199.50053891,0 +1612195200000,33160.00000000,33603.91000000,33133.26000000,33460.83000000,2419.87278000,1612198799999,80761974.58769844,50309,1133.40766000,37826860.75130885,0 +1612198800000,33460.83000000,34100.00000000,33380.00000000,33978.31000000,3038.66868500,1612202399999,102352703.97211269,76303,1455.47781900,49063257.86370151,0 +1612202400000,33979.94000000,34032.93000000,33655.01000000,33731.52000000,1872.63065600,1612205999999,63366430.46922832,53060,843.16582300,28529194.50917199,0 +1612206000000,33739.52000000,34072.54000000,33700.30000000,33838.13000000,1802.34725300,1612209599999,61103749.87479555,40254,955.42222900,32392586.45573624,0 +1612209600000,33838.13000000,34039.00000000,33722.04000000,33831.55000000,1718.93123500,1612213199999,58254258.51752635,36267,986.74705500,33438414.96058199,0 +1612213200000,33831.54000000,33848.95000000,33549.00000000,33658.67000000,1451.01626700,1612216799999,48922604.53882721,32918,717.17428800,24184331.91016902,0 +1612216800000,33661.79000000,33789.73000000,33511.00000000,33539.39000000,1538.15262500,1612220399999,51750348.05666541,37352,647.50595400,21786987.24340813,0 +1612220400000,33542.12000000,33768.00000000,33430.76000000,33526.37000000,1851.58138300,1612223999999,62175650.92606452,36242,922.45142900,30979207.01918344,0 +1612224000000,33517.09000000,34161.39000000,33418.00000000,33763.07000000,3418.17893300,1612227599999,115729706.33114230,63969,1834.01032400,62119675.06646612,0 +1612227600000,33763.06000000,33800.96000000,33509.00000000,33744.71000000,1866.75345600,1612231199999,62792661.73073772,52952,881.33041000,29646228.26125995,0 +1612231200000,33742.99000000,33876.73000000,33555.49000000,33646.00000000,2079.71725000,1612234799999,70054606.83642168,56184,1032.14771700,34765415.66222445,0 +1612234800000,33646.00000000,33700.00000000,33501.25000000,33550.32000000,1739.29358600,1612238399999,58463810.05230950,46143,762.90747200,25643101.38073138,0 +1612238400000,33554.08000000,33963.29000000,33500.00000000,33876.37000000,2126.28743500,1612241999999,71835719.93835479,43360,1006.42534400,34007577.10022674,0 +1612242000000,33876.36000000,34100.00000000,33770.00000000,33992.83000000,2064.00040900,1612245599999,70038448.05485895,60017,1051.64973300,35695177.95958224,0 +1612245600000,33992.83000000,34321.61000000,33924.73000000,34295.01000000,3127.06324200,1612249199999,106640407.46283040,82974,1864.24443700,63593360.71907737,0 +1612249200000,34295.01000000,34400.00000000,34136.02000000,34223.38000000,3112.03491100,1612252799999,106630733.57998358,66027,1360.28784800,46612659.85584861,0 +1612252800000,34223.38000000,34683.63000000,34080.00000000,34663.87000000,4957.22423300,1612256399999,170397234.01661507,84147,2572.90613200,88458694.69105036,0 +1612256400000,34663.87000000,35668.10000000,34663.87000000,35334.04000000,8817.04469900,1612259999999,310915131.05624431,158364,4715.61287300,166220299.63782661,0 +1612260000000,35334.03000000,35434.70000000,34910.48000000,35160.24000000,3910.05383200,1612263599999,137638713.26559870,81936,1969.64299400,69336306.75180312,0 +1612263600000,35160.24000000,35284.49000000,34601.00000000,34720.15000000,4384.33598400,1612267199999,153356161.25391537,84105,2322.49346000,81237513.90743492,0 +1612267200000,34722.97000000,35000.00000000,34524.20000000,34779.91000000,2883.95498700,1612270799999,100377726.68791107,61033,1527.53948300,53167842.80168389,0 +1612270800000,34779.90000000,35200.00000000,34731.70000000,34844.73000000,3086.32433400,1612274399999,107830810.18705080,68712,1563.54779800,54629422.78110823,0 +1612274400000,34844.06000000,34932.50000000,34333.00000000,34793.99000000,3325.55569500,1612277999999,115350800.34527094,77765,1464.98036700,50826272.19172544,0 +1612278000000,34795.72000000,35151.00000000,34548.26000000,34708.47000000,3413.59949100,1612281599999,118797411.48827525,91425,1673.84486800,58273351.05906327,0 +1612281600000,34708.47000000,35175.31000000,34556.85000000,34964.52000000,4344.34360500,1612285199999,151529824.86205332,107598,2102.94280600,73357443.61602877,0 +1612285200000,34964.52000000,35021.85000000,34738.00000000,34851.47000000,2262.62325500,1612288799999,78878997.20662456,63282,1079.40325900,37634210.25001854,0 +1612288800000,34851.47000000,35308.23000000,34790.00000000,35264.21000000,2743.26236400,1612292399999,96146404.38965027,66654,1456.82234100,51080321.11312637,0 +1612292400000,35264.66000000,35800.00000000,35090.91000000,35762.03000000,4111.44241800,1612295999999,145781142.12603605,93057,2163.66700400,76735932.20940161,0 +1612296000000,35762.05000000,35984.33000000,35525.10000000,35786.51000000,4024.74000800,1612299599999,143903400.12762671,92961,2000.29360800,71524851.86595844,0 +1612299600000,35788.30000000,35896.49000000,35558.90000000,35653.07000000,2723.87766400,1612303199999,97346782.21912855,68418,1183.55344900,42304056.00682402,0 +1612303200000,35653.03000000,35812.49000000,35530.00000000,35572.36000000,1588.32591600,1612306799999,56638743.09164516,60824,723.20399600,25793701.52793158,0 +1612306800000,35576.49000000,35699.38000000,35466.00000000,35466.24000000,1946.62217300,1612310399999,69246520.00732346,57765,903.10538300,32127548.22049756,0 +1612310400000,35472.71000000,36240.00000000,35362.38000000,36135.01000000,4260.42510600,1612313999999,153185534.44129433,86243,2203.09281300,79227037.81705352,0 +1612314000000,36139.74000000,36349.64000000,35843.21000000,35879.27000000,3464.39918300,1612317599999,124916962.68756605,66965,1653.08112200,59598074.16722305,0 +1612317600000,35879.26000000,36125.93000000,35816.74000000,35889.37000000,2828.48526800,1612321199999,101621495.81154046,54021,1324.44941100,47583575.26033304,0 +1612321200000,35889.37000000,36500.00000000,35878.11000000,36403.47000000,3006.03753600,1612324799999,108745191.30919389,55259,1432.54751000,51837707.53058516,0 +1612324800000,36403.47000000,36845.00000000,36403.47000000,36628.85000000,4488.05451800,1612328399999,164545262.50417447,108221,2400.78299900,88008701.12544991,0 +1612328400000,36628.86000000,36690.14000000,36377.10000000,36460.12000000,2188.76658000,1612331999999,79870230.17375060,62274,1139.80547900,41586730.04582903,0 +1612332000000,36462.63000000,36789.00000000,36435.96000000,36535.90000000,2417.77068400,1612335599999,88535810.28662406,55099,1346.49868100,49309644.81198082,0 +1612335600000,36533.94000000,36590.08000000,36231.66000000,36297.57000000,2827.28406700,1612339199999,102996893.41242375,53205,1277.00218500,46524149.46095999,0 +1612339200000,36297.58000000,36299.98000000,35640.93000000,36010.09000000,4414.92098600,1612342799999,158931388.68529092,82881,2039.10271600,73397144.18563155,0 +1612342800000,36011.01000000,36036.00000000,35511.00000000,35851.19000000,3634.75184200,1612346399999,130021296.18955165,72725,1963.61532100,70243609.17911803,0 +1612346400000,35851.19000000,36040.00000000,35657.69000000,35985.27000000,2271.00839000,1612349999999,81400262.48087777,54106,1250.01216100,44809168.90517665,0 +1612350000000,35985.27000000,36238.38000000,35855.31000000,35969.41000000,2702.52792900,1612353599999,97455671.35949739,62958,1234.33109500,44512176.33707880,0 +1612353600000,35969.41000000,36322.96000000,35810.90000000,36178.86000000,2932.29172400,1612357199999,105997784.07411489,75668,1462.93130700,52880945.50975140,0 +1612357200000,36179.62000000,36720.56000000,35944.51000000,36537.42000000,4542.42642200,1612360799999,165607888.09043088,108797,2106.04437400,76774909.81866128,0 +1612360800000,36537.42000000,36760.53000000,36369.56000000,36548.60000000,3658.66180400,1612364399999,133734783.41610500,82802,1652.42268100,60404716.13487960,0 +1612364400000,36548.59000000,36917.27000000,36540.79000000,36850.00000000,4080.22547600,1612367999999,149926004.80378024,89781,2038.01231000,74886177.18525864,0 +1612368000000,36850.00000000,37221.42000000,36643.07000000,37146.67000000,5690.30451000,1612371599999,210149745.28047698,128478,3114.07008200,115033725.72814644,0 +1612371600000,37146.67000000,37179.69000000,36929.00000000,37176.86000000,3489.54181000,1612375199999,129297550.90680523,87386,1753.00959900,64945347.84804888,0 +1612375200000,37176.87000000,37200.00000000,36688.00000000,37114.14000000,3606.78845700,1612378799999,133452803.73988869,94525,1785.80943800,66092068.23989953,0 +1612378800000,37116.47000000,37136.00000000,36788.88000000,36788.89000000,2430.82486900,1612382399999,89721003.60116466,72957,1101.98836900,40677504.75242853,0 +1612382400000,36788.89000000,37075.70000000,36644.44000000,37039.88000000,2729.99998500,1612385999999,100654510.98253434,77912,1303.46058400,48066791.14988422,0 +1612386000000,37039.88000000,37420.51000000,36965.52000000,37256.97000000,3713.74998200,1612389599999,138078449.71433311,94908,1780.08801500,66197164.04526289,0 +1612389600000,37256.97000000,37509.74000000,37232.72000000,37276.31000000,2590.42054700,1612393199999,96836739.62843673,77051,1138.23533000,42549937.54073131,0 +1612393200000,37276.30000000,37662.63000000,37267.02000000,37618.87000000,2814.66598800,1612396799999,105549524.60444919,77518,1362.68147800,51101039.36254488,0 +1612396800000,37620.26000000,38128.00000000,37615.93000000,38063.15000000,4961.19259900,1612400399999,187977973.17526249,117944,3061.91068900,116029439.75396000,0 +1612400400000,38065.00000000,38288.00000000,37861.83000000,38147.35000000,4294.87765600,1612403999999,163643128.68714705,92293,2203.02853500,83962739.55237745,0 +1612404000000,38147.36000000,38215.40000000,37505.51000000,37896.36000000,3775.56313000,1612407599999,142792275.77206093,81556,1829.97626400,69199475.74376775,0 +1612407600000,37896.36000000,38015.50000000,37363.17000000,37498.78000000,3017.09742300,1612411199999,113590846.05870777,64132,1354.76592900,51021670.96465612,0 +1612411200000,37498.78000000,37788.76000000,37326.83000000,37678.39000000,2283.22218800,1612414799999,85875459.99277110,66721,1012.22829600,38070204.87406065,0 +1612414800000,37678.40000000,37924.35000000,37479.03000000,37578.23000000,2687.63416100,1612418399999,101354654.40364460,55759,1199.57788700,45251175.88198284,0 +1612418400000,37577.31000000,38195.00000000,37530.95000000,38076.43000000,3405.71067700,1612421999999,129186885.66333964,89003,1797.58701100,68202617.61705715,0 +1612422000000,38076.43000000,38175.69000000,37800.00000000,37843.40000000,3290.32831400,1612425599999,124899917.36988243,81512,1709.94375700,64917523.56638815,0 +1612425600000,37843.40000000,38708.27000000,37015.00000000,37338.19000000,9587.95413600,1612429199999,366242945.92388063,191071,5060.19562000,193523169.32141441,0 +1612429200000,37339.11000000,37604.07000000,36662.45000000,37509.22000000,7567.33806800,1612432799999,281563628.35227136,185306,3731.19218000,138879883.45744725,0 +1612432800000,37509.22000000,37772.43000000,37206.20000000,37611.63000000,3331.24284900,1612436399999,124958513.58251474,84501,1660.32241100,62288639.09505894,0 +1612436400000,37612.90000000,37922.78000000,37306.12000000,37321.75000000,3250.63072000,1612439999999,122447003.14992986,82299,1575.70367600,59379233.80206839,0 +1612440000000,37319.43000000,37763.57000000,37021.80000000,37618.69000000,3402.20962400,1612443599999,127500327.07817100,85938,1639.67822300,61461903.60544999,0 +1612443600000,37618.68000000,37690.00000000,37268.03000000,37587.58000000,2729.71393000,1612447199999,102291632.65196248,75618,1178.04694100,44158825.48738725,0 +1612447200000,37587.58000000,37705.00000000,36626.86000000,36795.15000000,4883.79355700,1612450799999,181710552.43222282,107485,2150.47386200,80066225.29988460,0 +1612450800000,36795.15000000,36965.34000000,36161.95000000,36564.23000000,5975.27268200,1612454399999,218390088.61388537,126393,3210.41416400,117331751.49171108,0 +1612454400000,36564.23000000,36989.99000000,36399.79000000,36929.36000000,3826.18916300,1612457999999,140423708.51856383,86263,1929.22354400,70810966.36637297,0 +1612458000000,36929.53000000,37070.00000000,36780.00000000,36884.34000000,3095.31990500,1612461599999,114258715.03809118,87277,1340.55860200,49492340.65480582,0 +1612461600000,36884.34000000,37422.37000000,36761.89000000,37141.96000000,2972.45142600,1612465199999,110379893.67350746,80261,1528.26404400,56771212.21425576,0 +1612465200000,37143.44000000,37499.99000000,36980.00000000,37467.18000000,2969.28167600,1612468799999,110544242.29106592,75098,1335.24969300,49718533.36209310,0 +1612468800000,37467.18000000,37783.83000000,37366.00000000,37613.31000000,3154.23804600,1612472399999,118507575.50112123,79887,1529.58809400,57462912.05821626,0 +1612472400000,37613.32000000,37729.82000000,37302.00000000,37643.00000000,2384.69396100,1612475999999,89503771.03270257,74675,1111.65352100,41720592.51664071,0 +1612476000000,37643.00000000,37698.73000000,36964.03000000,37240.00000000,2533.48052000,1612479599999,94359816.25785984,79029,1148.75691600,42780272.54525439,0 +1612479600000,37240.00000000,37382.34000000,36841.77000000,36936.66000000,2701.29948700,1612483199999,100265466.93272621,61845,1217.87383100,45208704.65722741,0 +1612483200000,36936.65000000,37227.22000000,36795.72000000,36993.25000000,2538.98242500,1612486799999,94060540.82816912,66150,1370.47502500,50781072.55362958,0 +1612486800000,36993.25000000,37300.00000000,36570.00000000,36632.38000000,2618.34989800,1612490399999,96919235.86880108,65505,1214.69936000,44986589.95702002,0 +1612490400000,36632.38000000,36990.00000000,36570.00000000,36958.28000000,2861.36000100,1612493999999,105221638.22311394,66191,1351.23382600,49686787.80852069,0 +1612494000000,36958.33000000,37400.00000000,36909.71000000,37366.02000000,2614.23721000,1612497599999,97331762.32062225,68270,1382.64503900,51483483.61294185,0 +1612497600000,37366.01000000,37499.00000000,37187.81000000,37266.78000000,1902.89073900,1612501199999,70991732.29723368,54835,998.86660700,37264472.34248572,0 +1612501200000,37266.79000000,37350.33000000,36995.27000000,37065.97000000,1730.40606500,1612504799999,64358448.18172280,49929,824.66968800,30670842.63141629,0 +1612504800000,37065.98000000,37658.00000000,37021.80000000,37375.52000000,2965.59287000,1612508399999,110836113.57500378,76786,1668.63744500,62377233.66280996,0 +1612508400000,37374.39000000,37727.22000000,37374.38000000,37653.98000000,2722.54939900,1612511999999,102258856.11144493,74145,1405.51437900,52789937.13927410,0 +1612512000000,37659.64000000,37800.00000000,37392.71000000,37705.27000000,3404.58685900,1612515599999,128051636.94025258,85797,1728.19622500,65008576.01249925,0 +1612515600000,37705.27000000,37769.85000000,37211.85000000,37251.07000000,2526.09904400,1612519199999,94847506.17347487,70845,1167.10109800,43835634.94429535,0 +1612519200000,37251.07000000,37655.44000000,37200.00000000,37395.91000000,2315.26181600,1612522799999,86736898.08353802,70360,1122.58134400,42057910.15909118,0 +1612522800000,37395.92000000,37733.75000000,37395.78000000,37691.32000000,2165.14946300,1612526399999,81402029.34160568,63507,1010.10163900,37972029.61722899,0 +1612526400000,37691.32000000,38151.69000000,37527.14000000,37850.36000000,4197.95733600,1612529999999,159155783.62946250,104275,2317.12911900,87866670.67919380,0 +1612530000000,37850.36000000,38298.00000000,37767.09000000,38272.32000000,3967.77305800,1612533599999,150813327.15355556,127525,2099.61640800,79831159.32397812,0 +1612533600000,38272.33000000,38310.12000000,37960.73000000,38095.02000000,4108.05694300,1612537199999,156744958.72791620,99933,1866.70509400,71218889.68443885,0 +1612537200000,38095.14000000,38288.19000000,37871.42000000,37960.76000000,3833.87290000,1612540799999,145986174.46799004,114481,1710.61808300,65151398.33083216,0 +1612540800000,37960.76000000,38163.34000000,37655.17000000,37809.55000000,4270.39593400,1612544399999,162066461.07501361,130627,1847.41596500,70111024.53628700,0 +1612544400000,37813.19000000,37950.00000000,37733.00000000,37894.61000000,2229.58176300,1612547999999,84391751.86856290,68440,1069.02714800,40465805.16053230,0 +1612548000000,37894.61000000,37922.44000000,37312.25000000,37406.23000000,2936.18453000,1612551599999,110607646.49013193,73073,1329.27869900,50085592.08049400,0 +1612551600000,37405.63000000,37676.13000000,37230.00000000,37608.92000000,3067.36093300,1612555199999,115005347.28495289,77422,1344.85113300,50427638.18365530,0 +1612555200000,37608.91000000,37790.00000000,37485.94000000,37740.39000000,2177.90475900,1612558799999,82020586.16573915,69036,1082.11254000,40757143.58772434,0 +1612558800000,37740.40000000,37920.00000000,37656.29000000,37819.67000000,1692.32032700,1612562399999,63941297.17713087,60169,821.26085200,31034094.15883675,0 +1612562400000,37819.67000000,37971.61000000,37652.79000000,37784.12000000,1587.73281200,1612565999999,60092643.60543921,53710,718.65661900,27201604.72468686,0 +1612566000000,37782.98000000,38309.00000000,37743.81000000,38290.24000000,2246.72719100,1612569599999,85435916.16070902,62242,1304.99169600,49648288.94626587,0 +1612569600000,38289.32000000,38879.00000000,38215.94000000,38740.92000000,5397.48355200,1612573199999,208053475.66680662,147707,3406.47525700,131322910.58625497,0 +1612573200000,38740.92000000,39482.18000000,38275.86000000,38806.45000000,10003.94637800,1612576799999,390200018.23093633,197361,5676.12679700,221449716.55407816,0 +1612576800000,38806.45000000,39535.36000000,38612.00000000,39382.10000000,5911.87452700,1612580399999,231361842.13340831,128272,3115.93829000,122001548.96890421,0 +1612580400000,39383.26000000,39666.00000000,39200.00000000,39384.74000000,4116.76235500,1612583999999,162350846.58796715,91721,2220.03890000,87582967.52244492,0 +1612584000000,39386.92000000,39386.93000000,38933.00000000,39179.56000000,2678.75088500,1612587599999,104992043.77130752,60522,1391.05886300,54518857.13771583,0 +1612587600000,39179.56000000,39238.00000000,38600.00000000,39014.73000000,2895.91239600,1612591199999,112848792.63929416,64210,1441.67270800,56201285.53642504,0 +1612591200000,39015.08000000,39458.37000000,38989.90000000,39267.47000000,2778.74063400,1612594799999,109086522.14959429,58879,1398.43575600,54896197.02950555,0 +1612594800000,39267.47000000,39488.62000000,39156.16000000,39359.12000000,2344.52768700,1612598399999,92210146.02486588,55905,1187.52056100,46709229.45616234,0 +1612598400000,39362.27000000,39699.69000000,39297.75000000,39425.02000000,3300.46687200,1612601999999,130441380.93142371,74577,1752.72083500,69278540.91525593,0 +1612602000000,39427.00000000,39900.00000000,39400.00000000,39887.91000000,3983.37562300,1612605599999,158139448.06879191,92083,2259.81137600,89736312.59180295,0 +1612605600000,39887.91000000,40000.00000000,39516.17000000,39998.63000000,4327.83615600,1612609199999,172331537.28403555,89421,2465.75916600,98241913.39500154,0 +1612609200000,39998.63000000,40479.86000000,39992.64000000,40199.99000000,6837.07743600,1612612799999,275033964.19394919,143363,3673.13335200,147725671.45858567,0 +1612612800000,40199.52000000,40445.55000000,39836.72000000,39902.49000000,4298.29820900,1612616399999,172657675.33101562,92646,2161.80091700,86855747.22067142,0 +1612616400000,39902.50000000,40255.08000000,39900.00000000,40130.47000000,2914.83720400,1612619999999,116904231.22820420,79449,1450.02169800,58146130.51888595,0 +1612620000000,40127.07000000,40574.85000000,40125.30000000,40268.44000000,3508.67471100,1612623599999,141595861.06674717,93559,1875.19658100,75682835.58260766,0 +1612623600000,40268.44000000,40866.66000000,40134.80000000,40864.73000000,4850.41533800,1612627199999,196738399.90669565,125084,2635.63599800,106912802.55464475,0 +1612627200000,40865.12000000,40955.51000000,40478.19000000,40608.76000000,4533.51779900,1612630799999,184552299.88860376,95758,2349.01142000,95629949.47079209,0 +1612630800000,40608.77000000,40662.01000000,40163.67000000,40197.01000000,3400.92676500,1612634399999,137684308.85395985,100225,1623.59211800,65744658.43377461,0 +1612634400000,40197.01000000,40444.44000000,40052.39000000,40276.41000000,3152.89187200,1612637999999,126882405.86077563,99367,1621.15080000,65251328.98528318,0 +1612638000000,40276.41000000,40420.00000000,39940.44000000,40179.42000000,3188.91142100,1612641599999,128046935.90480729,66350,1673.80400000,67202217.40755716,0 +1612641600000,40179.42000000,40179.42000000,39572.74000000,40087.40000000,4169.92339700,1612645199999,166198712.66538587,85476,2118.90035900,84468998.23157547,0 +1612645200000,40087.40000000,40250.00000000,40026.98000000,40028.19000000,2506.70206700,1612648799999,100621883.58426316,78962,1135.88883000,45596660.88473547,0 +1612648800000,40028.91000000,40469.19000000,39869.00000000,39992.77000000,2057.03210500,1612652399999,82644937.35575857,64952,1038.37131000,41738352.71705292,0 +1612652400000,39992.77000000,40083.86000000,39035.33000000,39186.94000000,5598.42579400,1612655999999,220517479.59955308,105797,2343.44747000,92285914.18750626,0 +1612656000000,39181.01000000,39611.04000000,38701.00000000,39564.17000000,4552.18409900,1612659599999,178542407.33143695,93465,1976.99804200,77615459.49756957,0 +1612659600000,39564.16000000,39588.90000000,38500.00000000,38627.36000000,4822.67221800,1612663199999,188375499.80254731,101064,2112.28431200,82610946.92491478,0 +1612663200000,38627.36000000,38820.00000000,38344.00000000,38747.31000000,4332.43097600,1612666799999,167276556.58820521,98932,2003.81349700,77383388.60306319,0 +1612666800000,38747.31000000,38926.58000000,38554.63000000,38841.46000000,2453.33738000,1612670399999,95079047.20114498,84838,1205.41446900,46718949.65173031,0 +1612670400000,38839.52000000,38839.52000000,37923.00000000,38312.99000000,4918.02111900,1612673999999,188621927.55185316,121762,2224.93175500,85416326.01581226,0 +1612674000000,38312.99000000,38692.04000000,38175.02000000,38511.00000000,2441.37048500,1612677599999,93822676.60161684,60173,1244.28011400,47824960.17905836,0 +1612677600000,38511.01000000,38700.00000000,38282.44000000,38531.35000000,2092.40306000,1612681199999,80635761.10435173,50410,1035.78810100,39915086.52709731,0 +1612681200000,38531.35000000,39094.36000000,38410.63000000,39030.00000000,3441.57032400,1612684799999,133713437.10999375,72600,1648.17198200,64043236.24602802,0 +1612684800000,39030.00000000,39529.00000000,39021.22000000,39496.96000000,3816.58070600,1612688399999,150114213.35314617,78481,2057.54242000,80939443.85233719,0 +1612688400000,39496.96000000,39700.00000000,39304.18000000,39513.92000000,2546.25168700,1612691999999,100566318.01428217,60075,1279.97857700,50558052.51961604,0 +1612692000000,39513.92000000,39658.04000000,39124.39000000,39331.42000000,3239.67694100,1612695599999,127508580.30409017,72901,1911.25912700,75210340.15890308,0 +1612695600000,39331.43000000,39358.00000000,38762.16000000,39046.60000000,3207.01430500,1612699199999,125201209.09617050,80558,1672.26608500,65284270.30592733,0 +1612699200000,39044.37000000,39272.69000000,38530.25000000,38820.87000000,3546.26063300,1612702799999,137643917.64609149,84468,1788.32781400,69429076.28582462,0 +1612702800000,38820.87000000,39119.47000000,38381.62000000,38629.26000000,3723.03824100,1612706399999,144194292.25096896,82493,1789.60439700,69307989.63849768,0 +1612706400000,38629.26000000,38700.00000000,38162.87000000,38214.98000000,3836.98198500,1612709999999,147453531.70169341,89438,1853.70646900,71253242.19345469,0 +1612710000000,38215.01000000,38395.26000000,37580.00000000,37921.11000000,6376.15806600,1612713599999,242026048.33180534,139577,2773.44817900,105268386.92469764,0 +1612713600000,37921.12000000,38244.50000000,37351.00000000,38185.72000000,6459.78356200,1612717199999,244040363.26502659,133648,3115.32024100,117743789.16913083,0 +1612717200000,38179.78000000,38208.60000000,37685.96000000,37870.62000000,2902.65676900,1612720799999,110346883.99433824,71482,1405.96995700,53447579.23303858,0 +1612720800000,37870.63000000,38342.88000000,37846.66000000,38239.10000000,2631.35331500,1612724399999,100278110.80744342,68332,1295.44204500,49365879.51053074,0 +1612724400000,38239.37000000,38444.00000000,37976.00000000,38050.00000000,2671.24633600,1612727999999,102309356.48609894,65691,1179.36978500,45180735.78622704,0 +1612728000000,38050.00000000,38492.82000000,37660.97000000,38471.95000000,2745.74401700,1612731599999,104501767.56806792,68446,1387.67585000,52833061.93097086,0 +1612731600000,38471.96000000,38635.42000000,38355.45000000,38530.33000000,2282.27472500,1612735199999,87851831.46733939,55575,1200.31639400,46205951.31578641,0 +1612735200000,38530.37000000,38832.99000000,38285.10000000,38797.02000000,2286.31583500,1612738799999,88111847.41554566,76519,1064.79476800,41051399.96729534,0 +1612738800000,38797.02000000,39080.00000000,38715.66000000,38795.69000000,3038.35297900,1612742399999,118305799.24735263,65429,1537.68457900,59875355.12639038,0 +1612742400000,38795.69000000,39130.00000000,38650.76000000,38725.40000000,3030.91878000,1612745999999,117791949.79313795,65167,1405.32997800,54617947.61118808,0 +1612746000000,38725.40000000,38909.95000000,38430.48000000,38521.72000000,2492.17365300,1612749599999,96312458.87905944,56830,1270.62993100,49106010.59596674,0 +1612749600000,38521.72000000,38650.00000000,38149.00000000,38249.00000000,2220.46382100,1612753199999,85280341.98126883,52010,1078.11386600,41407195.82047728,0 +1612753200000,38249.00000000,38497.50000000,37988.89000000,38076.06000000,2798.66060900,1612756799999,107131637.01042387,55513,1285.08646600,49207822.45467370,0 +1612756800000,38073.02000000,38684.21000000,37992.39000000,38584.70000000,2611.81627200,1612760399999,100519036.16207770,54037,1250.48586300,48124048.95702886,0 +1612760400000,38584.92000000,38872.00000000,38440.68000000,38677.47000000,2411.12876500,1612763999999,93241978.54774997,52341,1143.79146300,44227267.02963788,0 +1612764000000,38677.84000000,39233.39000000,38620.00000000,39012.69000000,2829.47296400,1612767599999,110342777.22582950,63244,1538.22857700,59996368.11071210,0 +1612767600000,39012.69000000,39391.78000000,38874.63000000,39269.95000000,2414.80194400,1612771199999,94595602.60556947,61747,1300.89253400,50966390.98282920,0 +1612771200000,39269.78000000,39349.56000000,39040.17000000,39175.38000000,2258.26449200,1612774799999,88500049.48902812,62080,1007.98681000,39500241.71163902,0 +1612774800000,39175.38000000,39364.77000000,38888.00000000,38954.27000000,2762.90216000,1612778399999,108076786.29721453,75447,1383.59556900,54126699.41096542,0 +1612778400000,38954.28000000,39450.10000000,38844.75000000,39418.71000000,3105.50345500,1612781999999,121624026.58701947,78008,1718.24311700,67305407.08201280,0 +1612782000000,39418.71000000,39498.99000000,39301.01000000,39423.08000000,2769.79507600,1612785599999,109144775.45251031,97377,1484.98658000,58517565.03905303,0 +1612785600000,39423.08000000,43231.10000000,39094.01000000,42984.07000000,13971.32848000,1612789199999,572303859.09169724,281022,8934.79634000,365535713.95395129,0 +1612789200000,42984.07000000,44918.00000000,41906.70000000,42897.12000000,21921.23645700,1612792799999,951254145.42218917,457654,11816.01984300,513017816.11132060,0 +1612792800000,42907.14000000,44057.94000000,42767.63000000,43558.73000000,11977.05863900,1612796399999,521038272.71814902,217634,6496.48940400,282657161.46136651,0 +1612796400000,43560.93000000,44164.74000000,43345.27000000,43716.32000000,9038.40695600,1612799999999,394966646.10916701,195838,4745.24468800,207432113.54493147,0 +1612800000000,43703.23000000,44280.00000000,43051.00000000,43170.24000000,8148.28728200,1612803599999,356060320.08012214,203787,3716.89390300,162371709.27085316,0 +1612803600000,43184.74000000,43418.39000000,42521.62000000,43079.07000000,5094.63397200,1612807199999,218820296.72776131,162393,2484.82238500,106741803.24217564,0 +1612807200000,43079.08000000,43397.02000000,42554.71000000,42673.49000000,3721.17821400,1612810799999,159805467.36965493,121696,1779.31882600,76420277.18409947,0 +1612810800000,42673.49000000,43140.29000000,42644.49000000,43051.95000000,2979.57181700,1612814399999,127868659.74062607,102328,1388.60700800,59603412.90703731,0 +1612814400000,43049.98000000,44350.00000000,42905.29000000,44151.07000000,6270.11109400,1612817999999,273096814.28266604,135972,2952.18884100,128686340.41412909,0 +1612818000000,44151.08000000,44799.58000000,43898.01000000,44632.41000000,6150.11080700,1612821599999,272426547.58067972,184914,3065.72219700,135879874.50597368,0 +1612821600000,44632.41000000,45034.48000000,44255.31000000,44682.76000000,5824.20366400,1612825199999,260330653.55861259,159797,3019.84577000,135105545.36924606,0 +1612825200000,44682.76000000,46794.45000000,44595.97000000,46374.87000000,11795.50754100,1612828799999,541003873.92348507,234125,6078.57160900,278759106.66986738,0 +1612828800000,46374.86000000,47498.00000000,46233.95000000,46768.22000000,10775.23109500,1612832399999,505274026.19963943,213817,5529.29043500,259330365.73344783,0 +1612832400000,46768.22000000,46770.61000000,45816.98000000,46158.97000000,7858.70160000,1612835999999,363311935.08453492,173087,3972.34052200,183578877.33859870,0 +1612836000000,46158.97000000,46348.96000000,45567.00000000,45707.38000000,4175.58615200,1612839599999,192023821.51698209,126347,2033.82809200,93527518.41809928,0 +1612839600000,45707.39000000,46750.00000000,45500.00000000,46599.51000000,4064.72925900,1612843199999,187934698.90951716,115209,2024.16391000,93590329.67704448,0 +1612843200000,46599.51000000,46888.00000000,46198.76000000,46837.57000000,3699.74339500,1612846799999,171897463.38680134,95864,1987.67055500,92367874.95742521,0 +1612846800000,46837.57000000,47219.13000000,46455.70000000,46850.12000000,4005.59749300,1612850399999,187582327.82090888,101403,2011.65750200,94230595.17602203,0 +1612850400000,46852.68000000,48140.90000000,46563.31000000,48111.18000000,6952.35579500,1612853999999,329510651.06549870,144340,4079.49401700,193431658.64145623,0 +1612854000000,48111.46000000,48142.19000000,47370.75000000,47505.40000000,5503.63622200,1612857599999,262512962.43176997,134510,2643.67907500,126098785.09148344,0 +1612857600000,47505.39000000,47928.23000000,46624.84000000,47109.51000000,6591.01341800,1612861199999,310754894.97243355,168396,3284.95261300,154951405.93493237,0 +1612861200000,47106.59000000,47160.00000000,46000.00000000,46401.30000000,4989.13460200,1612864799999,232243943.70862709,120413,2251.05362500,104878165.37866938,0 +1612864800000,46401.30000000,46588.00000000,45560.97000000,45641.77000000,4844.88605900,1612868399999,223420555.94472194,121039,2326.91117600,107370395.82193574,0 +1612868400000,45641.77000000,46683.18000000,45601.01000000,46380.92000000,3819.42801300,1612871999999,176260337.92535215,138954,2058.15398800,94979754.14789256,0 +1612872000000,46390.95000000,46806.41000000,45128.70000000,45300.17000000,5558.60425000,1612875599999,255693991.46305083,149422,2336.06912800,107407930.62631562,0 +1612875600000,45300.17000000,46425.00000000,44961.09000000,46285.14000000,6234.47110300,1612879199999,284785343.20588035,160509,2955.16842800,135015662.92702425,0 +1612879200000,46282.88000000,46700.00000000,46051.42000000,46624.44000000,3978.74752600,1612882799999,184275768.33181201,138195,1954.22864000,90517689.74133678,0 +1612882800000,46624.33000000,47083.84000000,46300.00000000,46773.63000000,5240.74903500,1612886399999,245141766.85935935,128932,2615.78801400,122361687.60946770,0 +1612886400000,46773.63000000,47110.72000000,46011.00000000,46470.85000000,4941.37082500,1612889999999,230199072.60440069,151285,2534.08989600,118083599.93105195,0 +1612890000000,46470.85000000,46940.91000000,46180.00000000,46483.67000000,3342.61264800,1612893599999,155501851.86611672,111222,1647.91334400,76675037.82333734,0 +1612893600000,46484.23000000,47433.78000000,46254.02000000,47012.77000000,4549.47911600,1612897199999,213785907.55947327,126534,2415.68949000,113522798.87660305,0 +1612897200000,47012.77000000,47289.28000000,46743.15000000,47060.18000000,2849.52535700,1612900799999,133860890.58155883,102956,1235.97484300,58082444.21378054,0 +1612900800000,47060.38000000,47499.43000000,46668.48000000,47084.17000000,3254.70271400,1612904399999,153225097.12674644,100788,1614.44070500,76019942.80397932,0 +1612904400000,47084.16000000,47461.06000000,46995.92000000,47231.03000000,2564.52493900,1612907999999,121109049.80527570,77433,1355.08328300,63994284.82557085,0 +1612908000000,47241.92000000,47241.92000000,46440.52000000,46839.01000000,2914.61431100,1612911599999,136314971.82543424,105273,1282.12154800,59976197.15951714,0 +1612911600000,46839.99000000,46860.00000000,46201.37000000,46420.42000000,2790.41678500,1612915199999,129634067.82129161,113106,1279.80151800,59458033.63681170,0 +1612915200000,46420.42000000,46900.00000000,46052.52000000,46517.64000000,3108.22494200,1612918799999,144725522.01661322,112724,1542.87810600,71867000.01282311,0 +1612918800000,46517.64000000,46533.52000000,45979.58000000,46259.97000000,3406.34784100,1612922399999,157491628.44145226,120124,1719.19236000,79491804.56903536,0 +1612922400000,46259.97000000,46800.00000000,46250.00000000,46276.51000000,3428.35059200,1612925999999,159414024.28492220,109913,1845.63178100,85821883.66758124,0 +1612926000000,46276.52000000,46743.87000000,46140.73000000,46221.07000000,3072.21766700,1612929599999,142503680.27006616,82996,1520.52985000,70536121.02378193,0 +1612929600000,46225.71000000,46319.03000000,45589.98000000,46020.40000000,4212.23625700,1612933199999,193184808.92330566,92361,2197.98082200,100796533.47325694,0 +1612933200000,46020.40000000,46424.93000000,45826.85000000,46131.99000000,2960.18055700,1612936799999,136653923.65983346,107677,1564.68467300,72237136.44424584,0 +1612936800000,46132.00000000,46650.00000000,46106.04000000,46510.25000000,2853.33957900,1612940399999,132540701.74792469,77526,1555.67686000,72262630.86099723,0 +1612940400000,46510.26000000,46944.07000000,46400.17000000,46563.69000000,3525.20422800,1612943999999,164394158.86926745,122297,1909.59152300,89062223.41210388,0 +1612944000000,46565.11000000,46844.59000000,46262.22000000,46668.89000000,3612.18762000,1612947599999,168046442.39707710,106493,2006.55363000,93370302.94057853,0 +1612947600000,46668.89000000,46900.00000000,46451.12000000,46550.00000000,3035.30548800,1612951199999,141776623.44097430,92272,1682.15254200,78565820.44870791,0 +1612951200000,46549.99000000,47310.00000000,46401.00000000,46630.17000000,4890.23204000,1612954799999,229342420.95511850,158998,2630.31290800,123370028.14241119,0 +1612954800000,46630.17000000,46691.94000000,46277.31000000,46586.56000000,2517.19374100,1612958399999,116999072.96833033,89683,1254.29354400,58304527.72301069,0 +1612958400000,46586.55000000,46593.34000000,44500.00000000,45652.34000000,9491.10542400,1612961999999,432642241.14381962,263732,4074.05066900,185753917.01434405,0 +1612962000000,45655.13000000,45969.28000000,45314.32000000,45626.32000000,5201.63471400,1612965599999,237517282.99456999,194463,2349.74776400,107321228.71241677,0 +1612965600000,45626.32000000,45988.20000000,44800.00000000,44954.12000000,5933.22736600,1612969199999,269001701.01912217,175733,2548.21964900,115623932.20685685,0 +1612969200000,44954.13000000,45227.27000000,43727.00000000,44353.04000000,9617.54060300,1612972799999,427486353.98836603,221857,4388.63303100,195152081.04264996,0 +1612972800000,44354.50000000,44900.00000000,43800.00000000,44746.66000000,5766.03991500,1612976399999,256477173.20488165,151805,2880.80272100,128170383.52477059,0 +1612976400000,44746.65000000,45071.45000000,44446.12000000,44963.31000000,3576.59790300,1612979999999,160245092.08724017,98294,1757.53643000,78745423.38097770,0 +1612980000000,44963.32000000,45200.00000000,44731.74000000,45088.17000000,3335.95103300,1612983599999,150232868.90680044,88939,1705.41583300,76814403.81694472,0 +1612983600000,45088.16000000,45239.98000000,44450.10000000,45190.05000000,3638.89731700,1612987199999,163302568.75371586,98852,1867.24189600,83813850.26899005,0 +1612987200000,45190.05000000,45240.70000000,44400.00000000,44555.59000000,2929.85296300,1612990799999,131336678.83683750,96105,1473.61305600,66060274.38136047,0 +1612990800000,44555.59000000,45028.15000000,44355.00000000,44999.09000000,2811.10407300,1612994399999,125539701.96718489,92892,1460.22626400,65229667.60533560,0 +1612994400000,44999.09000000,45216.49000000,44880.00000000,45199.99000000,1698.33418500,1612997999999,76570446.67516731,64905,851.45837300,38392700.75485535,0 +1612998000000,45200.00000000,45322.09000000,44769.88000000,44807.58000000,2532.87615200,1613001599999,114225012.69851429,70951,1185.56144600,53467363.38955074,0 +1613001600000,44807.58000000,45051.27000000,43994.02000000,44250.00000000,4145.40034300,1613005199999,184540982.07683789,117432,1904.41791700,84814761.28277238,0 +1613005200000,44250.00000000,44554.91000000,44010.88000000,44180.86000000,2791.70519700,1613008799999,123757289.11946866,78789,1479.85382600,65613379.02573939,0 +1613008800000,44180.08000000,44698.15000000,44172.57000000,44582.07000000,825.57125600,1613012399999,36756000.90767989,26744,451.86218000,20120073.75826733,0 +1613012400000,44582.07000000,44582.07000000,44582.07000000,44582.07000000,0.00000000,1613014854773,0.00000000,0,0.00000000,0.00000000,0 +1613019600000,44583.71000000,44999.00000000,44507.00000000,44641.72000000,2359.40984600,1613023199999,105586295.71125404,86586,1214.65927000,54364467.84916051,0 +1613023200000,44641.71000000,44918.19000000,44397.62000000,44559.99000000,2121.32005100,1613026799999,94729253.67138495,79025,1003.91767600,44836209.59223975,0 +1613026800000,44559.98000000,45129.59000000,44559.98000000,44700.01000000,2885.69503200,1613030399999,129648498.38039203,89906,1407.53347700,63245537.87999281,0 +1613030400000,44700.00000000,45095.49000000,44500.00000000,45017.02000000,2819.24106000,1613033999999,126257309.41883641,92734,1326.30392500,59424263.51177562,0 +1613034000000,45017.01000000,45609.16000000,44789.11000000,45500.98000000,3446.63083900,1613037599999,155601476.56576339,110310,1918.32236700,86632857.71743990,0 +1613037600000,45500.98000000,46377.44000000,45351.00000000,46279.80000000,4555.92155500,1613041199999,208521388.03699547,126846,2348.48315000,107573294.34162350,0 +1613041200000,46279.81000000,46546.47000000,45864.40000000,46061.49000000,4197.20832600,1613044799999,194027754.66724067,114423,2146.81190300,99264614.59968872,0 +1613044800000,46061.48000000,46625.83000000,46060.03000000,46516.39000000,3578.10764600,1613048399999,166014983.80997793,107617,1911.35190000,88689856.29531453,0 +1613048400000,46516.39000000,48399.00000000,46516.39000000,47555.46000000,13364.20517400,1613051999999,637152612.73289668,324269,7688.28214100,366593968.29226558,0 +1613052000000,47555.46000000,48100.00000000,47233.00000000,47864.81000000,5336.00574200,1613055599999,254515475.14724918,123624,2975.85510800,142002750.77037891,0 +1613055600000,47864.81000000,48185.26000000,47576.58000000,47960.85000000,4946.07776600,1613059199999,236862476.03094766,119640,2504.23152600,119978280.81114286,0 +1613059200000,47960.86000000,48298.00000000,47337.18000000,47590.53000000,4852.40756700,1613062799999,231886502.35895781,141567,2439.47310500,116635147.37799019,0 +1613062800000,47590.52000000,47666.97000000,46900.00000000,47366.42000000,3618.16439500,1613066399999,171070096.78908613,135155,1838.15493600,86918626.85669068,0 +1613066400000,47366.43000000,48010.54000000,47311.01000000,47653.14000000,3425.20414100,1613069999999,163336518.84669500,99995,1817.68629600,86691755.25250974,0 +1613070000000,47653.15000000,48050.00000000,47526.28000000,47754.03000000,3150.42137400,1613073599999,150798893.31631415,117847,1697.15669100,81247929.12738847,0 +1613073600000,47754.02000000,48678.90000000,47000.00000000,47027.49000000,6204.93255600,1613077199999,297302565.32965942,158483,3139.16955400,150593641.83827483,0 +1613077200000,47027.49000000,47360.00000000,46542.29000000,46884.84000000,5079.47740900,1613080799999,238541749.49237101,120266,2142.97912700,100644373.61292273,0 +1613080800000,46885.07000000,47727.37000000,46864.32000000,47712.94000000,2820.02394000,1613084399999,133425727.90695118,93877,1198.92751600,56726849.65012410,0 +1613084400000,47716.44000000,48125.58000000,47588.65000000,47969.51000000,3037.95023900,1613087999999,145297084.09393544,105814,1582.90314900,75723283.24862085,0 +1613088000000,47968.66000000,48985.80000000,47770.58000000,47990.00000000,6786.70764900,1613091599999,329105189.36083577,175069,3930.51515200,190667676.28566924,0 +1613091600000,47990.01000000,48550.00000000,47721.00000000,48477.50000000,2957.11592700,1613095199999,142466595.59612409,105150,1480.42190600,71327147.29041160,0 +1613095200000,48477.51000000,48477.51000000,47729.68000000,47935.66000000,3206.02141300,1613098799999,154268952.43159719,74731,1822.37443500,87715348.27697328,0 +1613098800000,47935.66000000,47988.49000000,47338.35000000,47587.31000000,2471.16246300,1613102399999,117791339.87269018,63708,1208.91740300,57630517.38636812,0 +1613102400000,47587.31000000,47587.31000000,46888.00000000,47271.55000000,4724.62151100,1613105999999,222878560.54100781,107423,1903.44237500,89819256.58668268,0 +1613106000000,47271.54000000,47506.44000000,47086.30000000,47257.09000000,3397.95599300,1613109599999,160812548.46313150,106915,1574.90293200,74536014.38939227,0 +1613109600000,47257.09000000,47551.02000000,46789.00000000,47380.16000000,3483.71169900,1613113199999,164362658.90442514,76561,1608.66549000,75927489.29698522,0 +1613113200000,47380.15000000,47475.00000000,46903.48000000,47318.81000000,2921.00849600,1613116799999,137891961.65193392,91205,1393.99899500,65806393.93410295,0 +1613116800000,47318.02000000,47700.00000000,47080.00000000,47117.86000000,3406.82443700,1613120399999,161434280.11324426,117079,1710.78602000,81083052.15607194,0 +1613120400000,47117.86000000,47400.00000000,47027.03000000,47337.00000000,2666.71850100,1613123999999,125893980.83818209,81497,1408.75366400,66512693.47278401,0 +1613124000000,47337.01000000,47711.00000000,47300.00000000,47381.16000000,2710.45776600,1613127599999,128709097.20287873,80154,1401.97785500,66577186.87763223,0 +1613127600000,47371.80000000,47999.00000000,47280.26000000,47562.42000000,2966.76718800,1613131199999,141273408.13448735,94784,1618.78663200,77094280.58199452,0 +1613131200000,47560.06000000,47957.87000000,47323.61000000,47669.82000000,2999.82626000,1613134799999,142971083.26918040,86565,1467.96618900,69950703.40792844,0 +1613134800000,47669.82000000,48140.00000000,47646.00000000,47871.40000000,3795.08650900,1613138399999,181852482.15911031,84014,1925.30539400,92274673.39796593,0 +1613138400000,47871.40000000,47878.74000000,46125.00000000,46547.50000000,8109.95056100,1613141999999,380438580.18828964,168342,3066.37777800,143817140.78583088,0 +1613142000000,46542.60000000,47163.83000000,46525.25000000,47021.05000000,4791.74044800,1613145599999,224732107.80397928,115458,1965.07758000,92158450.76053785,0 +1613145600000,47021.05000000,47980.00000000,47008.40000000,47614.40000000,4632.35856400,1613149199999,220200748.80202655,129365,2507.52307800,119186545.04986801,0 +1613149200000,47612.52000000,47905.00000000,47459.78000000,47713.82000000,3375.04444900,1613152799999,160965420.00114915,108069,1770.45632500,84446523.78661901,0 +1613152800000,47713.83000000,47800.00000000,46915.32000000,47269.25000000,3866.28210200,1613156399999,183170674.50725803,113771,1898.85694800,89979243.50280463,0 +1613156400000,47268.27000000,47453.99000000,47086.32000000,47272.95000000,2344.98428900,1613159999999,110886680.18908771,82297,1039.97103000,49174105.69542646,0 +1613160000000,47272.96000000,47653.24000000,47140.26000000,47577.49000000,2591.14661000,1613163599999,122865293.60086744,77868,1176.03708800,55773960.77881402,0 +1613163600000,47577.49000000,48150.00000000,47560.01000000,47860.54000000,3556.84785500,1613167199999,170105117.73034401,106653,2100.01068700,100478479.98683872,0 +1613167200000,47860.75000000,47930.00000000,47602.71000000,47841.17000000,1481.56351100,1613170799999,70786383.61192161,82449,719.21218600,34362470.58815187,0 +1613170800000,47841.16000000,47870.00000000,47155.00000000,47287.60000000,2626.13149600,1613174399999,124708763.99390937,89714,1140.70199300,54173564.65273099,0 +1613174400000,47298.15000000,47587.29000000,47200.00000000,47459.54000000,2749.95842900,1613177999999,130278520.79639110,77928,1566.45178000,74203799.38910789,0 +1613178000000,47459.53000000,47799.61000000,47412.40000000,47626.98000000,2409.97375700,1613181599999,114842069.79136774,71635,1311.32682200,62494134.92434280,0 +1613181600000,47629.76000000,47944.84000000,47503.57000000,47839.77000000,2036.99045900,1613185199999,97207665.40260089,68481,1087.68647100,51913065.01987237,0 +1613185200000,47839.77000000,48150.00000000,47693.44000000,47829.22000000,2448.08022500,1613188799999,117199433.02362883,82095,1285.27154500,61544937.37874067,0 +1613188800000,47829.21000000,47924.86000000,47598.89000000,47904.70000000,1983.56289600,1613192399999,94728852.94530847,55291,965.42736900,46111202.15620792,0 +1613192400000,47904.69000000,47934.14000000,47397.71000000,47888.00000000,2604.32470700,1613195999999,124213425.66935890,72837,1212.44352100,57843107.35586879,0 +1613196000000,47887.99000000,47922.22000000,47483.88000000,47728.26000000,2058.77855700,1613199599999,98127246.97414455,93121,984.58164000,46924695.75272914,0 +1613199600000,47728.25000000,47794.36000000,46990.00000000,46995.72000000,3084.23424400,1613203199999,146077668.02093981,117815,1287.87213300,61025205.75170483,0 +1613203200000,46995.01000000,47499.93000000,46618.00000000,47429.93000000,3749.61188800,1613206799999,176778974.61905360,124648,1694.46254100,79890639.41544427,0 +1613206800000,47429.92000000,47569.03000000,47061.00000000,47205.53000000,2095.84243100,1613210399999,99205007.00637642,74304,1002.36347400,47448456.22309443,0 +1613210400000,47205.52000000,47266.05000000,46660.44000000,46709.17000000,4954.58299000,1613213999999,233121108.64482687,121839,2391.40789300,112553293.58607895,0 +1613214000000,46700.77000000,46990.00000000,46251.00000000,46589.20000000,5399.86052400,1613217599999,251729345.47012649,162522,2340.43296000,109125918.11598543,0 +1613217600000,46586.23000000,47209.25000000,46202.53000000,46879.81000000,3800.32361700,1613221199999,178158136.50656325,104894,1841.05206600,86339763.83543092,0 +1613221200000,46879.81000000,47150.22000000,46557.56000000,46971.43000000,3446.30427500,1613224799999,161654009.80683459,89740,1598.69823200,74991594.07773369,0 +1613224800000,46971.43000000,47044.04000000,46596.37000000,46946.90000000,2508.59132200,1613228399999,117432469.88562899,77718,1205.10570800,56417225.26116503,0 +1613228400000,46946.67000000,47300.00000000,46883.03000000,47076.01000000,2933.38704900,1613231999999,138289031.88103748,91046,1488.39878900,70165043.71039798,0 +1613232000000,47076.02000000,47400.14000000,46864.48000000,47136.89000000,2729.09808200,1613235599999,128649056.46212938,95531,1340.14111000,63181395.35727337,0 +1613235600000,47136.90000000,47190.00000000,46735.83000000,46855.24000000,2308.46806600,1613239199999,108463214.98842457,88653,1097.42261900,51564386.74235221,0 +1613239200000,46855.23000000,47022.26000000,46738.24000000,46792.05000000,1858.54608200,1613242799999,87151435.42899831,64903,868.04645200,40703558.81344678,0 +1613242800000,46790.39000000,47086.92000000,46708.94000000,46870.15000000,1771.33522700,1613246399999,83072851.52190488,60723,890.09556700,41744449.53535929,0 +1613246400000,46871.95000000,46967.07000000,46653.58000000,46934.06000000,1644.41918400,1613249999999,76962780.36939968,67842,788.68050300,36916583.01501596,0 +1613250000000,46934.07000000,47397.36000000,46700.38000000,47130.82000000,2224.29458700,1613253599999,104527195.39377084,75907,1206.90256000,56721826.58286662,0 +1613253600000,47132.94000000,47280.26000000,46863.63000000,47058.88000000,1292.72461900,1613257199999,60850363.11643882,59844,658.48701600,30999765.17969414,0 +1613257200000,47058.88000000,47300.00000000,47001.01000000,47153.69000000,1674.80418200,1613260799999,78990283.69290518,59506,883.55108800,41671352.81289809,0 +1613260800000,47156.78000000,47695.18000000,47014.17000000,47594.52000000,3370.18172200,1613264399999,160032955.65323055,95072,1734.65904500,82366268.62512580,0 +1613264400000,47594.52000000,47730.00000000,47244.88000000,47471.23000000,2800.47480100,1613267999999,132999504.11235503,67516,1710.55626200,81204830.58789642,0 +1613268000000,47475.25000000,47630.00000000,47291.13000000,47378.87000000,2140.96333100,1613271599999,101622478.66020674,57822,1211.58630600,57492350.30306380,0 +1613271600000,47378.87000000,47498.74000000,47204.98000000,47267.21000000,1924.99107300,1613275199999,91249019.54804192,58965,927.09967600,43945003.00081581,0 +1613275200000,47267.20000000,47650.62000000,47220.42000000,47551.25000000,2140.73755600,1613278799999,101552135.18153622,52242,1074.74995400,50989392.76741221,0 +1613278800000,47551.25000000,48948.00000000,47497.39000000,48929.18000000,6249.80455200,1613282399999,301375915.99620004,131926,3706.82603800,178767898.79206442,0 +1613282400000,48929.18000000,49404.94000000,48505.69000000,48745.29000000,7730.20751900,1613285999999,378819096.25902371,160941,4662.70506500,228584464.44144215,0 +1613286000000,48745.28000000,49082.33000000,48520.00000000,48725.18000000,2672.89422700,1613289599999,130304315.88334336,69579,1434.03799200,69918747.44310697,0 +1613289600000,48725.18000000,49018.37000000,48389.55000000,48710.17000000,2764.14148200,1613293199999,134723038.64918590,72737,1302.98777200,63516711.13205439,0 +1613293200000,48710.17000000,49190.00000000,48610.86000000,49134.33000000,2619.21635100,1613296799999,128149093.37750377,77494,1396.10610700,68307128.74014529,0 +1613296800000,49133.33000000,49349.76000000,48956.26000000,49024.21000000,3537.81887900,1613300399999,173925503.24158430,95745,1723.57184000,84747677.06129399,0 +1613300400000,49024.22000000,49139.38000000,48750.59000000,49055.16000000,2377.25319500,1613303999999,116408121.81640217,82683,1258.21308700,61615133.62091801,0 +1613304000000,49055.17000000,49707.43000000,48999.57000000,49436.86000000,5146.83708100,1613307599999,254304722.44098076,151305,2837.71034800,140208067.90938001,0 +1613307600000,49434.05000000,49578.67000000,48550.00000000,48759.63000000,4143.32885900,1613311199999,203312553.42023441,131420,2040.23217900,100115403.51998615,0 +1613311200000,48759.62000000,49069.37000000,48449.76000000,48757.38000000,3279.61955400,1613314799999,160075756.54762092,107053,1583.16150000,77293478.27289885,0 +1613314800000,48757.39000000,48943.47000000,48101.38000000,48541.18000000,3668.24824000,1613318399999,177837037.04234682,112627,1709.34223800,82874968.43423887,0 +1613318400000,48537.96000000,49075.43000000,48424.66000000,49006.74000000,3211.72195400,1613321999999,156577943.29069835,93272,1530.41261100,74629271.28910978,0 +1613322000000,49005.01000000,49100.00000000,48587.00000000,48619.19000000,2166.34239900,1613325599999,105859597.96267876,68456,1094.63271900,53494133.23952528,0 +1613325600000,48619.20000000,48819.29000000,48400.31000000,48739.99000000,2031.32711600,1613329199999,98756144.55389657,62016,907.81514100,44137657.01786330,0 +1613329200000,48739.99000000,48919.86000000,48479.80000000,48693.39000000,1647.87755700,1613332799999,80279379.08039663,72367,807.65119300,39354820.47381999,0 +1613332800000,48693.38000000,49000.00000000,48600.00000000,48929.50000000,1775.36510500,1613336399999,86734312.94108836,63113,894.33528500,43699748.92437283,0 +1613336400000,48929.50000000,49058.74000000,48755.47000000,48822.66000000,1772.35823100,1613339999999,86671621.44494648,54000,883.63964700,43214284.61624973,0 +1613340000000,48822.67000000,49300.00000000,48706.53000000,49012.94000000,1875.45012600,1613343599999,91999378.96832099,85508,1060.56203400,52031437.88633010,0 +1613343600000,49012.94000000,49094.71000000,48505.79000000,48577.79000000,2688.31462300,1613347199999,131238722.76290996,66211,1259.56264200,61501042.96374648,0 +1613347200000,48580.47000000,49010.92000000,48428.00000000,48763.62000000,2016.44349500,1613350799999,98237902.75557831,81903,970.97984000,47312216.92817248,0 +1613350800000,48763.79000000,48816.62000000,47700.00000000,48011.44000000,4889.30019600,1613354399999,235426059.12818572,137267,2002.07846900,96414045.04540308,0 +1613354400000,48011.45000000,48213.83000000,45570.79000000,46874.02000000,11217.85149100,1613357999999,524402408.59355430,293802,4766.42986400,222833708.12581665,0 +1613358000000,46874.01000000,47269.09000000,46540.67000000,47120.30000000,4188.45200300,1613361599999,196816109.46067822,130430,1999.77789900,93986906.83760872,0 +1613361600000,47120.31000000,47136.02000000,46174.78000000,46866.57000000,4963.73452400,1613365199999,231640212.72911710,117265,2555.71418300,119198071.11229076,0 +1613365200000,46866.56000000,47000.00000000,46400.00000000,46722.49000000,2939.43039800,1613368799999,137310368.09635524,80552,1310.16549500,61211676.80102441,0 +1613368800000,46722.48000000,47140.00000000,46683.02000000,46887.36000000,2622.53921200,1613372399999,123158432.47353344,89824,1244.34040700,58439504.94655495,0 +1613372400000,46887.36000000,47441.02000000,46831.61000000,47267.06000000,2861.55980200,1613375999999,135181501.07298136,82240,1418.34999000,66996900.89167774,0 +1613376000000,47270.50000000,47772.00000000,47112.38000000,47599.99000000,2821.99134500,1613379599999,133918267.12457979,77978,1474.81929500,69985910.06565023,0 +1613379600000,47600.00000000,47724.64000000,47201.27000000,47505.66000000,3001.82932500,1613383199999,142576622.11924442,70082,1336.05093400,63455178.90359955,0 +1613383200000,47505.67000000,47888.00000000,47306.02000000,47849.99000000,2326.61287800,1613386799999,110656982.90530200,66156,1225.88465300,58304856.58190226,0 +1613386800000,47849.99000000,47999.00000000,47606.86000000,47802.66000000,2660.67096300,1613390399999,127203238.52893592,74332,1418.00170400,67791449.65179393,0 +1613390400000,47802.67000000,48070.00000000,47423.99000000,47951.01000000,3213.28005900,1613393999999,153304036.36698223,104794,1786.62064300,85274876.78427529,0 +1613394000000,47951.01000000,48219.23000000,47800.00000000,47960.73000000,3089.86453000,1613397599999,148366647.54025140,85788,1552.52546000,74543834.55454221,0 +1613397600000,47963.69000000,48150.62000000,47472.92000000,47564.16000000,3063.76672800,1613401199999,146519643.89369118,95741,1404.41439300,67177057.01943177,0 +1613401200000,47563.58000000,48000.00000000,47536.15000000,47938.83000000,2186.45038100,1613404799999,104527719.43185056,85613,1123.12360200,53693402.18585358,0 +1613404800000,47938.84000000,48570.75000000,47938.83000000,48494.96000000,3853.34875200,1613408399999,186222808.78934653,103731,1884.57664300,91076615.48945923,0 +1613408400000,48494.97000000,48800.00000000,48399.23000000,48562.31000000,2723.91403300,1613411999999,132525799.34526871,76332,1428.76456100,69514104.07326134,0 +1613412000000,48562.31000000,48698.52000000,48342.22000000,48358.99000000,2040.89843400,1613415599999,99038423.24332974,61154,989.97802200,48044410.01409379,0 +1613415600000,48361.00000000,48742.52000000,48354.78000000,48657.31000000,1945.42837200,1613419199999,94501180.34830712,59582,916.64489600,44527266.70598173,0 +1613419200000,48657.31000000,48801.00000000,48453.87000000,48580.99000000,3063.15339900,1613422799999,149075816.14749957,63704,1527.09219800,74328482.70080645,0 +1613422800000,48581.00000000,48750.00000000,48111.11000000,48207.54000000,2767.08275300,1613426399999,134028984.37812317,92043,1369.70711600,66345240.81797496,0 +1613426400000,48201.18000000,48334.23000000,47643.00000000,48284.89000000,2835.28984100,1613429999999,136203912.55939989,121233,1430.73997500,68737085.23889682,0 +1613430000000,48284.90000000,48432.73000000,47809.99000000,47911.10000000,2105.26387000,1613433599999,101375983.63262613,61609,1039.58441900,50058854.30535513,0 +1613433600000,47911.10000000,47958.40000000,47003.62000000,47669.02000000,4446.88263000,1613437199999,211520110.56438769,108138,2122.75194600,100966633.97327281,0 +1613437200000,47669.03000000,48319.33000000,47605.96000000,48305.28000000,2586.10856200,1613440799999,124140059.17193203,67535,1216.07506400,58379943.95026175,0 +1613440800000,48305.28000000,48689.25000000,48160.12000000,48442.06000000,2292.25947100,1613444399999,110969746.49352592,63661,1089.98428200,52782871.21542479,0 +1613444400000,48442.05000000,49670.00000000,48405.11000000,49624.03000000,5795.63915500,1613447999999,285488361.36382928,137535,3567.26065500,175740321.90302698,0 +1613448000000,49624.02000000,49998.00000000,49068.41000000,49350.01000000,5457.71299300,1613451599999,270563379.05828514,122195,3072.70896700,152415970.66421239,0 +1613451600000,49350.01000000,49500.00000000,48969.00000000,49179.03000000,2937.10233400,1613455199999,144638880.08477047,68720,1646.53586000,81086283.97363601,0 +1613455200000,49179.04000000,49234.70000000,48550.00000000,49023.74000000,3291.76102900,1613458799999,160999597.65167020,75160,1568.79066800,76747021.12143053,0 +1613458800000,49020.91000000,49281.81000000,48609.90000000,49163.46000000,2651.26426400,1613462399999,129833533.79377934,69430,1286.37114400,63015986.21663588,0 +1613462400000,49161.75000000,49300.00000000,48871.20000000,49293.26000000,2651.81617900,1613465999999,130244759.29780029,70945,1542.70007700,75782998.80271560,0 +1613466000000,49289.75000000,49318.47000000,48900.00000000,49283.30000000,2177.75779000,1613469599999,106976494.62458385,59616,1187.27631800,58344890.18167947,0 +1613469600000,49283.30000000,49318.47000000,48750.09000000,49020.00000000,2241.00369300,1613473199999,109964695.63731140,59947,1066.06133300,52317017.13588433,0 +1613473200000,49020.00000000,49114.68000000,48700.00000000,48915.48000000,2048.97807800,1613476799999,100241550.94394563,63385,988.91973900,48385685.98339005,0 +1613476800000,48915.49000000,50689.18000000,48403.21000000,49650.01000000,14737.10386500,1613480399999,732384592.48279260,309032,8496.06546800,422705966.11879982,0 +1613480400000,49650.00000000,49826.12000000,48862.99000000,48950.89000000,5108.59246500,1613483999999,251611466.30664461,114976,2372.89496000,116899397.76024331,0 +1613484000000,48950.89000000,49457.00000000,48700.00000000,49289.40000000,4348.89993700,1613487599999,213452078.27008461,110414,2002.83939900,98336603.68360024,0 +1613487600000,49286.80000000,49509.84000000,48935.70000000,48956.91000000,3296.49630900,1613491199999,162347104.02420421,79948,1553.28754100,76503999.81067586,0 +1613491200000,48956.91000000,49291.00000000,48073.00000000,48167.68000000,4643.95192900,1613494799999,226315620.09887102,123288,2097.96977400,102287785.73942366,0 +1613494800000,48165.07000000,48618.60000000,48128.81000000,48230.50000000,3626.44968800,1613498399999,175494885.18182849,91405,1834.78778100,88797433.14423107,0 +1613498400000,48230.63000000,48692.10000000,47750.00000000,48616.79000000,4046.88939600,1613501999999,195127956.52220223,104643,1798.04174900,86746114.81986579,0 +1613502000000,48616.79000000,48800.42000000,48340.14000000,48537.39000000,1898.84599200,1613505599999,92258235.99179017,57825,939.27966900,45638140.85655053,0 +1613505600000,48536.35000000,48784.29000000,48173.81000000,48769.27000000,2584.41782600,1613509199999,125224973.58411438,72638,1170.40579800,56713941.58012348,0 +1613509200000,48769.28000000,48809.09000000,48355.80000000,48575.07000000,2220.45870700,1613512799999,107864262.87435384,59586,983.15925800,47748809.49058261,0 +1613512800000,48575.06000000,49180.00000000,48524.65000000,49108.68000000,1763.41221300,1613516399999,86066130.65612859,55227,976.92044400,47698669.49893138,0 +1613516400000,49113.91000000,49290.00000000,48933.33000000,49133.45000000,1959.46179300,1613519999999,96255303.01353128,54600,1027.51594400,50482117.36375763,0 +1613520000000,49133.45000000,49566.66000000,49034.35000000,49079.99000000,2890.37085800,1613523599999,142739155.81647983,71248,1555.49541700,76827486.69299600,0 +1613523600000,49079.99000000,49417.25000000,48947.00000000,49282.80000000,1693.38424600,1613527199999,83381268.34242158,50936,894.15892400,44030913.38943179,0 +1613527200000,49283.14000000,50274.88000000,49268.42000000,49654.89000000,4959.60353500,1613530799999,247368994.85793249,115010,2814.90641900,140400743.28110094,0 +1613530800000,49657.54000000,49759.46000000,49231.09000000,49657.38000000,2563.13435700,1613534399999,126902933.72016300,71106,1306.00954100,64665779.25825580,0 +1613534400000,49657.84000000,49963.40000000,49106.75000000,49345.38000000,3012.37512700,1613537999999,149086045.25660271,77807,1468.62868400,72710985.70366317,0 +1613538000000,49345.39000000,49731.03000000,49227.68000000,49706.80000000,2239.28153900,1613541599999,110753762.97523999,64527,1004.11886300,49672597.69420271,0 +1613541600000,49706.80000000,50677.58000000,49624.06000000,50556.05000000,6397.97406700,1613545199999,321370364.39629328,147819,3592.32335300,180474031.33095040,0 +1613545200000,50556.15000000,51266.09000000,50200.00000000,51112.39000000,6735.57496700,1613548799999,342035834.26117668,193718,3793.02344700,192682135.76784413,0 +1613548800000,51116.77000000,51300.00000000,50628.58000000,51031.71000000,4279.62119300,1613552399999,217886860.01050137,149891,2251.72981700,114644447.26451840,0 +1613552400000,51031.71000000,51678.36000000,50991.69000000,51431.04000000,5578.73201700,1613555999999,286611008.96667963,162052,3286.03457000,168840616.15725178,0 +1613556000000,51436.11000000,51612.80000000,50995.00000000,51192.00000000,3569.37083300,1613559599999,183265198.81630454,131463,1754.58633900,90096143.57606315,0 +1613559600000,51192.00000000,51675.55000000,51101.07000000,51273.46000000,3178.17850300,1613563199999,163389326.95798126,140591,1725.82996200,88728208.71586878,0 +1613563200000,51270.86000000,51530.00000000,50777.20000000,51039.56000000,4448.57671200,1613566799999,227775681.68139399,137066,2205.98423700,112968102.53606598,0 +1613566800000,51039.56000000,51234.00000000,50542.30000000,51149.96000000,4231.90257000,1613570399999,215340528.89268039,100049,2143.90030700,109100848.01972300,0 +1613570400000,51149.97000000,51284.78000000,50770.82000000,51262.00000000,4229.88726300,1613573999999,215714255.19115635,99421,2185.30842600,111440510.05745384,0 +1613574000000,51262.01000000,51633.17000000,50968.87000000,51169.97000000,3226.68134900,1613577599999,165434598.21261716,90598,1673.88891600,85838931.40725455,0 +1613577600000,51169.97000000,51435.09000000,50780.00000000,51241.35000000,3213.60820100,1613581199999,164123126.33986162,87698,1432.19251200,73147635.88257750,0 +1613581200000,51241.35000000,51436.00000000,51085.95000000,51376.85000000,2383.38491000,1613584799999,122173286.38895154,70006,1248.79755800,64017785.26346042,0 +1613584800000,51380.78000000,51780.00000000,51304.96000000,51430.59000000,2455.34674600,1613588399999,126498176.77004941,73853,1417.98176100,73061493.41716664,0 +1613588400000,51430.59000000,52395.00000000,51374.56000000,52142.35000000,4887.84160900,1613591999999,254172782.78805094,119808,2674.02247500,139072940.34043922,0 +1613592000000,52142.36000000,52546.00000000,51956.82000000,52240.00000000,3160.98879700,1613595599999,165159364.15775175,101344,1673.49947700,87431344.98006769,0 +1613595600000,52239.99000000,52618.74000000,52021.37000000,52349.99000000,2544.38664700,1613599199999,133129592.23551998,111942,1217.13865500,63694297.65795707,0 +1613599200000,52349.99000000,52381.20000000,51893.34000000,52104.43000000,1961.28032700,1613602799999,102283994.68977260,66116,794.14230000,41419168.94664244,0 +1613602800000,52104.44000000,52397.84000000,51899.64000000,52119.71000000,1902.15144500,1613606399999,99235373.08971611,80305,941.74428100,49132087.93906716,0 +1613606400000,52117.67000000,52530.00000000,52104.69000000,52267.32000000,2415.71188100,1613609999999,126462808.59351453,68990,1184.67427600,62020150.22809579,0 +1613610000000,52263.85000000,52383.42000000,52026.06000000,52132.46000000,3038.62669900,1613613599999,158563091.46887272,83050,1497.39017600,78141903.88477890,0 +1613613600000,52132.47000000,52340.01000000,51933.24000000,52318.89000000,2290.19600500,1613617199999,119421691.26987759,79558,1076.65023200,56149947.94241353,0 +1613617200000,52318.89000000,52399.73000000,51951.00000000,52032.64000000,1876.43842400,1613620799999,97826861.30463848,70318,795.66203000,41494969.72859426,0 +1613620800000,52032.64000000,52180.00000000,51712.50000000,52153.36000000,2402.28846800,1613624399999,124762052.22122244,96640,1167.56278400,60643202.97179693,0 +1613624400000,52153.36000000,52298.00000000,52015.68000000,52170.01000000,1777.76259300,1613627999999,92719155.23415250,66549,833.81447800,43490476.29551979,0 +1613628000000,52170.02000000,52237.45000000,51862.78000000,51905.66000000,1952.33030800,1613631599999,101615004.47725443,53661,921.28408400,47950239.42759454,0 +1613631600000,51905.65000000,52085.85000000,51295.00000000,51901.96000000,4482.23840700,1613635199999,231492219.32012465,104998,2082.11648600,107551721.11270122,0 +1613635200000,51901.95000000,52168.75000000,51542.32000000,51706.88000000,2314.54402300,1613638799999,119941863.11582020,102125,1221.34767500,63298289.53003857,0 +1613638800000,51706.87000000,51873.41000000,51459.82000000,51770.99000000,2754.16149000,1613642399999,142340212.09189810,72873,1209.01340100,62464981.94171498,0 +1613642400000,51772.82000000,52000.00000000,51529.20000000,51643.50000000,2180.56772900,1613645999999,112913519.80171945,62181,1050.33611300,54397716.66662668,0 +1613646000000,51643.49000000,51720.32000000,51133.00000000,51374.07000000,3329.97338200,1613649599999,171274319.05293026,87957,1690.23063800,86927479.69519652,0 +1613649600000,51375.12000000,51623.37000000,50901.90000000,51464.66000000,3689.59965300,1613653199999,189054669.44080802,139022,1548.14890500,79378801.25721558,0 +1613653200000,51464.67000000,52025.00000000,51262.43000000,51796.24000000,3004.84490300,1613656799999,155300530.92317071,101151,1397.34176400,72231807.92522654,0 +1613656800000,51796.24000000,52285.00000000,51613.23000000,52233.43000000,2980.96917900,1613660399999,154938085.17949990,97995,1450.31815300,75397809.46952058,0 +1613660400000,52233.43000000,52260.00000000,51450.00000000,51585.29000000,3418.73399100,1613663999999,176937329.82928261,87026,1656.39480100,85726936.09436358,0 +1613664000000,51585.29000000,52099.00000000,51450.00000000,52091.02000000,2524.31891600,1613667599999,130884579.77739727,73116,1296.25971200,67212387.09674489,0 +1613667600000,52091.03000000,52100.00000000,51777.00000000,51839.55000000,2163.57531900,1613671199999,112371921.92356896,67551,1053.74030700,54728472.25750906,0 +1613671200000,51839.56000000,52177.75000000,51764.16000000,51862.85000000,2028.77431800,1613674799999,105496043.67767959,63518,1060.93505400,55166552.56671546,0 +1613674800000,51860.40000000,52070.68000000,51685.00000000,51760.01000000,1593.36591800,1613678399999,82699893.18919559,55280,784.05700800,40700741.13264565,0 +1613678400000,51760.01000000,52115.92000000,51514.26000000,52111.89000000,2609.19452600,1613681999999,135456895.07548493,72923,1178.50074600,61185198.08094893,0 +1613682000000,52111.89000000,52195.12000000,51892.20000000,52007.21000000,2176.64281700,1613685599999,113327558.51274466,64911,1055.36463900,54943569.74469788,0 +1613685600000,52005.08000000,52075.07000000,51615.01000000,51837.19000000,1724.94218000,1613689199999,89417272.03740988,59893,738.00623000,38254993.28968866,0 +1613689200000,51837.18000000,51920.51000000,51510.00000000,51552.60000000,2028.24582500,1613692799999,104755499.96919844,60306,944.20893100,48773287.50356038,0 +1613692800000,51552.61000000,51943.99000000,51452.00000000,51511.33000000,2713.99459100,1613696399999,140325236.14208726,73812,1277.91639000,66079407.67949208,0 +1613696400000,51512.62000000,51700.99000000,51165.88000000,51325.44000000,2620.93680300,1613699999999,134749623.27586721,77935,1180.17216100,60691482.33635172,0 +1613700000000,51325.44000000,51339.05000000,50710.20000000,51248.52000000,3846.48439000,1613703599999,196444482.96142958,99919,1697.42806300,86704110.90889451,0 +1613703600000,51248.53000000,51500.15000000,51200.00000000,51245.00000000,1787.93614700,1613707199999,91806401.12800927,51393,884.10881500,45394334.76811912,0 +1613707200000,51247.86000000,51530.56000000,50918.00000000,51166.30000000,1969.38099200,1613710799999,100815563.36062377,55063,964.02333400,49359592.08224309,0 +1613710800000,51166.29000000,51567.26000000,51166.29000000,51524.05000000,2079.78925000,1613714399999,106871810.17193274,58451,1079.43239300,55471459.87239495,0 +1613714400000,51524.06000000,51822.96000000,51517.16000000,51734.88000000,2693.88085800,1613717999999,139210203.26247520,98332,1411.00572300,72920017.03868398,0 +1613718000000,51734.87000000,51894.77000000,51654.57000000,51727.08000000,2224.77573300,1613721599999,115164269.58954758,90363,1170.60600200,60593865.41858441,0 +1613721600000,51727.09000000,52293.77000000,51649.82000000,52236.31000000,2775.40234700,1613725199999,144118630.72947438,112827,1599.56171400,83091994.11254978,0 +1613725200000,52236.31000000,52965.31000000,52218.62000000,52690.70000000,5901.16645800,1613728799999,310796784.20453511,149725,3320.32334000,174853654.51923500,0 +1613728800000,52690.75000000,52984.99000000,52625.00000000,52687.60000000,2635.22912700,1613732399999,139156643.20101719,89427,1364.59362200,72066017.08383998,0 +1613732400000,52685.98000000,52863.19000000,52485.95000000,52710.00000000,2380.09901500,1613735999999,125517764.46963318,77057,1208.92392000,63759654.75650406,0 +1613736000000,52709.99000000,52729.75000000,52400.09000000,52534.75000000,2360.66813300,1613739599999,124206180.92702526,103686,1155.50898000,60803591.81707465,0 +1613739600000,52534.76000000,52850.00000000,52315.37000000,52800.04000000,2831.21696500,1613743199999,148967037.12173166,85835,1444.86362700,76032822.29639958,0 +1613743200000,52800.03000000,53280.00000000,52653.93000000,52890.00000000,3789.65655000,1613746799999,200676344.41197990,104574,1912.94928500,101312292.85425075,0 +1613746800000,52877.10000000,53886.07000000,52810.11000000,53863.19000000,5187.73271900,1613750399999,277195452.06437244,123877,2656.18740200,141945314.86494440,0 +1613750400000,53863.82000000,54850.00000000,53605.58000000,54368.65000000,6521.08734300,1613753999999,353986874.90433082,156593,3288.78566800,178412524.08597555,0 +1613754000000,54368.61000000,54766.34000000,54054.00000000,54765.49000000,2446.44460700,1613757599999,133286273.95126311,75913,1177.15246600,64134875.67038222,0 +1613757600000,54765.50000000,55435.96000000,54525.11000000,55384.46000000,2849.83242300,1613761199999,156724151.03477345,69618,1641.45848500,90288653.98634405,0 +1613761200000,55384.46000000,55843.78000000,54583.95000000,54990.01000000,5529.09411400,1613764799999,304068964.59181108,146628,3009.86819600,165517149.87116405,0 +1613764800000,54994.85000000,55698.16000000,54800.00000000,55348.33000000,3733.04848500,1613768399999,206292559.74413172,115558,1851.22754800,102289448.68597726,0 +1613768400000,55345.17000000,56368.00000000,55304.52000000,55651.16000000,5011.99036400,1613771999999,280151757.43058394,146559,2540.36048100,142019526.27173952,0 +1613772000000,55651.16000000,55767.29000000,55130.00000000,55426.40000000,3226.95406900,1613775599999,178971150.41723793,99522,1480.46710800,82104873.17686108,0 +1613775600000,55426.40000000,55950.00000000,55330.00000000,55906.00000000,2542.97653700,1613779199999,141663668.58837266,76548,1239.09552300,69024646.06593565,0 +1613779200000,55906.00000000,56500.00000000,55322.00000000,56226.73000000,5639.85206300,1613782799999,315580909.79922147,139690,2957.74432200,165522858.02641096,0 +1613782800000,56223.44000000,56609.14000000,55946.27000000,56179.17000000,3867.21968100,1613786399999,217600207.67930692,110107,1956.80718900,110112112.46941631,0 +1613786400000,56179.16000000,56395.00000000,55959.41000000,56143.46000000,2927.80920200,1613789999999,164594593.35020089,101379,1367.09183000,76865833.70079412,0 +1613790000000,56143.46000000,56250.00000000,55481.38000000,55706.07000000,2837.35212900,1613793599999,158565110.54746008,107593,1399.96603400,78247337.88213564,0 +1613793600000,55711.90000000,56144.87000000,55511.00000000,55815.19000000,1943.94171300,1613797199999,108608963.33222419,61115,971.01848200,54257440.03207530,0 +1613797200000,55815.19000000,55952.18000000,55555.55000000,55675.43000000,1876.99088600,1613800799999,104616251.66430172,94387,842.85798600,46985070.93292468,0 +1613800800000,55675.44000000,55952.88000000,55580.00000000,55937.12000000,1688.23270000,1613804399999,94196751.80932634,60030,858.00379800,47874150.83791051,0 +1613804400000,55937.02000000,55967.14000000,55185.98000000,55207.92000000,3179.75022900,1613807999999,176654915.35822290,83321,1482.63226400,82383749.90358093,0 +1613808000000,55207.93000000,55674.68000000,55185.16000000,55236.53000000,2266.72007200,1613811599999,125623432.56659793,123216,1109.72949900,61506912.30132833,0 +1613811600000,55236.54000000,55525.00000000,55030.00000000,55252.40000000,2534.56658600,1613815199999,140183539.19055306,115629,1267.49834900,70106264.42073112,0 +1613815200000,55252.40000000,55929.23000000,55210.53000000,55895.31000000,2330.74195200,1613818799999,129723444.86482127,71009,1196.60800300,66591499.28420447,0 +1613818800000,55895.31000000,56388.37000000,55752.77000000,56355.91000000,2787.34971200,1613822399999,155931507.43980731,77103,1370.90644100,76720072.86851603,0 +1613822400000,56355.94000000,57700.46000000,56268.01000000,57291.92000000,6646.36125500,1613825999999,379343463.92682278,167002,2945.25839000,167994072.82411004,0 +1613826000000,57291.93000000,57550.00000000,56923.04000000,57274.34000000,3515.23980700,1613829599999,201257726.46089098,129782,1745.62097000,99946792.89291828,0 +1613829600000,57274.35000000,57426.57000000,56080.00000000,56280.83000000,4268.77802300,1613833199999,243081284.26698700,121978,2083.74691900,118700258.45525395,0 +1613833200000,56280.83000000,56759.99000000,55722.11000000,56145.97000000,5099.63497900,1613836799999,286778901.86173186,170299,2379.84257000,133831357.21577137,0 +1613836800000,56136.55000000,56943.60000000,56136.55000000,56720.16000000,3717.38436700,1613840399999,210031148.92345144,144866,1722.49894600,97326270.53841969,0 +1613840400000,56720.17000000,57425.00000000,56713.79000000,57048.35000000,4217.72333900,1613843999999,240931598.98318140,134869,1947.70969500,111267847.46584215,0 +1613844000000,57048.35000000,57152.33000000,56800.01000000,57115.24000000,1840.03131000,1613847599999,104893005.61052269,73385,954.07713100,54389820.50943438,0 +1613847600000,57118.09000000,57234.48000000,56709.23000000,56975.12000000,1864.07048000,1613851199999,106178555.91371001,79787,919.41331500,52370693.25698575,0 +1613851200000,56975.12000000,57050.00000000,56562.51000000,56719.52000000,2039.86527000,1613854799999,115803725.90370444,66950,980.29465800,55654794.27561605,0 +1613854800000,56719.52000000,56878.28000000,56250.66000000,56472.13000000,2361.84010600,1613858399999,133665925.43983636,70121,1178.71298000,66716850.38525542,0 +1613858400000,56472.13000000,56495.33000000,53863.93000000,55423.99000000,7721.82236500,1613861999999,427670179.98369899,229383,3261.29413700,180656146.92911081,0 +1613862000000,55424.00000000,56191.43000000,55378.02000000,55841.19000000,3774.92708800,1613865599999,210375714.97469261,109845,1736.73236600,96805671.03221858,0 +1613865600000,55841.19000000,56061.64000000,55477.59000000,55834.95000000,2949.77756100,1613869199999,164492362.88754974,84284,1567.96922000,87449093.15253602,0 +1613869200000,55834.95000000,56351.08000000,55717.87000000,56347.69000000,2125.26328800,1613872799999,119014770.77697408,70496,1075.38780300,60228584.99549423,0 +1613872800000,56347.70000000,56660.94000000,56253.77000000,56318.08000000,2201.03164900,1613876399999,124306784.48488625,60339,1103.50273900,62317358.21959931,0 +1613876400000,56318.08000000,56900.00000000,56311.40000000,56505.22000000,2027.22019700,1613879999999,114735892.16174038,58188,1149.97872000,65093136.83821802,0 +1613880000000,56505.22000000,56725.12000000,56040.31000000,56701.08000000,2060.64233700,1613883599999,116297497.07284269,58464,1062.28469700,59954099.29038342,0 +1613883600000,56701.08000000,56959.71000000,56511.54000000,56545.13000000,2041.76479100,1613887199999,115814774.95798891,52225,917.48546300,52041831.40677734,0 +1613887200000,56545.12000000,56609.46000000,56250.00000000,56493.23000000,1604.42588500,1613890799999,90577328.06397415,56614,752.11336700,42463469.43576441,0 +1613890800000,56493.22000000,56594.23000000,55863.54000000,56091.76000000,2600.75351900,1613894399999,146223148.22796013,72120,1269.80374400,71395366.24749209,0 +1613894400000,56092.02000000,56676.70000000,55821.03000000,56513.22000000,2357.26255600,1613897999999,132614264.62652807,68592,1197.62047500,67393178.59409487,0 +1613898000000,56513.21000000,56845.90000000,56364.65000000,56795.81000000,1801.28886800,1613901599999,101801688.89236490,61188,939.18785100,53077127.37936225,0 +1613901600000,56795.81000000,57827.00000000,56657.96000000,57560.00000000,4162.46381100,1613905199999,239049955.88924410,119544,2387.90028500,137110975.22207403,0 +1613905200000,57560.00000000,57570.94000000,57200.00000000,57284.79000000,2690.83005000,1613908799999,154331132.25970184,75626,1599.03421000,91702070.55597467,0 +1613908800000,57284.78000000,57440.82000000,56589.00000000,56888.80000000,2904.91437000,1613912399999,165858686.62890997,85031,1712.70506900,97820928.28773681,0 +1613912400000,56888.81000000,57220.00000000,56888.79000000,57154.19000000,1979.23846400,1613915999999,112975449.21178608,89259,891.56690100,50893748.72844281,0 +1613916000000,57154.19000000,57449.00000000,56783.33000000,57381.13000000,2751.79923100,1613919599999,157416712.46221265,80003,1276.31932100,73018095.70725041,0 +1613919600000,57381.12000000,57555.00000000,57165.40000000,57313.99000000,2657.73107500,1613923199999,152476065.18503597,124088,1300.65590200,74627514.63854968,0 +1613923200000,57313.99000000,57782.00000000,57006.16000000,57733.96000000,2772.77107900,1613926799999,159262145.61400902,116379,1338.48329200,76890547.27388531,0 +1613926800000,57733.95000000,57749.82000000,57356.53000000,57499.01000000,1895.34702700,1613930399999,109165561.47905982,71673,899.25412700,51792489.75834086,0 +1613930400000,57499.02000000,58300.00000000,57333.79000000,58183.69000000,2708.74612400,1613933999999,156704543.25729914,119447,1533.09588400,88720683.24901281,0 +1613934000000,58183.69000000,58352.80000000,57916.66000000,58072.62000000,2656.04312300,1613937599999,154497112.99673591,80188,1256.41617400,73085956.47884253,0 +1613937600000,58072.62000000,58247.84000000,57458.15000000,57654.80000000,2454.89171800,1613941199999,142135184.40035702,89127,1154.67616300,66858169.40086438,0 +1613941200000,57657.10000000,57900.00000000,57180.00000000,57293.53000000,2438.14225000,1613944799999,140356109.44497323,84682,1122.74916100,64646612.45708931,0 +1613944800000,57293.52000000,57616.34000000,56935.03000000,57328.47000000,2198.42742300,1613948399999,125844765.70797286,113697,1043.31190500,59724900.74080561,0 +1613948400000,57328.46000000,57590.05000000,57100.00000000,57408.57000000,2125.93211500,1613951999999,122046326.65778230,59279,954.58661200,54801150.09877834,0 +1613952000000,57412.35000000,57508.47000000,56230.84000000,56235.15000000,4513.74034200,1613955599999,256206476.92647041,101603,2052.93015500,116527941.85630910,0 +1613955600000,56235.15000000,57000.00000000,56013.13000000,56860.04000000,3425.03640300,1613959199999,194048532.20100081,131706,1687.57100000,95610108.82367427,0 +1613959200000,56860.04000000,57277.99000000,55351.15000000,56855.12000000,4511.02871100,1613962799999,254949389.91415914,102202,2217.52420900,125342467.22338429,0 +1613962800000,56855.13000000,57078.50000000,55757.58000000,55860.12000000,2876.05652800,1613966399999,162014342.49408319,107178,1400.27272900,78908418.38414442,0 +1613966400000,55858.99000000,56258.49000000,55102.77000000,55786.36000000,4117.07045800,1613969999999,229089676.70647494,107816,1812.86382600,100869406.52186817,0 +1613970000000,55785.61000000,56372.01000000,55625.11000000,55869.15000000,2634.16909100,1613973599999,147463057.07817703,83020,1185.58001100,66366349.12047309,0 +1613973600000,55869.16000000,56377.00000000,55684.74000000,55989.36000000,2101.70438100,1613977199999,117982728.62770379,73328,1086.16914200,60976053.84114737,0 +1613977200000,55989.35000000,56550.00000000,55652.45000000,56422.92000000,2595.91051900,1613980799999,145788942.68097489,72550,1247.08029300,70045210.06757610,0 +1613980800000,56422.23000000,56623.69000000,55408.92000000,55480.80000000,4285.43355200,1613984399999,239939231.56158729,85723,1844.93513200,103362861.28565440,0 +1613984400000,55480.80000000,55800.00000000,54355.00000000,54766.39000000,5226.54351400,1613987999999,288464821.34418318,122713,2507.17848000,138510621.77047116,0 +1613988000000,54747.23000000,55101.69000000,53505.70000000,54847.72000000,8059.54495200,1613991599999,438974088.46219304,184557,3812.06418000,207693324.36044736,0 +1613991600000,54847.72000000,55251.79000000,54403.11000000,54524.94000000,4098.26864800,1613995199999,225014641.37038058,111831,1937.00577200,106318273.85508172,0 +1613995200000,54515.00000000,54695.66000000,52628.90000000,53781.12000000,10930.65063700,1613998799999,585168995.14976690,238630,5133.96507200,274790620.59419257,0 +1613998800000,53784.14000000,54062.77000000,52050.00000000,52070.47000000,8203.24906400,1614002399999,434668374.13266490,185091,4008.41171000,212584375.41294594,0 +1614002400000,52066.99000000,53654.37000000,47622.00000000,53478.83000000,24477.79279200,1614005999999,1252120246.31738026,508500,11859.23979000,606836411.55804317,0 +1614006000000,53472.69000000,53993.00000000,52483.39000000,53236.69000000,11024.95969200,1614009599999,588440597.71152324,267399,4644.85426600,247758483.42495487,0 +1614009600000,53236.69000000,53847.56000000,52730.00000000,53180.05000000,5464.14551800,1614013199999,291577112.37865897,153293,2558.14367500,136554777.21755541,0 +1614013200000,53177.82000000,53302.59000000,51955.65000000,52100.00000000,4675.17425200,1614016799999,246033067.08975183,124241,2258.17834000,118830414.26901206,0 +1614016800000,52100.00000000,53490.00000000,51570.00000000,53227.23000000,5492.27131500,1614020399999,288540225.07433704,138584,2571.49882000,135020716.48823552,0 +1614020400000,53227.23000000,53746.29000000,52942.33000000,53581.69000000,2709.39250800,1614023999999,144745202.52390016,81259,1240.42562800,66276641.32370668,0 +1614024000000,53587.41000000,54364.00000000,53452.51000000,53771.34000000,3461.08948600,1614027599999,187077759.39328225,93144,1743.12562700,94207575.36040389,0 +1614027600000,53779.38000000,54900.00000000,53667.72000000,54883.16000000,2928.49419700,1614031199999,159285168.52561068,81059,1528.69787400,83133656.64893852,0 +1614031200000,54883.16000000,54989.46000000,53782.09000000,54084.97000000,2862.15708100,1614034799999,155579306.49037132,85407,1491.61936500,81048353.69973041,0 +1614034800000,54084.97000000,54373.32000000,53279.02000000,54087.67000000,3345.55130300,1614038399999,180214736.28216198,72249,1848.32688300,99644091.41302238,0 +1614038400000,54087.67000000,54183.59000000,53018.54000000,53440.66000000,2943.36896500,1614041999999,157532202.95411356,107377,1463.66931400,78334979.37420292,0 +1614042000000,53431.44000000,53925.86000000,52281.88000000,52546.18000000,3132.59441600,1614045599999,165831902.16947045,83399,1571.23029700,83164230.74900639,0 +1614045600000,52546.59000000,52887.66000000,50901.00000000,51218.63000000,5963.50597500,1614049199999,309284577.51721979,157353,2965.01472600,153869619.32416301,0 +1614049200000,51218.75000000,52496.90000000,51153.33000000,51906.36000000,5642.99707000,1614052799999,292785084.71039049,139770,2790.72713500,144781100.80713279,0 +1614052800000,51900.73000000,52311.71000000,49600.00000000,50754.50000000,6698.05728500,1614056399999,340983951.87896339,150863,2904.19675200,148035992.07803085,0 +1614056400000,50754.50000000,50755.48000000,48615.00000000,49950.00000000,10951.85598400,1614059999999,544401197.91319265,229947,4974.20165700,247273966.34705154,0 +1614060000000,49952.49000000,51241.99000000,49380.14000000,49547.02000000,6064.54940400,1614063599999,305207167.88787803,133354,3082.08275600,155117465.41686265,0 +1614063600000,49544.58000000,50547.30000000,49288.94000000,49640.33000000,4936.85373500,1614067199999,246714261.69089670,109379,2392.57052700,119574223.45067150,0 +1614067200000,49642.92000000,50027.01000000,46560.00000000,46565.18000000,15751.17067700,1614070799999,758815141.17923971,312940,6948.96769600,334957181.75485304,0 +1614070800000,46562.33000000,48695.75000000,45000.00000000,48075.45000000,17379.42280400,1614074399999,821119205.83081268,368112,8358.22422300,395536539.20981648,0 +1614074400000,48072.01000000,48979.17000000,46568.00000000,47546.01000000,8447.62229800,1614077999999,402870433.97213644,193960,4140.71415200,197483399.16148375,0 +1614078000000,47531.15000000,48275.74000000,44892.56000000,46369.29000000,12372.25443300,1614081599999,572863947.25727364,242476,5839.99678400,270527141.22070734,0 +1614081600000,46359.14000000,49455.53000000,45788.10000000,48670.21000000,13248.95882000,1614085199999,629347433.60642503,259976,6898.84650700,327806976.86841776,0 +1614085200000,48670.54000000,49600.00000000,48032.17000000,48750.00000000,7741.58941200,1614088799999,377614079.11806758,172266,4023.14235200,196254720.55646505,0 +1614088800000,48754.47000000,49141.89000000,45838.84000000,46978.18000000,7605.54125100,1614092399999,360869163.70869394,191730,3632.63684400,172532576.02962880,0 +1614092400000,46977.89000000,49350.00000000,46635.00000000,48602.03000000,7893.56502000,1614095999999,381359810.37807281,186256,4125.87428200,199476492.49976093,0 +1614096000000,48602.02000000,49247.69000000,47230.01000000,47365.61000000,5789.95500800,1614099599999,278323778.57237520,127453,2681.22027300,129036576.21017609,0 +1614099600000,47361.41000000,48197.74000000,46888.00000000,47175.27000000,3541.70158500,1614103199999,168002549.47439544,94047,1758.35548200,83426686.47410004,0 +1614103200000,47163.74000000,47777.00000000,46501.34000000,46881.49000000,3767.75261800,1614106799999,177599282.14800305,100101,1842.67491100,86936002.82502872,0 +1614106800000,46872.77000000,47291.03000000,45500.00000000,45523.00000000,4845.94891300,1614110399999,224281371.84178197,120852,2209.35751900,102293371.28860546,0 +1614110400000,45523.02000000,47820.00000000,45251.00000000,47814.50000000,4719.43409900,1614113999999,220303390.69267214,113735,2429.29030800,113559842.78994764,0 +1614114000000,47812.80000000,48474.31000000,47400.70000000,47937.33000000,4237.63139600,1614117599999,203749279.92999366,95017,2468.49531300,118729321.24352526,0 +1614117600000,47930.44000000,48756.00000000,47738.82000000,48589.69000000,3213.00765300,1614121199999,155350590.03150539,74216,1710.03929700,82702263.28772867,0 +1614121200000,48597.19000000,48938.85000000,48124.51000000,48891.00000000,2485.68623000,1614124799999,120629326.77981200,60617,1252.61388500,60784623.12998936,0 +1614124800000,48891.00000000,49100.00000000,46988.69000000,48456.58000000,4847.53073600,1614128399999,232076690.35418094,113148,2353.74857500,112801918.33755374,0 +1614128400000,48456.58000000,50225.22000000,48419.48000000,50191.60000000,5367.92410400,1614131999999,264734974.10829012,116620,2863.56549200,141251223.84913265,0 +1614132000000,50191.68000000,50553.33000000,49803.00000000,50160.42000000,3962.03444500,1614135599999,198889484.54245099,101287,1961.74069800,98491365.70161724,0 +1614135600000,50160.21000000,50993.57000000,50025.01000000,50874.99000000,3145.82980800,1614139199999,158803323.04548693,79857,1666.77630900,84155964.55322895,0 +1614139200000,50869.77000000,51357.00000000,50327.35000000,50617.29000000,4569.37934100,1614142799999,232438416.79339211,109519,2570.52035500,130768549.11077603,0 +1614142800000,50619.83000000,51044.22000000,50000.00000000,50247.40000000,3407.58076900,1614146399999,171886820.25996955,84827,1810.31364600,91331452.56812189,0 +1614146400000,50247.61000000,50719.78000000,49456.00000000,50109.21000000,4666.11847000,1614149999999,233390526.45703587,109361,2366.15574100,118348580.97282154,0 +1614150000000,50109.20000000,50368.40000000,49530.43000000,50090.57000000,3036.97920300,1614153599999,151776782.27984239,78641,1584.03485200,79184469.31195800,0 +1614153600000,50090.61000000,50886.20000000,49799.29000000,50634.36000000,3931.00620100,1614157199999,198647202.83939082,102253,1954.68993800,98774033.09842807,0 +1614157200000,50634.32000000,51374.99000000,50306.12000000,50847.51000000,4804.82076900,1614160799999,244207904.89909110,115218,2495.37209800,126760609.55484541,0 +1614160800000,50847.50000000,51000.00000000,50033.52000000,50075.00000000,3196.21238900,1614164399999,161464416.54413845,92558,1504.95120500,76053703.29705312,0 +1614164400000,50075.00000000,50875.00000000,50049.15000000,50360.02000000,2831.80462200,1614167999999,142887063.44259436,82887,1430.93015000,72212300.17751500,0 +1614168000000,50360.02000000,51294.00000000,50326.81000000,50739.94000000,4538.97781000,1614171599999,230946348.07511860,102495,2106.56547500,107201169.34209975,0 +1614171600000,50738.27000000,51060.00000000,49056.33000000,49481.61000000,7310.45414800,1614175199999,363938756.12032670,152980,3406.18825800,169502557.32618663,0 +1614175200000,49469.19000000,49777.00000000,48758.00000000,49404.04000000,4794.06506400,1614178799999,236323203.72922684,99104,2365.99498000,116665506.76388923,0 +1614178800000,49404.62000000,49850.00000000,48450.00000000,49819.50000000,4685.05192800,1614182399999,230450785.30372679,105383,2398.34043600,118032165.63465616,0 +1614182400000,49819.49000000,50150.00000000,49160.00000000,49308.28000000,3788.49869500,1614185999999,188185982.84580416,80231,1918.82606000,95330349.09763051,0 +1614186000000,49308.29000000,50060.31000000,49303.56000000,50041.80000000,2368.46736800,1614189599999,117885039.87187039,62024,1207.15248900,60083975.40984697,0 +1614189600000,50046.03000000,50052.18000000,49465.15000000,49570.00000000,2338.30656600,1614193199999,116311162.40909255,55934,1071.79336200,53314935.44764492,0 +1614193200000,49570.00000000,49690.15000000,48811.26000000,48959.93000000,2856.47685000,1614196799999,140540872.27822315,63481,1377.77991800,67775581.68214042,0 +1614196800000,48959.93000000,49266.39000000,48581.26000000,49101.18000000,2532.66408700,1614200399999,123860543.18299560,65161,1201.33183700,58743856.60865807,0 +1614200400000,49101.18000000,49150.00000000,48090.00000000,48707.72000000,3651.36623600,1614203999999,176954151.28704662,82126,1747.74613500,84724951.63964196,0 +1614204000000,48715.97000000,48950.00000000,48028.18000000,48811.63000000,2341.05845900,1614207599999,113682228.47331085,69019,1035.68505500,50305302.55720192,0 +1614207600000,48811.63000000,49747.49000000,48722.71000000,49676.20000000,2908.60118400,1614211199999,143750322.23693025,70418,1350.51176700,66752084.09569870,0 +1614211200000,49676.21000000,50865.00000000,49517.01000000,50507.25000000,3530.40346200,1614214799999,177315058.26818629,87157,1865.29052100,93677845.27793823,0 +1614214800000,50507.24000000,50884.88000000,50357.14000000,50504.71000000,2197.13675300,1614218399999,111268572.08912711,53310,1189.00936000,60218195.43755632,0 +1614218400000,50505.26000000,50834.43000000,50421.36000000,50650.95000000,1895.03724200,1614221999999,96020905.95990301,47719,975.19348400,49414002.72529453,0 +1614222000000,50650.95000000,50659.77000000,50033.94000000,50206.97000000,1947.21850800,1614225599999,97997520.78394554,52519,973.23221100,48974935.56632615,0 +1614225600000,50206.97000000,50366.67000000,49567.89000000,49627.34000000,2531.01652400,1614229199999,126596464.51532776,55577,1271.09020400,63579920.34369894,0 +1614229200000,49626.90000000,50449.07000000,49533.44000000,50388.60000000,2489.27614500,1614232799999,124308971.42079986,63601,1312.36198100,65532875.49801985,0 +1614232800000,50391.10000000,50568.97000000,50212.79000000,50453.54000000,1878.14184600,1614236399999,94672068.91718432,71321,936.38339600,47201518.69036245,0 +1614236400000,50453.54000000,50559.51000000,50105.71000000,50395.99000000,1945.51267000,1614239999999,98085710.90143531,55250,987.33240300,49783416.60237040,0 +1614240000000,50395.58000000,50513.35000000,49534.90000000,49700.00000000,2853.46848600,1614243599999,142708611.69016401,73044,1442.17472000,72134777.56929014,0 +1614243600000,49700.01000000,49840.60000000,48581.71000000,48977.03000000,4454.01146200,1614247199999,218864240.01879811,109551,2159.84100800,106137032.63691128,0 +1614247200000,48977.03000000,49729.52000000,48812.92000000,49551.51000000,2744.27976000,1614250799999,135270333.22223811,108491,1409.13453800,69471930.39275963,0 +1614250800000,49551.51000000,50403.14000000,49551.51000000,50294.80000000,3076.06333800,1614254399999,153555644.49355980,104662,1581.69123500,78976835.05466704,0 +1614254400000,50299.00000000,51500.00000000,50077.00000000,51487.06000000,5006.69196500,1614257999999,253928753.62570436,142209,2750.04184000,139510873.31588941,0 +1614258000000,51497.98000000,52041.73000000,51060.27000000,51347.60000000,6437.20928400,1614261599999,331813816.68325372,156703,3305.41176100,170455329.85337949,0 +1614261600000,51351.93000000,51530.00000000,50599.00000000,50830.88000000,3602.68247200,1614265199999,184076620.86842276,96270,1629.94566600,83315760.62943449,0 +1614265200000,50830.60000000,51367.61000000,50480.00000000,50849.99000000,3311.82255800,1614268799999,168638000.41787461,102306,1540.15706900,78411652.12854003,0 +1614268800000,50850.00000000,51370.18000000,50563.82000000,50630.66000000,3186.56373600,1614272399999,162452252.98783745,100933,1528.30413100,77914098.04088617,0 +1614272400000,50632.85000000,50665.78000000,49306.91000000,49550.95000000,4625.13316200,1614275999999,231011634.46842033,109813,2024.93443000,101143499.45406222,0 +1614276000000,49550.96000000,50086.28000000,49226.09000000,49544.14000000,3513.02183800,1614279599999,174509030.04080191,96606,1739.77401000,86434357.97169301,0 +1614279600000,49543.04000000,50000.00000000,49262.29000000,49443.86000000,2583.92601300,1614283199999,128220155.52403962,110202,1288.11088100,63926257.90612366,0 +1614283200000,49442.20000000,49550.01000000,48529.47000000,49152.75000000,4249.67515800,1614286799999,208126020.37474209,123297,1950.51150400,95521642.40626772,0 +1614286800000,49151.36000000,49300.00000000,48051.00000000,48101.99000000,3634.64330500,1614290399999,177026810.91773268,101460,1592.40149400,77619066.20353466,0 +1614290400000,48102.01000000,48900.00000000,47471.00000000,48235.85000000,5670.50516700,1614293999999,272928468.09759038,152785,2249.08470900,108297095.79279770,0 +1614294000000,48229.63000000,48463.27000000,46674.34000000,47073.73000000,5947.23226700,1614297599999,282793061.85452555,130893,2909.25220300,138415598.14855837,0 +1614297600000,47073.73000000,47613.50000000,46000.00000000,46801.05000000,8103.39317700,1614301199999,377831011.56882769,172768,3825.35259500,178444800.91619932,0 +1614301200000,46807.84000000,47479.06000000,46240.84000000,46480.48000000,6203.21910400,1614304799999,290755125.08169801,136879,2797.08898300,131130552.04979824,0 +1614304800000,46480.48000000,47800.00000000,46124.74000000,47343.51000000,5240.30775400,1614308399999,246801657.25005068,113885,2727.86834900,128587722.42657518,0 +1614308400000,47343.50000000,47695.77000000,46639.24000000,47330.24000000,3512.63530400,1614311999999,165764356.62534804,74188,1678.73869200,79268414.42883371,0 +1614312000000,47331.34000000,47786.50000000,46806.49000000,47025.06000000,2839.21943900,1614315599999,134360235.86143333,67187,1404.24721700,66455661.80800747,0 +1614315600000,47028.80000000,47207.40000000,45502.69000000,45517.53000000,5228.38820800,1614319199999,241909695.32155710,106473,2393.47558700,110855039.12883120,0 +1614319200000,45524.35000000,46500.00000000,45512.02000000,46093.07000000,3894.66556800,1614322799999,179503674.00823412,92708,2004.62294400,92392698.00012970,0 +1614322800000,46098.99000000,46430.02000000,44106.78000000,44973.68000000,10843.41221600,1614326399999,488062440.47692488,182846,4759.61414800,214102124.22802633,0 +1614326400000,44986.99000000,45950.00000000,44939.19000000,45727.74000000,5560.53718000,1614329999999,252899486.53136551,112993,3040.30106900,138268949.01498576,0 +1614330000000,45727.75000000,46626.35000000,45325.00000000,46410.76000000,6228.04563800,1614333599999,287389360.53800643,120877,2953.79986200,136357667.07994773,0 +1614333600000,46410.76000000,46880.40000000,46168.00000000,46706.85000000,3745.26633500,1614337199999,174396328.08068973,83336,1855.10917900,86378782.45516731,0 +1614337200000,46704.75000000,46850.00000000,45662.94000000,46427.65000000,3319.25951200,1614340799999,153378598.05698269,74580,1652.14932400,76345324.90886055,0 +1614340800000,46427.65000000,47266.34000000,46315.08000000,46823.39000000,3485.25260900,1614344399999,163279933.31185639,73849,1769.62185000,82921416.43307298,0 +1614344400000,46823.38000000,46999.77000000,45800.00000000,45958.41000000,3593.67866900,1614347999999,166636422.45052784,74350,1875.93901200,86995976.18924903,0 +1614348000000,45958.41000000,47429.00000000,45828.37000000,46868.98000000,4508.89686400,1614351599999,210961601.75950509,95235,2427.59182800,113576978.93155110,0 +1614351600000,46869.59000000,47853.13000000,46333.00000000,47594.65000000,5170.12468800,1614355199999,243331076.24514916,95719,2707.73438300,127476530.24788660,0 +1614355200000,47590.66000000,48219.08000000,47450.00000000,48127.26000000,4556.16230600,1614358799999,218038757.46334770,97078,2376.52056900,113747181.50612344,0 +1614358800000,48127.26000000,48424.11000000,47542.20000000,47660.98000000,3255.90618200,1614362399999,156184096.40823589,97578,1516.64501800,72767422.86201629,0 +1614362400000,47659.96000000,47873.24000000,47269.99000000,47317.09000000,2473.72390500,1614365999999,117680138.80192218,67348,1261.37198300,59999766.57364878,0 +1614366000000,47317.09000000,47478.07000000,46602.62000000,46959.17000000,3342.27688000,1614369599999,157219140.61462317,81667,1775.23647800,83525665.16354663,0 +1614369600000,46959.18000000,47115.38000000,46071.89000000,46270.00000000,3514.29786700,1614373199999,163727573.68617536,80837,1733.79210500,80755103.94787450,0 +1614373200000,46270.00000000,46867.00000000,45500.00000000,45677.46000000,3831.69018200,1614376799999,177173658.77323526,85141,1806.78594000,83585069.84939639,0 +1614376800000,45680.00000000,45988.77000000,45000.00000000,45476.30000000,4400.97529100,1614380399999,200547396.61397559,123927,2204.94896800,100559178.29847833,0 +1614380400000,45476.30000000,46444.57000000,45368.74000000,46276.87000000,2571.86578500,1614383999999,118542767.20494309,60317,1078.34853900,49692166.80407637,0 +1614384000000,46276.88000000,47568.18000000,46156.24000000,47525.07000000,3534.29999100,1614387599999,165803625.84097623,86580,1665.01567100,78110640.54767086,0 +1614387600000,47523.34000000,47960.00000000,47331.54000000,47761.97000000,2844.98808800,1614391199999,135514542.91739055,66295,1421.25152600,67704139.35897203,0 +1614391200000,47761.97000000,48085.47000000,47186.00000000,47375.34000000,4456.60085500,1614394799999,212457424.21204068,78369,2189.07166400,104342900.46655170,0 +1614394800000,47375.34000000,47937.03000000,47158.26000000,47423.08000000,2661.32193700,1614398399999,126754003.33040374,57862,1405.78906700,66954860.25786872,0 +1614398400000,47423.07000000,47918.40000000,47278.54000000,47657.47000000,2060.90965900,1614401999999,98143308.31298744,53225,1066.13491300,50771040.52663614,0 +1614402000000,47657.48000000,47955.58000000,47460.21000000,47803.71000000,1995.34977400,1614405599999,95113752.31335984,49559,1050.35401800,50073355.08143282,0 +1614405600000,47799.68000000,48394.00000000,47527.33000000,47566.60000000,2654.87120400,1614409199999,127353603.53008118,66971,1405.04827800,67410668.81044190,0 +1614409200000,47560.69000000,47626.26000000,46712.18000000,47158.53000000,3140.61823000,1614412799999,148219870.16535473,103195,1362.54620800,64305961.13869768,0 +1614412800000,47153.01000000,47284.74000000,46380.00000000,46620.50000000,2860.16511300,1614416399999,133799040.21912423,72532,1377.74747200,64451428.41630400,0 +1614416400000,46620.83000000,46827.73000000,46224.84000000,46671.04000000,2576.34509200,1614419999999,119862455.12701158,69632,1302.27292700,60589695.58045667,0 +1614420000000,46671.04000000,47099.97000000,46601.01000000,46775.51000000,2600.52498100,1614423599999,121899926.21080389,73219,1320.99195800,61923992.42977355,0 +1614423600000,46775.68000000,47640.03000000,46690.00000000,47299.99000000,2765.21237600,1614427199999,130625873.88869273,98218,1334.86962300,63061410.76453267,0 +1614427200000,47299.99000000,47800.00000000,46735.63000000,47429.99000000,3286.07999400,1614430799999,155524036.69004770,104559,1719.14008500,81375777.57309195,0 +1614430800000,47430.00000000,47700.00000000,47058.82000000,47441.91000000,2358.37712800,1614434399999,111900397.24020663,67771,1165.13395500,55286834.45013342,0 +1614434400000,47441.91000000,47620.00000000,46836.00000000,47079.64000000,2566.95495400,1614437999999,121112174.87390989,68107,1187.81147400,56048094.24457132,0 +1614438000000,47078.23000000,47378.92000000,46337.53000000,46528.64000000,3281.96265900,1614441599999,153502286.09020234,75010,1591.87644400,74468168.98682059,0 +1614441600000,46528.82000000,46949.96000000,46271.00000000,46883.19000000,2253.46093200,1614445199999,105298736.37827274,63972,1046.25098800,48907145.01779883,0 +1614445200000,46883.19000000,47177.00000000,46700.00000000,47042.53000000,1672.24031500,1614448799999,78515466.79669112,51211,805.28582400,37810517.31586011,0 +1614448800000,47041.13000000,47329.17000000,46900.00000000,47136.30000000,1457.74337900,1614452399999,68687063.11667067,46792,729.86197100,34391944.86717012,0 +1614452400000,47136.29000000,47450.26000000,47028.59000000,47405.39000000,1684.93500000,1614455999999,79658239.62294505,60931,834.00371700,39436662.29000260,0 +1614456000000,47405.38000000,47557.14000000,46900.00000000,47081.07000000,1868.82747200,1614459599999,88246185.35643802,58133,998.73874800,47167746.01101271,0 +1614459600000,47083.43000000,47170.00000000,46534.13000000,46825.30000000,1969.98297900,1614463199999,92418276.77836795,53136,879.07275900,41240297.39382531,0 +1614463200000,46825.30000000,46870.31000000,45742.00000000,45828.43000000,2593.33291400,1614466799999,120278864.92911987,77561,1114.37705300,51711821.91528250,0 +1614466800000,45828.44000000,46441.41000000,45000.00000000,46106.43000000,6915.72926600,1614470399999,315208284.60987299,154880,3014.37330400,137467007.50468982,0 +1614470400000,46103.67000000,46638.46000000,45588.11000000,46345.94000000,3169.79714600,1614473999999,146343245.43574778,73122,1659.58699400,76624309.58339224,0 +1614474000000,46345.93000000,46600.00000000,46100.00000000,46442.50000000,1907.14640000,1614477599999,88446962.56277918,46835,969.55992000,44980753.83648046,0 +1614477600000,46439.20000000,46518.68000000,45220.28000000,45397.23000000,2844.47407400,1614481199999,130253873.25121635,71301,1295.88687100,59331828.16020728,0 +1614481200000,45397.97000000,45684.56000000,44444.00000000,44629.17000000,5409.31508300,1614484799999,243565752.27029851,107113,2459.09725300,110765442.09332018,0 +1614484800000,44632.70000000,45100.00000000,44267.48000000,44384.14000000,3744.72190800,1614488399999,167372917.56371388,81166,1864.17655200,83344548.00617286,0 +1614488400000,44384.38000000,45600.00000000,44200.00000000,44791.27000000,4065.08885100,1614491999999,182473020.62141399,88176,2025.52662800,91017014.80541965,0 +1614492000000,44791.27000000,44977.05000000,43738.65000000,44372.43000000,6061.42567500,1614495599999,268938540.46627653,123877,2986.34030800,132564535.19387009,0 +1614495600000,44379.68000000,44783.29000000,44099.99000000,44400.83000000,2997.71730300,1614499199999,133261571.87941589,71352,1509.46732000,67112779.23711468,0 +1614499200000,44400.83000000,45273.68000000,44375.02000000,44856.61000000,3222.93603900,1614502799999,144621237.55419828,69922,1672.73012400,75067985.53918451,0 +1614502800000,44856.61000000,45530.62000000,44680.71000000,45067.61000000,2733.85811000,1614506399999,123504689.95208467,60914,1397.29972800,63134373.77267454,0 +1614506400000,45067.51000000,45513.78000000,44712.19000000,45177.20000000,2357.30304900,1614509999999,106473932.85628458,51637,1191.64029400,53849452.11931280,0 +1614510000000,45177.20000000,45493.87000000,44966.63000000,45284.86000000,2221.51346500,1614513599999,100639192.03627693,48549,1133.87832600,51377617.18932274,0 +1614513600000,45287.25000000,45500.17000000,44501.00000000,44756.99000000,2991.00191900,1614517199999,134304067.74202045,70740,1533.22514500,68851526.75005113,0 +1614517200000,44756.99000000,44889.00000000,44150.00000000,44178.80000000,3108.19179800,1614520799999,138482357.92560297,65249,1410.56367100,62851419.90856457,0 +1614520800000,44183.52000000,44652.30000000,43556.98000000,44561.92000000,5862.90959100,1614524399999,258553829.19896809,118733,2853.84535500,125894209.04068268,0 +1614524400000,44564.46000000,44628.89000000,43168.00000000,43391.14000000,5007.27058300,1614527999999,218771349.57323169,108126,2347.12410900,102573613.94667773,0 +1614528000000,43391.14000000,43934.56000000,43000.00000000,43514.78000000,4682.77407500,1614531599999,203706183.12276087,100278,2208.85326200,96126605.99246248,0 +1614531600000,43514.77000000,43942.62000000,43085.00000000,43119.02000000,3300.00538700,1614535199999,143500534.33324752,72028,1493.07205400,64961325.13164407,0 +1614535200000,43123.42000000,43779.96000000,43001.00000000,43677.39000000,2672.29292500,1614538799999,116189047.22323296,56790,1365.94908900,59415305.57699560,0 +1614538800000,43683.79000000,44521.66000000,43434.22000000,44405.32000000,2825.26510900,1614542399999,124222953.03989421,66719,1390.80217500,61174762.09096287,0 +1614542400000,44402.88000000,44960.00000000,44088.00000000,44860.38000000,2723.97533900,1614545999999,120993189.49728925,64301,1276.70520100,56732923.18431498,0 +1614546000000,44866.37000000,45380.21000000,44845.88000000,45129.52000000,3611.87808000,1614549599999,163044265.62454782,85094,1695.55722700,76544169.12652960,0 +1614549600000,45129.52000000,45362.35000000,44755.10000000,45180.00000000,1990.55793300,1614553199999,89784874.35224988,55700,1104.36519700,49819715.24342241,0 +1614553200000,45179.99000000,45919.61000000,44850.00000000,45135.66000000,3543.94920000,1614556799999,160912377.37182900,80623,1842.91904700,83681231.07360078,0 +1614556800000,45134.11000000,46571.30000000,44950.53000000,46217.19000000,4899.57483300,1614560399999,225513040.97302689,98570,2546.12383200,117249522.87670990,0 +1614560400000,46217.18000000,46492.33000000,45850.00000000,46161.83000000,2685.38600500,1614563999999,123992734.60490434,63851,1272.87872400,58775192.06854412,0 +1614564000000,46166.16000000,46796.94000000,46102.84000000,46419.56000000,2926.95109900,1614567599999,136131784.14017812,66979,1434.36610300,66682014.58160103,0 +1614567600000,46414.70000000,46540.31000000,46204.08000000,46336.37000000,1970.34891200,1614571199999,91409715.99835350,48608,996.75823700,46245628.53192638,0 +1614571200000,46336.38000000,46688.13000000,45959.70000000,46458.33000000,2152.37990400,1614574799999,99623997.43976883,52281,1018.96408400,47174472.85825921,0 +1614574800000,46474.53000000,46486.33000000,45980.00000000,46200.47000000,2151.81610900,1614578399999,99418827.42803201,42108,1160.44899500,53602856.04459932,0 +1614578400000,46200.46000000,46272.38000000,45641.02000000,45857.30000000,2462.75599200,1614581999999,113251774.58884000,54715,1221.62636300,56181460.93743773,0 +1614582000000,45857.30000000,46425.61000000,45837.28000000,46288.18000000,2757.47142600,1614585599999,127185633.65512986,52132,1401.27958900,64626989.17786812,0 +1614585600000,46291.87000000,47300.00000000,46272.10000000,47009.38000000,4893.93544600,1614589199999,229398351.72244389,105294,2517.08494200,118002132.07713202,0 +1614589200000,47009.38000000,47500.00000000,46900.00000000,47350.12000000,3890.52625300,1614592799999,183805805.57094061,119593,1860.70307400,87929478.97873058,0 +1614592800000,47347.51000000,47714.61000000,46968.00000000,47615.66000000,3790.49879700,1614596399999,179579344.64943491,113749,1814.06676300,85969877.50688835,0 +1614596400000,47615.66000000,48050.00000000,47400.00000000,47722.78000000,5754.50783300,1614599999999,274969148.28367645,148678,2584.48026900,123436759.74516606,0 +1614600000000,47722.42000000,48044.63000000,47450.32000000,47913.80000000,3184.93608500,1614603599999,152215160.11143974,130402,1642.63539700,78521976.07015114,0 +1614603600000,47913.80000000,48441.96000000,47757.78000000,47799.33000000,5239.10988500,1614607199999,252041307.30553061,128669,2231.27196300,107367721.13743488,0 +1614607200000,47799.34000000,48564.03000000,47580.10000000,48083.04000000,4564.09516600,1614610799999,219732963.70363260,106239,2351.11959800,113191346.51585313,0 +1614610800000,48083.04000000,49298.00000000,48065.54000000,49188.00000000,5757.10113300,1614614399999,281053341.77638509,126214,3130.48006600,152782808.66391681,0 +1614614400000,49187.99000000,49469.99000000,48530.36000000,49065.40000000,5837.99284000,1614617999999,286091759.29871188,155200,3045.56667000,149251264.19539030,0 +1614618000000,49069.60000000,49200.00000000,48527.27000000,48565.00000000,3508.19818100,1614621599999,171459146.32915217,75536,1500.41754800,73337903.66428158,0 +1614621600000,48565.00000000,48777.71000000,48233.33000000,48465.27000000,3120.34098400,1614625199999,151243496.69571990,71330,1632.04003700,79098725.14175139,0 +1614625200000,48465.27000000,48700.00000000,48019.06000000,48262.83000000,2240.12268200,1614628799999,108246561.65351669,59593,1097.23393800,53024323.54805958,0 +1614628800000,48262.66000000,48916.55000000,47876.00000000,48512.40000000,4496.21330400,1614632399999,217115102.90005244,101790,2755.45463300,133029219.81850437,0 +1614632400000,48512.99000000,48872.00000000,48338.25000000,48784.09000000,2011.39697700,1614635999999,97812320.09828620,96201,1014.30510600,49324876.35973564,0 +1614636000000,48784.46000000,49300.00000000,48588.89000000,49137.73000000,1882.44168200,1614639599999,92252313.95743198,57553,870.78503600,42666007.40763326,0 +1614639600000,49137.73000000,49790.00000000,49064.62000000,49587.03000000,2908.01012000,1614643199999,143972161.98113952,71938,1516.90339400,75094127.70673212,0 +1614643200000,49595.76000000,50200.00000000,49278.94000000,49354.62000000,4346.81402400,1614646799999,216488087.59988408,129863,2270.17818400,113115088.77165506,0 +1614646800000,49354.63000000,49699.93000000,48710.00000000,49368.60000000,2651.16259000,1614650399999,130190243.85463369,69946,1413.38820000,69418719.02284061,0 +1614650400000,49368.60000000,49777.00000000,49045.45000000,49272.74000000,2909.33571100,1614653999999,143869485.52624628,70920,1463.01451400,72353098.49711370,0 +1614654000000,49272.74000000,49398.00000000,48825.00000000,48974.75000000,2134.19589000,1614657599999,104756035.22156957,50352,962.66098100,47247693.97571770,0 +1614657600000,48974.74000000,49243.00000000,48544.75000000,49159.16000000,2213.46541600,1614661199999,108239030.17290433,54092,1153.58493300,56405746.98290183,0 +1614661200000,49159.16000000,49402.07000000,48660.28000000,48672.07000000,1944.60465600,1614664799999,95318839.01138939,46463,925.04489500,45331645.20696174,0 +1614664800000,48673.88000000,48846.03000000,48333.00000000,48638.36000000,2733.66015400,1614668399999,132803863.87494007,113819,1346.87413900,65437960.53324578,0 +1614668400000,48631.58000000,48833.10000000,48301.36000000,48331.61000000,2277.99261900,1614671999999,110625788.74445659,99655,1231.21930100,59791562.29107835,0 +1614672000000,48331.60000000,49222.00000000,48270.69000000,48858.08000000,2996.19663500,1614675599999,146165949.21175821,67298,1564.55009300,76329343.62713566,0 +1614675600000,48861.23000000,49265.54000000,48861.22000000,49144.23000000,2269.41548500,1614679199999,111331476.44254829,59578,1029.79736100,50509186.80540750,0 +1614679200000,49144.22000000,49263.95000000,48550.00000000,48721.09000000,2242.27340900,1614682799999,109735288.60017008,59225,1055.02994600,51635794.36524153,0 +1614682800000,48721.09000000,49047.06000000,48550.00000000,48844.13000000,1837.03586300,1614686399999,89672315.55733889,51394,925.98387800,45202432.84676146,0 +1614686400000,48844.14000000,49117.00000000,48568.98000000,48811.03000000,1941.87487100,1614689999999,94695646.41897205,58535,939.50143700,45819256.80625263,0 +1614690000000,48807.45000000,49076.70000000,48712.70000000,49000.00000000,2099.03468900,1614693599999,102661918.65693999,53590,1048.34135100,51275549.02548314,0 +1614693600000,49000.00000000,49699.99000000,48769.32000000,48899.31000000,4150.04648100,1614697199999,204406128.59988017,93972,2043.69139200,100694555.36869732,0 +1614697200000,48899.30000000,49043.99000000,48380.83000000,48676.08000000,3178.21165500,1614700799999,154673872.36398197,74708,1340.28285400,65238082.99869603,0 +1614700800000,48676.09000000,48718.18000000,47265.79000000,47520.01000000,5366.20531800,1614704399999,257575962.00608259,151798,2348.60968800,112738228.67151534,0 +1614704400000,47519.58000000,47982.45000000,47200.00000000,47852.63000000,3662.97735400,1614707999999,174456947.30407828,128730,1829.51643800,87142089.64553995,0 +1614708000000,47852.63000000,48030.48000000,47526.31000000,47678.38000000,1994.87417900,1614711599999,95233303.89670687,93769,952.79825600,45494063.33970039,0 +1614711600000,47678.38000000,47944.43000000,47144.22000000,47467.43000000,2771.26309500,1614715199999,131747693.06842034,98596,1309.93651000,62301181.25787985,0 +1614715200000,47467.43000000,47643.28000000,47047.60000000,47529.57000000,2453.64842600,1614718799999,116231937.36985676,64205,1202.55626400,56972275.63864315,0 +1614718800000,47529.57000000,47870.00000000,47273.01000000,47407.03000000,1932.81103100,1614722399999,91943475.69137602,53329,928.83926000,44190501.89233958,0 +1614722400000,47407.25000000,47960.00000000,47331.96000000,47789.87000000,1253.98626200,1614725999999,59837463.58720565,47363,580.48573900,27703230.00487398,0 +1614726000000,47793.36000000,48489.24000000,47719.70000000,48440.65000000,2859.97632700,1614729599999,137811317.12811264,64383,1511.15246300,72798082.56783824,0 +1614729600000,48436.61000000,48745.13000000,48100.71000000,48507.96000000,2531.59123400,1614733199999,122798419.62848665,53077,1177.89221700,57133626.05636271,0 +1614733200000,48514.80000000,48882.43000000,48458.38000000,48848.63000000,1643.30219000,1614736799999,80018499.29918459,41210,726.73526000,35389387.98642285,0 +1614736800000,48848.63000000,49000.51000000,48528.92000000,48594.07000000,1553.52741800,1614740399999,75752054.89001707,38394,719.59482100,35090864.33090984,0 +1614740400000,48594.06000000,48839.27000000,48494.53000000,48704.75000000,1185.08812100,1614743999999,57663580.92956713,40893,607.00264100,29538436.50475996,0 +1614744000000,48704.75000000,49327.70000000,48653.09000000,49105.47000000,2790.44936100,1614747599999,136996237.70821637,65457,1488.15755300,73047477.71140269,0 +1614747600000,49105.47000000,49466.69000000,48837.00000000,49079.64000000,2164.58725700,1614751199999,106340109.61150006,108475,1065.72382500,52357904.27170272,0 +1614751200000,49078.59000000,49637.39000000,49078.59000000,49529.90000000,2958.78076000,1614754799999,146185107.96353998,93723,1666.72251300,82355738.29385587,0 +1614754800000,49529.90000000,49960.00000000,49474.11000000,49752.97000000,2792.45951800,1614758399999,138931530.68384826,97584,1459.85421200,72631476.78293404,0 +1614758400000,49752.97000000,50998.00000000,49752.97000000,50909.41000000,5488.74934600,1614761999999,277024353.58012751,125973,3143.49451100,158582078.01920919,0 +1614762000000,50909.40000000,51495.00000000,50720.00000000,51445.31000000,5106.81950300,1614765599999,261126093.92694194,132698,2763.20349500,141336464.50458270,0 +1614765600000,51445.31000000,51756.05000000,51187.07000000,51414.19000000,4520.03804600,1614769199999,232747613.88113270,151516,2397.06561200,123449947.65462317,0 +1614769200000,51414.19000000,51777.00000000,51155.33000000,51666.33000000,4391.34593700,1614772799999,226230013.96903974,130413,2396.12146300,123441814.32529159,0 +1614772800000,51665.83000000,52575.17000000,51355.00000000,52540.04000000,5714.41055100,1614776399999,296992452.13045612,127191,3308.02935500,171904075.38866856,0 +1614776400000,52547.23000000,52640.00000000,51188.31000000,51559.50000000,5758.60323800,1614779999999,298239335.78139556,137323,2804.76765100,145233591.21723580,0 +1614780000000,51559.63000000,51564.15000000,50651.00000000,50776.36000000,7069.14955100,1614783599999,360402221.17815262,141576,3365.80942100,171557758.40703310,0 +1614783600000,50776.35000000,51155.00000000,50481.00000000,50767.36000000,4526.07871600,1614787199999,229708968.53050298,130473,2035.28169900,103338304.58871397,0 +1614787200000,50767.35000000,51444.90000000,50750.02000000,51077.00000000,4984.12482500,1614790799999,254824653.29664886,165716,2300.10871300,117606484.26926302,0 +1614790800000,51077.00000000,51449.84000000,50825.18000000,51307.78000000,2696.71573800,1614794399999,138068361.30626659,87905,1283.44169500,65716481.02773078,0 +1614794400000,51305.50000000,51600.00000000,51100.00000000,51233.11000000,2318.50380800,1614797999999,119154743.77854526,60959,1156.39773200,59434033.01814201,0 +1614798000000,51233.11000000,51257.29000000,50260.00000000,50857.17000000,3237.72893200,1614801599999,164086181.75125293,85121,1481.36872300,75059542.89752790,0 +1614801600000,50857.17000000,51172.62000000,50431.37000000,50521.40000000,2027.51565200,1614805199999,103090865.08911168,59000,941.50563200,47881773.56682220,0 +1614805200000,50523.93000000,51123.00000000,50364.64000000,50958.60000000,1734.77098600,1614808799999,88022811.63217602,52301,837.51421800,42524598.54984129,0 +1614808800000,50956.10000000,51356.86000000,50500.00000000,50577.34000000,1805.80320500,1614812399999,91937030.51610346,60526,858.10618500,43715137.90935652,0 +1614812400000,50577.33000000,51068.99000000,50301.50000000,50349.37000000,2035.76981200,1614815999999,103180016.47848618,54627,971.46925200,49259901.39581802,0 +1614816000000,50349.37000000,51147.05000000,49850.81000000,50894.48000000,3929.68063600,1614819599999,197918438.70191361,136711,1730.25342400,87217347.38470511,0 +1614819600000,50894.48000000,51622.94000000,50714.28000000,51475.19000000,3033.52882300,1614823199999,155800990.35958906,71501,1699.67633300,87308878.17578879,0 +1614823200000,51475.14000000,51773.88000000,50790.55000000,50791.63000000,2491.78961200,1614826799999,127904320.77595812,63350,1207.29439800,61990478.73723125,0 +1614826800000,50792.02000000,51033.47000000,49401.30000000,49574.89000000,4911.74132000,1614830399999,246022529.21847696,106305,2092.21946100,104801051.58968789,0 +1614830400000,49574.89000000,49811.66000000,49010.10000000,49065.33000000,3987.47014200,1614833999999,197194266.54437518,99280,1978.71458700,97856280.97287022,0 +1614834000000,49065.32000000,49698.43000000,49034.81000000,49661.35000000,2844.02402400,1614837599999,140413615.69223364,102342,1521.52767900,75117152.19597829,0 +1614837600000,49664.40000000,49870.00000000,49237.49000000,49393.07000000,2645.16712500,1614841199999,131018764.94435118,72059,1176.34274000,58273254.52288077,0 +1614841200000,49393.08000000,49816.00000000,49320.00000000,49696.49000000,2234.03931000,1614844799999,110828678.90419889,109498,1055.00032200,52337421.41246901,0 +1614844800000,49701.37000000,50756.23000000,49688.46000000,50221.61000000,4072.44769000,1614848399999,205017535.42104988,98949,1920.06207300,96645888.47671643,0 +1614848400000,50221.67000000,50225.00000000,48524.86000000,49069.98000000,5990.24725100,1614851999999,293836706.53748163,155675,2850.86327900,139805295.23980407,0 +1614852000000,49069.99000000,49562.49000000,48747.46000000,49219.42000000,3159.20152200,1614855599999,155318797.62700935,82160,1450.19468900,71297604.04786283,0 +1614855600000,49216.96000000,49499.00000000,48898.64000000,49323.32000000,2362.81813700,1614859199999,116380363.77900442,79907,1225.97429300,60394695.34874380,0 +1614859200000,49323.31000000,49764.92000000,49113.63000000,49355.84000000,2548.53514900,1614862799999,125917611.75631470,106501,1271.47501100,62830402.83400939,0 +1614862800000,49355.85000000,49710.00000000,48721.43000000,49633.44000000,3379.86793700,1614866399999,166619030.46277974,90032,1744.42532100,86010212.06358469,0 +1614866400000,49633.44000000,50569.41000000,49205.13000000,49422.53000000,4935.92384900,1614869999999,245794766.67514644,122141,2398.65822600,119450300.31675610,0 +1614870000000,49422.53000000,49812.41000000,48829.07000000,49412.60000000,4123.16341300,1614873599999,203320373.60060322,103220,2125.30199900,104800742.77860544,0 +1614873600000,49412.60000000,50033.92000000,49300.01000000,49693.59000000,2731.21131900,1614877199999,135736787.73498519,81783,1392.03344700,69191403.27582915,0 +1614877200000,49694.60000000,49927.34000000,48319.36000000,48508.07000000,4940.77189000,1614880799999,242741823.79543321,124202,2414.98676600,118688903.20083292,0 +1614880800000,48508.01000000,48666.66000000,47588.52000000,47600.01000000,5960.91355300,1614884399999,286835970.47422675,144059,2727.59863900,131306475.85429757,0 +1614884400000,47600.00000000,48394.04000000,47596.29000000,48000.36000000,3689.38935300,1614887999999,177510471.16833480,115542,1802.29835200,86688235.65910484,0 +1614888000000,48000.37000000,48270.99000000,47500.00000000,48221.00000000,3058.63060700,1614891599999,146501948.75320175,76424,1483.31950500,71073269.89941984,0 +1614891600000,48221.00000000,48434.68000000,47800.00000000,47955.77000000,1971.81794600,1614895199999,94901008.52759783,51084,1041.88162500,50141918.29659669,0 +1614895200000,47955.78000000,48350.00000000,47859.16000000,48249.99000000,1346.51845200,1614898799999,64853394.20502821,50261,732.94692900,35308935.56370703,0 +1614898800000,48249.99000000,48710.94000000,48049.00000000,48374.09000000,2300.81776900,1614902399999,111449045.19746825,48950,1226.92879000,59419406.95733242,0 +1614902400000,48374.09000000,48376.20000000,46512.90000000,46829.84000000,6980.75137400,1614905999999,328721516.54924524,147184,2850.39814000,134215808.17783862,0 +1614906000000,46829.84000000,47000.00000000,46300.00000000,46709.94000000,4433.21166500,1614909599999,206693722.64967049,110525,2172.25014500,101302132.56477424,0 +1614909600000,46709.95000000,47180.85000000,46366.33000000,47108.28000000,3350.86472100,1614913199999,156723197.32219965,72991,1732.80657400,81056202.99890545,0 +1614913200000,47107.25000000,47339.00000000,46800.88000000,47289.81000000,2239.18266700,1614916799999,105421027.90991740,61052,1025.98802000,48309932.46178079,0 +1614916800000,47289.81000000,47307.69000000,46500.00000000,46679.08000000,2082.33394200,1614920399999,97950064.72169799,49715,876.45557600,41235865.38349453,0 +1614920400000,46670.26000000,47253.17000000,46665.73000000,47153.13000000,2232.82222600,1614923999999,104974819.51468483,88227,1125.10198900,52905458.28653990,0 +1614924000000,47153.13000000,47442.01000000,46954.81000000,47396.56000000,2085.31822600,1614927599999,98517743.60347576,53209,1051.94983300,49709329.18608152,0 +1614927600000,47396.56000000,47547.00000000,47010.89000000,47380.00000000,2244.81060200,1614931199999,106162561.02350319,54941,1154.78843200,54615062.09516183,0 +1614931200000,47380.00000000,47500.00000000,46418.12000000,46634.35000000,3887.95356200,1614934799999,182154304.92190576,84285,1868.71969900,87561478.41656940,0 +1614934800000,46635.75000000,47157.43000000,46530.00000000,47063.51000000,2099.12380600,1614938399999,98404068.56155052,81748,1069.29766400,50123416.57233001,0 +1614938400000,47063.50000000,47229.79000000,46780.01000000,47080.97000000,2049.14217000,1614941999999,96466965.17676227,56548,1022.73574500,48147056.34526113,0 +1614942000000,47080.96000000,47523.59000000,47080.96000000,47478.87000000,2364.22037600,1614945599999,111937863.72534426,60511,1234.42823500,58449332.72046962,0 +1614945600000,47478.86000000,47880.00000000,46974.32000000,47649.99000000,3769.82325300,1614949199999,179062291.78839200,91969,1890.51077600,89822202.81165216,0 +1614949200000,47650.00000000,48296.93000000,47325.94000000,48056.18000000,4933.82732300,1614952799999,236340662.63323138,112419,2398.93031500,114929846.39371217,0 +1614952800000,48061.21000000,48728.21000000,47936.51000000,48136.81000000,5144.60762100,1614956399999,248717770.50665324,116319,2514.10997600,121555662.47912867,0 +1614956400000,48136.82000000,48698.19000000,47837.83000000,47867.45000000,3709.70111800,1614959999999,178860366.42656119,137384,1948.05050400,93911930.76677332,0 +1614960000000,47867.45000000,47867.45000000,46885.00000000,47658.14000000,5565.80565100,1614963599999,264110340.34202984,145730,2898.83900300,137588239.24386049,0 +1614963600000,47656.65000000,48237.42000000,47320.00000000,48096.01000000,3532.14967600,1614967199999,169030691.69754073,73267,1771.06620500,84768832.99502807,0 +1614967200000,48096.00000000,48558.50000000,47918.38000000,48478.11000000,3039.36504800,1614970799999,146912674.73393674,102775,1519.11297900,73436368.93067457,0 +1614970800000,48478.12000000,49400.00000000,48310.40000000,49295.47000000,3687.78444400,1614974399999,180194817.83148679,81593,2000.57971300,97749213.50761805,0 +1614974400000,49285.76000000,49448.93000000,48832.17000000,49173.85000000,2917.73505300,1614977999999,143449027.15022502,98086,1373.60348600,67531426.71356788,0 +1614978000000,49173.85000000,49398.00000000,48890.97000000,49035.21000000,2046.17724000,1614981599999,100533176.65973319,49623,901.49816000,44284505.17435807,0 +1614981600000,49035.20000000,49389.99000000,48673.71000000,49061.76000000,1773.89885300,1614985199999,87064645.44800825,68027,847.37477500,41588318.89630794,0 +1614985200000,49061.77000000,49160.29000000,48579.59000000,48751.71000000,2021.88575500,1614988799999,98728783.93955465,56088,1069.71443300,52227389.09566100,0 +1614988800000,48746.81000000,49156.00000000,48675.67000000,48808.05000000,1845.19339200,1614992399999,90328263.10627944,50809,831.66585500,40712519.85447785,0 +1614992400000,48807.83000000,48901.65000000,48520.00000000,48647.38000000,1293.84492500,1614995999999,62960628.37109181,36753,686.71059800,33415823.72733721,0 +1614999600000,48647.37000000,48801.81000000,48350.00000000,48657.72000000,818.44067300,1615003199999,39764114.17495608,24356,390.87255100,18994831.45205219,0 +1615003200000,48657.72000000,48687.49000000,48115.83000000,48451.16000000,1726.74406000,1615006799999,83446085.40417748,65417,838.47796700,40521172.94952703,0 +1615006800000,48450.12000000,48895.32000000,48193.00000000,48496.28000000,1653.75943400,1615010399999,80307401.56732063,60397,797.99258200,38755342.22985057,0 +1615010400000,48496.27000000,48971.29000000,48482.17000000,48922.00000000,1754.07195500,1615013999999,85589315.54183216,45201,814.31175800,39727407.03789698,0 +1615014000000,48922.00000000,49117.32000000,48772.24000000,48820.12000000,1647.18114200,1615017599999,80636495.63993865,44370,828.00818800,40541376.07465345,0 +1615017600000,48820.13000000,49100.00000000,48600.00000000,48641.64000000,2233.92258700,1615021199999,109189858.35294529,94092,1019.19495900,49830387.27238900,0 +1615021200000,48641.65000000,48785.00000000,48270.01000000,48335.10000000,1882.87757900,1615024799999,91307735.75840453,48858,968.13415000,46956183.45522934,0 +1615024800000,48335.22000000,48499.99000000,48000.00000000,48035.36000000,2154.95648200,1615028399999,103866218.01211190,86010,799.33601400,38574224.33102557,0 +1615028400000,48035.37000000,48331.91000000,48000.00000000,48171.01000000,1402.21562700,1615031999999,67556132.69875654,65040,720.06973300,34694811.70184996,0 +1615032000000,48171.02000000,48212.85000000,47401.82000000,47660.74000000,3296.63806100,1615035599999,157314265.41861050,107114,1500.30716100,71558286.31501310,0 +1615035600000,47660.75000000,47753.39000000,47070.00000000,47320.30000000,3107.86133500,1615039199999,147223560.49443072,111334,1571.47825100,74445086.16189465,0 +1615039200000,47320.30000000,47725.51000000,47201.12000000,47560.96000000,1820.41148200,1615042799999,86454116.60397910,85390,887.38063000,42145146.74546724,0 +1615042800000,47562.67000000,47712.69000000,47238.32000000,47267.88000000,1475.15553400,1615046399999,70130991.28769348,64970,643.01072600,30570476.13868999,0 +1615046400000,47267.88000000,47941.03000000,47104.85000000,47757.43000000,2487.13413100,1615049999999,118538409.63733009,67272,1233.57733000,58804306.46299256,0 +1615050000000,47755.08000000,48450.00000000,47655.01000000,48250.69000000,2674.93363700,1615053599999,128615238.60874081,74126,1417.64681900,68178381.97808647,0 +1615053600000,48250.70000000,48623.00000000,48109.79000000,48473.30000000,2003.05469900,1615057199999,96878694.16266076,60766,1000.80385800,48414740.66004490,0 +1615057200000,48473.30000000,48690.60000000,48248.27000000,48341.01000000,1584.42261600,1615060799999,76741497.69559580,55227,752.46265000,36448564.22125696,0 +1615060800000,48341.00000000,48734.84000000,48223.36000000,48518.50000000,2390.26653700,1615064399999,115903829.22444935,64961,1131.75658000,54877668.79805545,0 +1615064400000,48518.51000000,48723.00000000,48264.63000000,48578.71000000,1716.06082200,1615067999999,83333485.92817200,45864,853.45273200,41443886.40759648,0 +1615068000000,48577.22000000,49200.00000000,48463.75000000,48920.88000000,1991.42598100,1615071599999,97393078.60634556,64007,1087.31707300,53176565.98816272,0 +1615071600000,48920.87000000,49120.01000000,48805.00000000,48882.20000000,1438.66155100,1615075199999,70431288.99568053,54140,726.64745200,35578683.01640515,0 +1615075200000,48882.20000000,49312.00000000,48882.20000000,49203.25000000,2100.25945600,1615078799999,103198224.50174948,50983,970.03890400,47668550.32244923,0 +1615078800000,49203.25000000,49490.00000000,48982.17000000,49121.95000000,2165.86194700,1615082399999,106634203.07368673,55306,1075.88714600,52971496.16525737,0 +1615082400000,49121.95000000,49851.00000000,49052.91000000,49550.58000000,2579.98201800,1615085999999,127803055.39798113,66389,1312.80248700,65019805.77740570,0 +1615086000000,49550.57000000,49900.99000000,49433.88000000,49551.44000000,1952.16124400,1615089599999,96921817.82949490,45080,1107.94368900,55006437.20451545,0 +1615089600000,49551.43000000,49687.98000000,49296.80000000,49436.18000000,1523.22473900,1615093199999,75402078.26888658,39760,800.13952600,39611555.27593347,0 +1615093200000,49436.18000000,49459.25000000,49111.11000000,49342.00000000,1579.32018600,1615096799999,77820439.49386912,42161,804.41909400,39636770.77620378,0 +1615096800000,49342.00000000,49650.00000000,49146.68000000,49458.56000000,1487.21177300,1615100399999,73428065.58674330,40988,782.70461900,38646695.30076986,0 +1615100400000,49459.61000000,50179.17000000,49327.57000000,50052.68000000,1987.00673700,1615103999999,98810047.42277223,59667,1170.22996700,58216821.35403710,0 +1615104000000,50041.84000000,50839.54000000,50041.84000000,50383.09000000,4309.51042700,1615107599999,217681721.76721014,102837,2278.35695200,115075147.33173563,0 +1615107600000,50384.11000000,51148.22000000,50384.11000000,50943.02000000,4216.98337700,1615111199999,214282778.69557453,92581,1954.81008400,99350510.16871535,0 +1615111200000,50942.82000000,50985.84000000,50448.30000000,50612.92000000,2825.81054000,1615114799999,143295200.53975447,77271,1378.18459300,69882515.37060364,0 +1615114800000,50612.92000000,50899.22000000,50472.81000000,50705.52000000,2058.27371500,1615118399999,104312732.69251849,95481,966.46236400,48974258.26926097,0 +1615118400000,50705.52000000,50827.68000000,50391.19000000,50746.20000000,1924.67203300,1615121999999,97483869.91578244,98865,982.09945300,49745023.69876585,0 +1615122000000,50746.20000000,50850.00000000,50504.22000000,50764.44000000,1476.16870900,1615125599999,74825391.39357174,78201,786.47793900,39869761.83968621,0 +1615125600000,50764.44000000,51250.00000000,50130.65000000,50646.34000000,3464.33850600,1615129199999,175437666.26768617,132882,1812.38114600,91831991.42017184,0 +1615129200000,50644.47000000,50827.93000000,50375.00000000,50585.23000000,1711.75694000,1615132799999,86620570.80002084,82961,831.83894100,42101517.74190130,0 +1615132800000,50585.23000000,51352.10000000,50585.23000000,51052.90000000,3580.06799000,1615136399999,182478941.68802877,142491,1928.84970800,98306982.13874969,0 +1615136400000,51052.89000000,51201.00000000,50757.59000000,51075.93000000,2180.45262000,1615139999999,111189339.99283847,72122,1004.53434100,51215894.92970774,0 +1615140000000,51075.92000000,51085.71000000,50368.20000000,50412.31000000,1905.27267300,1615143599999,96571297.83960345,55137,823.15249100,41713682.58501177,0 +1615143600000,50412.31000000,50580.21000000,50250.00000000,50381.68000000,1644.62770800,1615147199999,82922192.40165974,56614,777.78155300,39217774.29134322,0 +1615147200000,50381.69000000,50381.69000000,49758.01000000,50036.64000000,2640.36389100,1615150799999,131910392.54777115,75982,1291.97714300,64531393.41747630,0 +1615150800000,50036.63000000,50265.81000000,49833.08000000,50086.12000000,1456.99025200,1615154399999,72905828.80531929,46097,737.53448100,36904326.21658190,0 +1615154400000,50086.11000000,50784.12000000,49986.39000000,50498.55000000,1517.24544000,1615157999999,76506985.44567601,57815,805.72865300,40637640.32013040,0 +1615158000000,50498.56000000,51450.03000000,50480.89000000,50971.75000000,2947.46511100,1615161599999,150433067.08092704,90430,1501.26169000,76646327.80473961,0 +1615161600000,50959.11000000,51685.00000000,50843.59000000,51491.10000000,3257.85465200,1615165199999,167532220.80472599,87283,1664.75015900,85625625.09715073,0 +1615165200000,51491.10000000,51847.38000000,51250.05000000,51557.70000000,2584.40645400,1615168799999,133321736.21101052,68603,1386.32360900,71527975.71411801,0 +1615168800000,51557.70000000,51594.22000000,50481.84000000,50730.82000000,2903.06562400,1615172399999,148006873.56592111,91650,1345.21497000,68578272.37141787,0 +1615172400000,50730.82000000,50808.32000000,50234.98000000,50598.49000000,2601.68625600,1615175999999,131406016.57716334,78549,1357.85207700,68578506.12065437,0 +1615176000000,50598.49000000,50598.50000000,50100.00000000,50417.44000000,2251.80367300,1615179599999,113395708.42521138,74157,976.48451800,49163995.41399760,0 +1615179600000,50417.45000000,50816.16000000,50355.16000000,50765.77000000,2044.28415900,1615183199999,103420379.41058103,50504,869.21726000,43967243.94008993,0 +1615183200000,50765.77000000,50944.00000000,50150.42000000,50274.76000000,2858.16042200,1615186799999,144355922.99870986,68636,1336.25596400,67455288.09774121,0 +1615186800000,50274.76000000,50427.53000000,49521.20000000,49755.24000000,4023.21432200,1615190399999,200668275.32925711,144588,1873.21801200,93429823.19165830,0 +1615190400000,49755.24000000,49888.59000000,49274.67000000,49880.35000000,3692.48248300,1615193999999,183134555.22723845,113084,2047.76088700,101577562.53025498,0 +1615194000000,49880.49000000,50099.97000000,49400.00000000,49880.00000000,2802.45034100,1615197599999,139353571.38893106,87412,1425.30809600,70870549.56441601,0 +1615197600000,49883.13000000,50271.67000000,49682.30000000,50061.00000000,2791.02336900,1615201199999,139630861.87948468,83384,1306.78230300,65377786.40296342,0 +1615201200000,50061.01000000,50560.00000000,49878.00000000,50496.82000000,2218.68353400,1615204799999,111303263.46838359,67392,1046.06135000,52500038.21727070,0 +1615204800000,50490.39000000,50550.00000000,50100.01000000,50275.00000000,2463.59128000,1615208399999,123859515.93219230,106998,1230.16748800,61832507.38718820,0 +1615208400000,50274.58000000,51065.63000000,50265.16000000,50978.43000000,3657.93876700,1615211999999,185567165.97821940,96513,1959.70080200,99433094.01405771,0 +1615212000000,50978.42000000,51233.00000000,50122.45000000,50740.90000000,3500.51925400,1615215599999,177662740.73706399,90866,1728.69959400,87764612.54062723,0 +1615215600000,50744.26000000,51220.00000000,50541.67000000,51054.99000000,3226.78819100,1615219199999,164440816.09683350,100209,1585.30549900,80788201.25393567,0 +1615219200000,51055.00000000,51175.00000000,50550.01000000,50664.91000000,2348.85657100,1615222799999,119420974.82149234,94450,1086.43708300,55242344.20254800,0 +1615222800000,50664.91000000,50880.00000000,50630.00000000,50809.04000000,1704.21204600,1615226399999,86504651.13651521,50012,847.61082300,43022964.53166323,0 +1615226400000,50801.55000000,51075.40000000,50732.36000000,50803.18000000,1705.52357700,1615229999999,86766065.46065339,55683,906.68032900,46127826.51742071,0 +1615230000000,50803.19000000,51485.35000000,50790.00000000,51310.82000000,2750.06832100,1615233599999,140806609.39956926,78017,1554.60407500,79595830.83252232,0 +1615233600000,51310.82000000,51996.58000000,51236.20000000,51759.63000000,3743.68592700,1615237199999,193227154.41797584,91822,2046.41460200,105638054.54415526,0 +1615237200000,51762.77000000,51927.00000000,51505.00000000,51848.33000000,2386.92988300,1615240799999,123383951.07238626,69111,1226.12339700,63380257.47346715,0 +1615240800000,51848.34000000,51900.00000000,51300.00000000,51599.99000000,2086.90564400,1615244399999,107715294.63750250,64080,996.38337000,51424034.54236948,0 +1615244400000,51599.99000000,52402.78000000,51599.99000000,52375.17000000,3383.22491400,1615247999999,175963606.05905191,86398,1792.07330300,93215403.60381130,0 +1615248000000,52375.18000000,52540.48000000,51789.41000000,52020.23000000,3791.40283500,1615251599999,197912696.36021609,87276,1664.14966100,86874880.25037327,0 +1615251600000,52020.24000000,53760.00000000,51981.26000000,53575.35000000,7510.12043300,1615255199999,399283702.06985720,175064,3768.11309800,200164678.25920825,0 +1615255200000,53575.35000000,53799.00000000,53250.41000000,53592.70000000,3698.60810800,1615258799999,197955885.60833725,85448,1754.37336900,93895295.30641556,0 +1615258800000,53592.84000000,54100.00000000,53452.47000000,53840.62000000,3755.86080800,1615262399999,202076703.45060345,123817,2013.20313100,108337810.89619365,0 +1615262400000,53840.63000000,54040.00000000,53484.44000000,53678.88000000,2461.50389000,1615265999999,132389835.35042694,105442,1212.58073500,65232255.48113861,0 +1615266000000,53684.14000000,54400.80000000,53681.44000000,54254.52000000,3270.83220000,1615269599999,177122662.01191597,105492,1617.87522500,87612894.14903043,0 +1615269600000,54254.52000000,54448.00000000,53737.00000000,53847.64000000,3100.27232600,1615273199999,167775430.98412366,105727,1472.88790800,79711132.13164485,0 +1615273200000,53847.64000000,53890.92000000,53409.57000000,53546.90000000,3215.78379400,1615276799999,172686602.92112191,89948,1660.18673600,89151626.76902997,0 +1615276800000,53546.89000000,54168.99000000,53274.96000000,54023.79000000,2853.62344200,1615280399999,153610890.80429791,85740,1417.53674300,76321973.66824262,0 +1615280400000,54023.79000000,54270.27000000,53872.05000000,54112.50000000,2719.14579200,1615283999999,147119316.09875463,109901,1324.06080600,71645321.27726512,0 +1615284000000,54112.50000000,54355.00000000,53875.00000000,54159.52000000,3441.45900400,1615287599999,186327392.60715713,84266,1855.50604200,100465270.82105504,0 +1615287600000,54159.52000000,54293.97000000,53917.21000000,54233.32000000,2086.75598400,1615291199999,112971333.32137995,74794,1091.29870400,59083177.99982496,0 +1615291200000,54235.88000000,54236.70000000,53538.77000000,53725.50000000,2514.80248000,1615294799999,135616547.02971201,85101,1219.35717200,65770018.74282352,0 +1615294800000,53725.49000000,54815.84000000,53664.21000000,54779.99000000,4188.62268200,1615298399999,227723165.86607819,95413,2150.28053700,116843910.89693138,0 +1615298400000,54780.26000000,54787.99000000,54364.32000000,54488.22000000,3828.42272800,1615301999999,208801703.42261675,88343,1713.49493600,93455110.78079582,0 +1615302000000,54491.33000000,54515.22000000,53852.36000000,54097.02000000,3283.75887800,1615305599999,178144082.57325058,87761,1620.73577500,87930796.04115975,0 +1615305600000,54097.03000000,54338.00000000,53750.00000000,54098.11000000,2509.81294500,1615309199999,135766937.13154166,81155,1198.87510800,64862537.00357689,0 +1615309200000,54098.10000000,54272.05000000,53770.71000000,53793.76000000,1643.37624400,1615312799999,88748904.97034261,55343,756.51538000,40857782.17084192,0 +1615312800000,53793.75000000,54046.78000000,53626.97000000,53885.96000000,1917.18194000,1615316399999,103252757.97341270,64916,853.52832300,45971308.90448470,0 +1615316400000,53885.96000000,54225.35000000,53790.00000000,54108.79000000,1688.78796300,1615319999999,91204342.10730320,52793,764.36135600,41284647.62990380,0 +1615320000000,54108.79000000,54584.19000000,54052.76000000,54326.14000000,2231.22065500,1615323599999,121220201.85818624,64958,919.93164000,49982072.82172721,0 +1615323600000,54326.14000000,54519.47000000,53882.52000000,54278.61000000,2200.55778200,1615327199999,119259800.97293867,107247,991.92819400,53764999.76525669,0 +1615327200000,54278.61000000,54860.28000000,54139.10000000,54808.75000000,1795.94455500,1615330799999,97889012.49945934,110379,998.30357900,54433604.60717156,0 +1615330800000,54808.76000000,54895.00000000,54474.99000000,54884.50000000,1948.87960800,1615334399999,106591056.66186947,68074,972.45692800,53191667.31053432,0 +1615334400000,54874.67000000,55763.00000000,54782.93000000,55510.00000000,5030.93125900,1615337999999,278163888.80423138,123240,2865.37255900,158451994.67947400,0 +1615338000000,55510.01000000,55813.09000000,54468.26000000,54676.87000000,3691.17587200,1615341599999,203388526.25539069,108462,1723.70589000,95018007.02153540,0 +1615341600000,54676.86000000,54676.87000000,53300.00000000,53936.44000000,5819.53214700,1615345199999,313787381.36255326,184750,2818.00969300,151971986.61652164,0 +1615345200000,53936.43000000,54126.67000000,53134.80000000,53467.80000000,3497.09674400,1615348799999,187553477.50767544,128407,1721.73624900,92340567.68327365,0 +1615348800000,53468.33000000,53837.16000000,53332.46000000,53647.63000000,1979.67065800,1615352399999,106022641.77677777,90802,1016.04946000,54420863.19915381,0 +1615352400000,53647.63000000,53692.21000000,53005.00000000,53651.39000000,2203.22310100,1615355999999,117817036.44144045,61148,1003.51678300,53671721.06711454,0 +1615356000000,53651.38000000,54065.65000000,53510.01000000,53864.41000000,2538.97931000,1615359599999,136586624.91054384,66401,1181.66589300,63576141.89829709,0 +1615359600000,53864.40000000,54407.74000000,53826.26000000,54173.38000000,3010.88572800,1615363199999,163063921.96133852,73576,1305.89170000,70694918.41897156,0 +1615363200000,54177.47000000,54734.96000000,54032.38000000,54632.79000000,2225.61026900,1615366799999,121263076.05268722,68375,1075.33229800,58597179.33791266,0 +1615366800000,54632.78000000,55444.00000000,54300.11000000,55227.99000000,3499.58051200,1615370399999,192174619.38342005,117610,1883.97487600,103469981.96843685,0 +1615370400000,55228.00000000,55389.00000000,54679.95000000,54832.98000000,2604.47748200,1615373999999,143232395.10989021,74415,1258.61416200,69219098.23965225,0 +1615374000000,54832.99000000,54991.00000000,54512.00000000,54858.47000000,2400.09979600,1615377599999,131435336.54839869,72473,1242.54503400,68049556.66874276,0 +1615377600000,54858.47000000,55481.28000000,54834.00000000,55219.99000000,2894.17949200,1615381199999,159715138.18974388,96315,1435.42521300,79210645.41164055,0 +1615381200000,55219.99000000,56333.00000000,55139.01000000,56262.56000000,5022.45430700,1615384799999,280601614.94202186,168592,2834.61204000,158395300.22812159,0 +1615384800000,56260.09000000,56400.00000000,55761.66000000,56092.62000000,4222.23944600,1615388399999,236711475.65369735,105277,2216.06998300,124253250.76830775,0 +1615388400000,56092.62000000,56489.66000000,55952.63000000,56328.81000000,3869.22929400,1615391999999,217544118.14182842,119846,2033.89209200,114362468.87187820,0 +1615392000000,56328.81000000,57075.92000000,56100.00000000,57009.53000000,4890.44202100,1615395599999,276608476.15814133,158136,2688.45561000,152151018.94701652,0 +1615395600000,57009.53000000,57100.00000000,56366.00000000,56860.01000000,4201.85636100,1615399199999,238726485.19676862,112830,2078.51722400,118097883.35913201,0 +1615399200000,56860.01000000,57100.00000000,56566.00000000,56730.54000000,3021.74944600,1615402799999,171672296.48973269,112253,1527.95686100,86833386.89608197,0 +1615402800000,56730.55000000,57387.69000000,56595.76000000,56739.40000000,3678.78143400,1615406399999,209778225.64322700,113397,1948.74731500,111142625.66022464,0 +1615406400000,56739.40000000,56894.11000000,56037.15000000,56266.00000000,4313.70234300,1615409999999,243351448.84513943,103580,2056.77838800,116032467.81399536,0 +1615410000000,56266.00000000,57045.22000000,55530.01000000,56918.40000000,4757.62006100,1615413599999,267433343.98345132,137896,2238.29399300,125891109.13654264,0 +1615413600000,56919.10000000,57225.73000000,56476.95000000,56905.37000000,2148.26032300,1615417199999,122097690.91867705,122720,1031.85684900,58640715.97042828,0 +1615417200000,56905.37000000,56950.00000000,55800.00000000,55851.59000000,3227.46153700,1615420799999,181468323.08243598,126783,1464.86724000,82363403.00431579,0 +1615420800000,55851.59000000,56499.98000000,55505.00000000,55601.55000000,3761.55064900,1615424399999,210353015.90269695,90868,1696.50550100,94915524.54606974,0 +1615424400000,55607.55000000,55947.36000000,55170.22000000,55781.92000000,2880.27800500,1615427999999,159874580.29863754,101593,1368.35340200,75951107.75153002,0 +1615428000000,55781.91000000,56323.51000000,55649.93000000,56314.58000000,2435.82663700,1615431599999,136454058.76350731,75084,1144.62183700,64131823.51034431,0 +1615431600000,56316.41000000,56483.11000000,55599.00000000,55992.60000000,2196.10924700,1615435199999,122958150.58607872,55310,1008.88913300,56489560.21144334,0 +1615435200000,55992.60000000,56179.87000000,55603.66000000,55835.40000000,1923.30227900,1615438799999,107433105.09803673,53208,867.97644500,48494019.10522811,0 +1615438800000,55835.39000000,55835.39000000,55200.80000000,55275.32000000,2300.08825500,1615442399999,127532060.63464739,59755,1026.44407700,56917529.14522981,0 +1615442400000,55275.32000000,55767.15000000,55005.00000000,55557.94000000,2896.87139900,1615445999999,160614869.33489713,88276,1212.49627000,67219434.03965599,0 +1615446000000,55555.13000000,55797.07000000,55005.00000000,55034.20000000,2820.53245100,1615449599999,156384279.72275556,67395,1232.04863500,68339656.64406550,0 +1615449600000,55034.21000000,55093.53000000,54272.82000000,54761.02000000,5458.58310800,1615453199999,298607963.54632673,163889,2560.04374100,140024508.03798743,0 +1615453200000,54761.01000000,54928.43000000,54431.86000000,54474.27000000,2587.03118800,1615456799999,141452638.84688428,104738,1153.32501000,63068186.21338541,0 +1615456800000,54474.27000000,55612.95000000,54414.40000000,55530.60000000,3587.14363000,1615460399999,197503390.76972889,103026,1736.73689000,95653283.58413024,0 +1615460400000,55530.59000000,56270.75000000,55407.18000000,56227.34000000,3528.16672500,1615463999999,196688903.37317042,137451,1746.61171400,97389590.63372770,0 +1615464000000,56233.42000000,56445.09000000,55702.09000000,56272.54000000,3821.53970800,1615467599999,214419408.69514294,120863,2079.66945400,116708252.86877621,0 +1615467600000,56275.00000000,56999.00000000,56272.54000000,56921.18000000,3907.83970500,1615471199999,221504818.85517440,105871,2166.02927900,122786018.61260917,0 +1615471200000,56921.18000000,57238.50000000,56462.48000000,56815.13000000,4930.07917700,1615474799999,280477535.35700521,113826,2610.84844900,148553409.34894555,0 +1615474800000,56815.13000000,57091.06000000,55855.00000000,56347.19000000,4918.27352200,1615478399999,277865272.78465665,132208,2348.87395600,132736207.88730156,0 +1615478400000,56347.19000000,57030.00000000,56340.06000000,56872.10000000,3501.18927600,1615481999999,198572717.14887414,111203,1874.83613400,106345667.99200097,0 +1615482000000,56872.10000000,57050.00000000,56269.76000000,56802.88000000,3424.87557200,1615485599999,194291111.72167817,118769,1684.21031000,95569536.95695499,0 +1615485600000,56802.88000000,57682.00000000,56531.67000000,57519.86000000,4910.64605200,1615489199999,281082821.13913408,164860,2879.09497200,164857199.07505495,0 +1615489200000,57519.86000000,57651.35000000,56628.03000000,56827.84000000,2840.07287800,1615492799999,162499210.35406519,95082,1414.14052500,80929865.24310701,0 +1615492800000,56823.78000000,57600.00000000,56560.00000000,57457.36000000,3049.18616700,1615496399999,174323211.05670353,113435,1521.53775300,87003639.98001721,0 +1615496400000,57457.36000000,57900.00000000,57235.29000000,57562.49000000,4464.24661700,1615499999999,257564954.44470721,118133,2252.67833000,129995977.23068369,0 +1615500000000,57573.70000000,58050.00000000,57462.12000000,57874.67000000,2810.01435900,1615503599999,162377609.21271529,136545,1485.20548800,85852721.92193145,0 +1615503600000,57882.57000000,58150.00000000,57604.16000000,57773.16000000,2961.36625300,1615507199999,171530513.35499559,78582,1532.27236300,88772098.55492637,0 +1615507200000,57773.15000000,58081.51000000,56777.77000000,57362.04000000,4018.33941800,1615510799999,230508156.35945129,134725,1818.08041000,104320105.25958165,0 +1615510800000,57362.05000000,57640.34000000,56624.00000000,56902.80000000,2607.21431900,1615514399999,149079401.68997003,114182,1240.52590800,70947086.08468645,0 +1615514400000,56902.80000000,57120.67000000,56700.00000000,56972.08000000,1664.62869900,1615517999999,94746373.78696695,70797,794.81942400,45243034.81560026,0 +1615518000000,56972.08000000,57294.47000000,56800.00000000,57104.17000000,1559.93359700,1615521599999,88961260.28276833,49973,761.14216000,43413589.44827765,0 +1615521600000,57107.14000000,57238.70000000,56456.58000000,56696.17000000,2369.87029900,1615525199999,134411337.01335934,66996,1031.56377100,58510635.64214419,0 +1615525200000,56696.18000000,57269.87000000,56350.00000000,57164.51000000,2283.87379200,1615528799999,129789530.71142608,69906,1128.04023600,64124927.24905406,0 +1615528800000,57168.24000000,57430.00000000,56894.49000000,57061.52000000,2057.80177800,1615532399999,117619076.35749922,68727,1035.96080400,59220887.22747215,0 +1615532400000,57061.52000000,57061.53000000,56456.71000000,56670.90000000,2870.52267600,1615535999999,162772861.65533323,77700,1440.14415300,81661907.25243049,0 +1615536000000,56670.90000000,57095.76000000,56259.79000000,56503.21000000,3164.29780600,1615539599999,179199309.03937183,98671,1533.97206400,86892152.12575596,0 +1615539600000,56506.71000000,56819.42000000,56311.00000000,56540.53000000,2384.20281800,1615543199999,134846075.46292302,72558,1096.98013800,62041774.84713004,0 +1615543200000,56540.53000000,56866.83000000,55826.05000000,56715.97000000,3955.42674200,1615546799999,222654294.08345982,111261,1931.75464500,108780158.60526391,0 +1615546800000,56715.97000000,57073.48000000,56347.00000000,56500.00000000,2990.14879600,1615550399999,169660312.34448261,143232,1436.44442200,81511264.82595460,0 +1615550400000,56499.99000000,56844.61000000,56179.47000000,56386.89000000,2404.35050800,1615553999999,135679621.30430332,87431,1167.11705000,65871600.70213599,0 +1615554000000,56385.97000000,56391.25000000,54962.84000000,55689.99000000,8573.23928300,1615557599999,476655241.56194007,258557,3933.54816400,218767849.41357745,0 +1615557600000,55689.99000000,56252.77000000,55368.42000000,56211.83000000,3760.79857900,1615561199999,209965143.95426218,142307,1899.51679500,106074466.50853060,0 +1615561200000,56221.53000000,57095.41000000,56025.20000000,56956.95000000,4384.39718600,1615564799999,248013123.58209527,140803,2373.42698400,134272670.05564597,0 +1615564800000,56956.96000000,57625.91000000,56956.95000000,57367.21000000,4127.97399200,1615568399999,236584058.17017194,120676,2255.18753800,129253583.05823978,0 +1615568400000,57367.21000000,57768.00000000,57062.31000000,57175.99000000,2912.77803200,1615571999999,167389828.43288778,105122,1337.48670200,76849459.49283539,0 +1615572000000,57175.26000000,57667.79000000,57070.00000000,57349.23000000,2355.16939400,1615575599999,135217315.90090701,64578,1254.78695300,72036826.11114289,0 +1615575600000,57349.24000000,57547.07000000,56712.51000000,56942.41000000,2759.49276100,1615579199999,157560117.21653335,76856,1346.64805100,76894391.52923280,0 +1615579200000,56942.41000000,57200.00000000,56400.00000000,56696.80000000,3482.30673400,1615582799999,197381435.60371237,103916,1628.03761400,92278016.38806870,0 +1615582800000,56696.81000000,57170.00000000,56262.14000000,56936.78000000,2554.41954900,1615586399999,144882646.37166268,123258,1234.56876500,70050444.56596873,0 +1615586400000,56936.78000000,57465.38000000,56859.06000000,57157.29000000,2252.89020400,1615589999999,128889329.20606505,107068,1090.60234600,62389139.17149281,0 +1615590000000,57157.29000000,57500.00000000,57153.68000000,57221.72000000,1911.32908500,1615593599999,109588876.28728603,80631,1032.58636500,59210330.09320884,0 +1615593600000,57221.72000000,57307.20000000,56312.91000000,56689.35000000,2913.36172600,1615597199999,165168452.54477606,113394,1417.09885200,80336764.68534269,0 +1615597200000,56689.36000000,56707.00000000,56081.59000000,56386.39000000,2358.62457700,1615600799999,132887326.66178754,74110,1151.11350100,64862774.93364839,0 +1615600800000,56386.39000000,56639.54000000,56078.23000000,56473.41000000,2183.69769500,1615604399999,123160401.31981544,60691,1223.91871700,69032245.32164948,0 +1615604400000,56473.41000000,56790.00000000,56308.98000000,56694.32000000,1902.37529900,1615607999999,107744212.64804490,54805,950.26145200,53819559.32391189,0 +1615608000000,56694.32000000,56899.00000000,56257.47000000,56896.32000000,1547.93218100,1615611599999,87520342.53587563,52050,782.23049200,44236447.06928076,0 +1615611600000,56882.74000000,57090.46000000,56610.00000000,56744.89000000,1432.00306800,1615615199999,81423246.77819168,49512,683.34391900,38858981.70426900,0 +1615615200000,56744.89000000,57060.86000000,56491.92000000,56931.58000000,1759.40972700,1615618799999,99851921.21550119,57668,1017.24287500,57722872.08075861,0 +1615618800000,56931.57000000,57389.58000000,56753.90000000,57343.70000000,1998.20036800,1615622399999,113909858.80102126,69690,1028.78919900,58662494.06794287,0 +1615622400000,57343.70000000,57649.03000000,57126.20000000,57434.31000000,2957.35947100,1615625999999,169868896.01532680,85667,1636.12207400,93990427.23668130,0 +1615626000000,57434.30000000,57614.52000000,57253.31000000,57610.77000000,1827.03931000,1615629599999,104898332.10026139,62926,960.81918100,55167917.14087029,0 +1615629600000,57610.77000000,59850.00000000,57446.81000000,59448.19000000,12696.97324300,1615633199999,750024013.95725474,308276,6970.79882700,411352961.91663017,0 +1615633200000,59448.20000000,60200.00000000,59420.99000000,59849.74000000,9101.22864900,1615636799999,544708721.09328957,230042,5410.48940700,323841046.32586433,0 +1615636800000,59853.58000000,60500.00000000,59232.53000000,59911.99000000,5886.08542200,1615640399999,352958744.72774301,152578,2983.04807900,178934553.17226557,0 +1615640400000,59911.99000000,60159.45000000,59500.00000000,59915.25000000,3621.79620900,1615643999999,216545084.88078375,125555,1860.58251200,111263139.20593685,0 +1615644000000,59915.30000000,60087.09000000,59700.67000000,59756.45000000,2295.31131800,1615647599999,137491113.63501919,123378,1178.62234500,70603882.18347910,0 +1615647600000,59761.93000000,59953.63000000,59523.00000000,59692.99000000,2357.24358600,1615651199999,140901493.52422564,109010,1038.61150400,62081067.12577019,0 +1615651200000,59693.00000000,59924.18000000,59458.67000000,59820.43000000,2721.30396300,1615654799999,162527909.67512986,78798,1488.98656700,88925467.77484757,0 +1615654800000,59820.39000000,60520.00000000,59751.70000000,60333.33000000,3328.78742800,1615658399999,200018042.39036289,90171,1629.79518600,97905366.36486346,0 +1615658400000,60333.33000000,60451.39000000,59977.60000000,60281.95000000,2419.09522400,1615661999999,145583487.30112188,73902,1202.73477600,72388179.96026483,0 +1615662000000,60281.95000000,60864.97000000,60144.20000000,60773.56000000,3093.95316800,1615665599999,187200648.05200946,92026,1723.99670400,104318320.72619846,0 +1615665600000,60773.56000000,61844.00000000,60651.74000000,61648.26000000,6042.50281900,1615669199999,370846057.04175508,162598,3694.46812800,226772352.26017361,0 +1615669200000,61648.26000000,61737.02000000,60605.50000000,61151.07000000,4486.03221700,1615672799999,274099735.55532582,163963,2167.40269400,132488084.65847787,0 +1615672800000,61156.40000000,61311.19000000,60767.62000000,61096.04000000,1770.67694100,1615676399999,108082107.64509043,100492,870.90845200,53168252.09290489,0 +1615676400000,61091.75000000,61480.00000000,61089.98000000,61188.39000000,2544.09773700,1615679999999,155963303.14626481,67700,1315.84647500,80657657.44076047,0 +1615680000000,61188.38000000,61724.79000000,60900.00000000,61260.48000000,2902.15756100,1615683599999,178152245.82840269,78033,1479.97667400,90847893.62271734,0 +1615683600000,61260.47000000,61260.48000000,60724.26000000,61081.00000000,2275.23627800,1615687199999,138789298.91416191,70486,1047.79405500,63914782.16084928,0 +1615687200000,61081.00000000,61218.20000000,60788.01000000,61061.27000000,1563.80244800,1615690799999,95357203.88183232,64760,802.93989200,48962245.42333133,0 +1615690800000,61061.28000000,61472.08000000,60900.00000000,61356.31000000,1564.46519700,1615694399999,95843858.04768765,48896,785.52393200,48122174.79458445,0 +1615694400000,61356.30000000,61595.09000000,61088.67000000,61225.53000000,1478.03990500,1615697999999,90606709.62163290,50459,785.00741000,48134610.92757440,0 +1615698000000,61225.54000000,61285.41000000,60903.96000000,61016.29000000,1714.88950900,1615701599999,104720513.49644333,46898,899.67837300,54930777.67156941,0 +1615701600000,61016.29000000,61016.30000000,60523.14000000,60975.39000000,2353.14978300,1615705199999,143136145.20747868,61901,1136.06327400,69101977.93047488,0 +1615705200000,60975.39000000,60975.39000000,60455.28000000,60494.80000000,1519.28971800,1615708799999,92234962.64422141,56073,704.87003800,42795620.94834144,0 +1615708800000,60494.80000000,60871.03000000,60250.01000000,60787.75000000,2163.70124000,1615712399999,131189408.73618039,98980,1075.27290900,65197075.16781411,0 +1615712400000,60787.75000000,61110.53000000,60618.00000000,60934.11000000,1847.33840300,1615715999999,112600404.62197312,55882,868.62255900,52950318.77186565,0 +1615716000000,60933.62000000,60970.00000000,60135.37000000,60293.09000000,2947.30181100,1615719599999,178349426.28366977,85222,1530.03164500,92592255.68971744,0 +1615719600000,60293.08000000,60405.03000000,59354.62000000,60308.31000000,4632.32120400,1615723199999,277582980.75469308,175131,2195.46267400,131591203.91019273,0 +1615723200000,60308.30000000,60550.00000000,60140.96000000,60427.82000000,2296.79355700,1615726799999,138632917.16206044,73366,1097.82405300,66268257.78031005,0 +1615726800000,60427.81000000,60481.70000000,59734.03000000,59940.00000000,2543.07988300,1615730399999,152769221.56988017,82975,1205.33089600,72403815.66563478,0 +1615730400000,59940.00000000,60477.83000000,59868.12000000,60001.91000000,1950.74360500,1615733999999,117410605.02275073,63605,1001.67006300,60290558.84116310,0 +1615734000000,60001.90000000,60150.00000000,59470.00000000,59681.26000000,2495.61525600,1615737599999,149336242.94249174,76701,1064.23896100,63721696.97498350,0 +1615737600000,59681.21000000,60066.59000000,59300.00000000,59567.74000000,3099.34760800,1615741199999,184953713.99594900,120192,1377.26474400,82198780.32783666,0 +1615741200000,59567.74000000,60023.07000000,59523.66000000,59701.10000000,1638.55137800,1615744799999,97971937.36521324,89045,829.24043300,49596173.31314670,0 +1615744800000,59701.10000000,60369.99000000,59700.00000000,60138.31000000,1579.17760400,1615748399999,94907457.27258277,64152,846.77215100,50891878.69917035,0 +1615748400000,60138.31000000,60200.00000000,59789.74000000,59931.70000000,1318.69249000,1615751999999,79162190.55300161,55188,619.65932700,37195690.01610081,0 +1615752000000,59928.71000000,60325.98000000,59702.78000000,60264.48000000,1677.50289300,1615755599999,100584010.81332785,57797,795.01996600,47679877.50516328,0 +1615755600000,60264.48000000,60485.08000000,59852.18000000,60081.54000000,1480.96127700,1615759199999,89065134.54869998,57633,732.28274800,44037662.87055341,0 +1615759200000,60081.55000000,60324.43000000,59733.38000000,60201.19000000,1414.97297300,1615762799999,84965673.31902896,53647,633.95168400,38072956.04917135,0 +1615762800000,60201.19000000,60750.00000000,58966.78000000,58968.31000000,4143.92116900,1615766399999,248075311.28127877,142747,1810.76858900,108552720.33577378,0 +1615766400000,58976.08000000,59917.78000000,58705.47000000,59404.48000000,4470.86309900,1615769999999,265713953.23734152,100243,2528.17046300,150316819.44283939,0 +1615770000000,59404.48000000,60251.42000000,59227.52000000,60066.56000000,2965.91702300,1615773599999,177264954.87272399,80765,1686.30905400,100744333.35911317,0 +1615773600000,60066.56000000,60331.02000000,60037.61000000,60069.63000000,1776.36213400,1615777199999,106937773.31051113,56984,969.20763300,58344923.59552751,0 +1615777200000,60069.63000000,60491.47000000,60069.62000000,60379.99000000,1353.80793600,1615780799999,81603410.21082850,48278,689.84765400,41586267.39876213,0 +1615780800000,60379.99000000,60633.43000000,59658.87000000,59773.71000000,2437.90966500,1615784399999,146672139.53938653,68290,1186.42199500,71396347.27299430,0 +1615784400000,59773.70000000,59916.24000000,59005.00000000,59013.35000000,3320.90935200,1615787999999,197532625.47269636,81960,1585.25655700,94305122.29442164,0 +1615788000000,59019.39000000,59365.42000000,58421.00000000,58781.49000000,4947.78241200,1615791599999,291146694.77416573,130536,2194.57443400,129180466.61114140,0 +1615791600000,58783.38000000,58792.57000000,57253.00000000,57789.76000000,8895.35121600,1615795199999,515335194.02854789,208289,3768.96655700,218358307.60227077,0 +1615795200000,57789.75000000,58350.00000000,57500.00000000,57757.70000000,4975.32173200,1615798799999,288336805.06503649,119653,2424.43659300,140511615.46207805,0 +1615798800000,57757.71000000,58100.00000000,54600.00000000,55867.91000000,16138.46740100,1615802399999,905203244.19086457,325051,7435.24769500,416798260.80812348,0 +1615802400000,55871.29000000,56438.00000000,55555.55000000,56355.14000000,5624.83382900,1615805999999,315479252.50055925,153767,2615.80008500,146712393.30472208,0 +1615806000000,56355.13000000,56576.37000000,55888.01000000,56150.79000000,4161.88247500,1615809599999,234126646.76055732,137998,2003.62985100,112723665.39977284,0 +1615809600000,56150.80000000,56481.38000000,55050.00000000,56439.53000000,6180.17600300,1615813199999,344675696.13245714,133436,3111.95745300,173549833.79185964,0 +1615813200000,56439.54000000,57046.87000000,56250.48000000,56855.58000000,4832.09007800,1615816799999,274254493.32146787,124306,2321.19488900,131723807.43708121,0 +1615816800000,56855.58000000,57312.47000000,56123.12000000,56134.09000000,4699.21633300,1615820399999,267295233.12895629,143725,2203.52400400,125368219.14239431,0 +1615820400000,56134.09000000,56816.69000000,55854.20000000,56224.13000000,4402.38440100,1615823999999,247998456.87422206,96774,2407.06727300,135606156.46048522,0 +1615824000000,56224.14000000,56700.00000000,55669.28000000,56247.87000000,4462.95611200,1615827599999,251075090.05218074,153182,2259.94406500,127126686.27498670,0 +1615827600000,56261.02000000,56331.11000000,55478.01000000,56035.79000000,3315.71378600,1615831199999,185299555.94013669,116860,1603.26706300,89604950.24974911,0 +1615831200000,56034.82000000,56377.66000000,55800.00000000,56113.90000000,2345.77916800,1615834799999,131599524.68354643,64657,1239.80361500,69548719.30195049,0 +1615834800000,56113.90000000,56647.24000000,56096.80000000,56570.36000000,2094.00178400,1615838399999,118124197.63037133,71275,1090.66108800,61529446.31604523,0 +1615838400000,56570.37000000,56930.17000000,56221.00000000,56379.97000000,2748.53681400,1615841999999,155576007.81124944,75928,1325.01700800,75010039.35635407,0 +1615842000000,56379.97000000,56940.00000000,56338.56000000,56707.71000000,1725.16621500,1615845599999,97702184.79430900,61993,805.67747200,45624776.00748374,0 +1615845600000,56712.71000000,56900.00000000,55979.22000000,56136.73000000,2331.70503600,1615849199999,131374668.50131774,64676,1105.40621600,62274498.24970701,0 +1615849200000,56144.74000000,56672.00000000,55537.00000000,55605.20000000,2564.29329400,1615852799999,143913249.25993820,65189,1264.04963000,70961431.49450600,0 +1615852800000,55605.20000000,56140.55000000,53960.11000000,54088.76000000,7957.15358700,1615856399999,437202648.13417986,191332,3393.89436400,186476877.39676450,0 +1615856400000,54097.20000000,54568.42000000,53271.34000000,54471.57000000,6577.50139400,1615859999999,354381089.45398518,142568,3216.72500800,173331683.36020260,0 +1615860000000,54471.57000000,54649.95000000,54122.38000000,54567.64000000,2831.21352800,1615863599999,154093135.08368528,75225,1481.73098600,80637920.03171625,0 +1615863600000,54567.64000000,54624.99000000,53850.00000000,54272.86000000,3152.44796100,1615867199999,170852387.52141331,75978,1515.48532200,82140373.34025877,0 +1615867200000,54272.66000000,54850.00000000,54188.82000000,54418.19000000,2351.53507500,1615870799999,128281117.37242801,57980,1142.11968000,62312485.76723559,0 +1615870800000,54418.19000000,54459.08000000,53607.93000000,54096.52000000,2955.46035700,1615874399999,159632428.00944406,87512,1519.06826000,82053862.77793192,0 +1615874400000,54088.44000000,55334.77000000,53650.00000000,55060.06000000,4606.99276500,1615877999999,251599927.65034215,106911,1980.46517000,108056129.30196051,0 +1615878000000,55060.05000000,55491.00000000,54787.70000000,55239.81000000,3771.70482300,1615881599999,208210331.92943864,100358,1724.85199900,95216251.56835064,0 +1615881600000,55239.81000000,56100.00000000,55110.73000000,55894.27000000,3835.32871400,1615885199999,213901595.63400257,105005,1970.90749200,109933399.52205052,0 +1615885200000,55892.13000000,56400.00000000,55709.32000000,55870.43000000,2595.14560500,1615888799999,145272849.09308388,80280,1271.74494000,71201820.33019871,0 +1615888800000,55870.43000000,56150.05000000,55432.44000000,55805.00000000,2847.30433300,1615892399999,158917868.72733189,101166,1422.74274800,79427012.81574484,0 +1615892400000,55805.00000000,55900.00000000,55079.63000000,55471.21000000,3253.39736400,1615895999999,180370410.51099929,119308,1740.04620400,96461021.80227283,0 +1615896000000,55464.11000000,55631.57000000,54596.89000000,55091.95000000,3389.37464000,1615899599999,186675722.53714168,92060,1640.04266700,90333547.83750450,0 +1615899600000,55091.94000000,55906.86000000,55006.35000000,55324.30000000,3311.89499300,1615903199999,183623764.90859133,80400,1554.87881600,86221695.13271721,0 +1615903200000,55324.30000000,55722.55000000,55199.48000000,55645.93000000,2532.83420700,1615906799999,140545964.75380359,76281,1318.68961200,73175688.08518264,0 +1615906800000,55645.93000000,55913.57000000,55420.00000000,55844.92000000,2814.91292800,1615910399999,156715501.88552340,80479,1327.82193500,73922058.01778391,0 +1615910400000,55844.92000000,56087.02000000,55436.66000000,55657.89000000,2849.02842900,1615913999999,158841732.94560050,100571,1363.08471400,76004971.37626362,0 +1615914000000,55657.90000000,55850.99000000,54950.16000000,55250.21000000,3538.50365500,1615917599999,195923778.17482664,126985,1721.68249600,95314824.30772918,0 +1615917600000,55250.20000000,55667.95000000,55091.32000000,55349.99000000,2023.35062100,1615921199999,112029692.96213441,61640,1017.04283100,56315680.78136919,0 +1615921200000,55349.99000000,55820.00000000,55151.70000000,55731.36000000,1579.06637200,1615924799999,87714795.49289385,53288,823.00404700,45727907.58998827,0 +1615924800000,55731.36000000,56431.41000000,55673.23000000,56373.10000000,2877.44784500,1615928399999,161651593.80010455,80244,1550.92710700,87119308.17251491,0 +1615928400000,56369.86000000,56619.02000000,56083.08000000,56450.11000000,1699.81433600,1615931999999,95842718.19096621,87749,864.81714100,48773282.71847072,0 +1615932000000,56450.10000000,56820.00000000,56225.79000000,56243.43000000,2651.03478600,1615935599999,150005594.50554297,71284,1204.15907700,68143298.44410021,0 +1615935600000,56243.44000000,56938.29000000,56070.23000000,56900.75000000,1984.24603700,1615939199999,111972558.36763656,86604,1059.56887700,59810262.07292637,0 +1615939200000,56900.74000000,57189.43000000,56258.77000000,56518.57000000,3017.41179500,1615942799999,171061428.51151949,79700,1522.15582100,86311900.38341505,0 +1615942800000,56518.57000000,56535.06000000,56060.00000000,56283.40000000,1658.77751200,1615946399999,93420081.73884519,77672,792.60604400,44643219.26220265,0 +1615946400000,56283.41000000,56283.41000000,55629.34000000,55777.69000000,2010.75917400,1615949999999,112448953.68323780,112846,991.58997400,55448075.53475651,0 +1615950000000,55777.68000000,56152.41000000,55401.02000000,55506.23000000,1845.94923000,1615953599999,103036667.73348934,67859,848.76650100,47384837.81674542,0 +1615953600000,55506.23000000,55861.88000000,55401.01000000,55569.07000000,1498.02164200,1615957199999,83352718.56123611,44454,752.72640300,41883730.67841739,0 +1615957200000,55569.06000000,55970.28000000,55185.42000000,55951.37000000,2124.18924800,1615960799999,118057910.85231841,77314,1048.49974300,58285628.85644024,0 +1615960800000,55951.37000000,56326.53000000,55834.29000000,56306.84000000,2223.80240100,1615964399999,124730274.66955771,63389,1036.15118100,58122491.18894678,0 +1615964400000,56306.84000000,56322.46000000,55682.03000000,55821.01000000,1768.83825900,1615967999999,99041648.72076432,74940,803.44729100,44985306.91548634,0 +1615968000000,55819.23000000,56052.63000000,55622.94000000,55775.16000000,1931.02047100,1615971599999,107751893.61626658,62044,936.79581700,52277764.17880552,0 +1615971600000,55784.11000000,55871.05000000,54326.27000000,54762.77000000,4958.34282200,1615975199999,272971874.23444566,127316,2140.09281600,117904688.76140569,0 +1615975200000,54763.59000000,55234.88000000,54600.00000000,55088.89000000,2354.37472200,1615978799999,129491352.51325751,84505,1173.86053400,64559380.27751988,0 +1615978800000,55088.90000000,55200.00000000,54569.99000000,54840.00000000,2315.50151700,1615982399999,127134285.80518269,90616,1100.81634200,60441474.01781767,0 +1615982400000,54840.01000000,55413.63000000,54123.69000000,55151.01000000,3929.96578900,1615985999999,215310490.77771350,137146,1963.79428800,107624094.07202577,0 +1615986000000,55151.01000000,55406.79000000,54711.60000000,55105.41000000,3060.90680800,1615989599999,168599299.64973796,121106,1497.14663600,82469230.61745621,0 +1615989600000,55108.44000000,55152.48000000,54524.65000000,54548.97000000,2732.54603100,1615993199999,149859158.26320678,67724,1296.64359300,71119003.88558349,0 +1615993200000,54547.57000000,55244.03000000,54298.18000000,54930.00000000,3582.18486800,1615996799999,196551207.33039579,80629,1729.89689900,94945360.50294275,0 +1615996800000,54930.00000000,55600.27000000,54740.00000000,55275.08000000,2677.39676100,1616000399999,147973226.98216747,71997,1342.13665500,74175857.79149212,0 +1616000400000,55275.08000000,55659.93000000,55162.60000000,55542.50000000,1783.07855900,1616003999999,98799496.44741874,54185,857.00826500,47479669.26712274,0 +1616004000000,55542.50000000,57576.28000000,55542.50000000,57575.51000000,6667.37098400,1616007599999,378321072.89441844,154832,3591.51023300,203764983.57290041,0 +1616007600000,57575.51000000,58201.58000000,57329.44000000,57867.42000000,5960.95180800,1616011199999,344434829.14549266,133407,2970.35677800,171667082.00578924,0 +1616011200000,57867.42000000,58333.00000000,57709.04000000,57715.19000000,3384.95866500,1616014799999,196329088.70543287,88383,1772.89216100,102835167.85216363,0 +1616014800000,57710.93000000,58732.08000000,57601.92000000,58427.49000000,3200.25526600,1616018399999,186219950.72705665,115571,1649.64849300,96007562.23631201,0 +1616018400000,58427.49000000,58940.00000000,58234.33000000,58284.41000000,3296.26553800,1616021999999,193172893.75094541,118643,1626.83635100,95348141.72472217,0 +1616022000000,58299.98000000,58974.73000000,58236.00000000,58912.97000000,2438.75097100,1616025599999,142923166.84018515,98018,1333.36695600,78140871.27985895,0 +1616025600000,58912.97000000,59561.54000000,58709.03000000,58927.54000000,4549.11801800,1616029199999,269144816.40752417,108968,2364.27987700,139892545.35798252,0 +1616029200000,58927.53000000,59326.93000000,58758.01000000,59043.14000000,2078.67188300,1616032799999,122755934.65744768,57646,1005.39054000,59373223.94041600,0 +1616032800000,59043.13000000,59300.00000000,58908.00000000,58996.77000000,1879.60094200,1616036399999,111172999.55449290,60761,884.14754000,52292935.24279920,0 +1616036400000,58999.17000000,59058.33000000,58606.10000000,58712.33000000,1790.19748100,1616039999999,105284148.20737737,86293,840.22241000,49409421.01416344,0 +1616040000000,58712.34000000,59200.00000000,58623.85000000,58800.01000000,1944.10750100,1616043599999,114428946.48940695,66378,986.44569300,58063497.36896383,0 +1616043600000,58800.01000000,59183.96000000,58651.00000000,58957.44000000,1825.78964000,1616047199999,107606654.08827600,78974,884.13185800,52108142.48884573,0 +1616047200000,58957.43000000,59070.00000000,58650.01000000,58910.00000000,2056.93352100,1616050799999,121023138.80481180,52697,1028.90090600,60540991.57198846,0 +1616050800000,58909.99000000,58926.26000000,58119.00000000,58355.15000000,3028.61646600,1616054399999,177130313.04424154,69124,1372.10672700,80234741.54906116,0 +1616054400000,58355.14000000,58525.83000000,57899.00000000,58007.11000000,2413.16618300,1616057999999,140565936.73101818,67896,1062.36634500,61890023.72523356,0 +1616058000000,58007.11000000,58475.01000000,57936.22000000,58399.98000000,2245.14676100,1616061599999,130759852.31288753,63316,1095.37950100,63795071.49612447,0 +1616061600000,58399.98000000,58660.00000000,58221.05000000,58520.25000000,1746.54181800,1616065199999,102079058.46371358,57295,813.19083800,47527049.03234213,0 +1616065200000,58520.24000000,58550.00000000,57870.38000000,58170.37000000,2116.02090500,1616068799999,123129919.35665675,66479,987.42541500,57455402.62199199,0 +1616068800000,58168.69000000,58187.11000000,57586.31000000,58051.31000000,3297.48134200,1616072399999,190832667.23974137,121393,1603.70198000,92809239.50561036,0 +1616072400000,58051.31000000,58188.85000000,57777.00000000,57846.31000000,1998.12233000,1616075999999,115885895.93320046,65146,979.62463200,56815083.20210928,0 +1616076000000,57846.31000000,58037.35000000,57500.00000000,57863.14000000,2429.21171200,1616079599999,140366667.47553594,74499,1137.69450000,65752018.42164948,0 +1616079600000,57863.13000000,59637.39000000,57700.00000000,59533.68000000,5520.69352300,1616083199999,324789182.97982674,140483,2966.63565500,174573742.56305089,0 +1616083200000,59533.67000000,60129.97000000,59037.15000000,59080.61000000,7435.16430300,1616086799999,443802273.70528617,202184,3589.95027100,214372955.02612068,0 +1616086800000,59074.61000000,59480.00000000,59073.40000000,59250.81000000,2837.01594900,1616090399999,168260289.73092714,116412,1408.93320100,83562882.73898958,0 +1616090400000,59250.81000000,59310.13000000,58000.10000000,58221.01000000,3740.43498100,1616093999999,219147368.77852779,140677,1834.83854600,107509027.11434387,0 +1616094000000,58221.02000000,58416.56000000,57200.00000000,57293.79000000,3699.02170400,1616097599999,213974977.63845645,103954,1654.74019900,95766804.03167023,0 +1616097600000,57294.12000000,57898.66000000,57023.00000000,57508.90000000,2886.38146400,1616101199999,166099816.10098642,83598,1331.09690200,76606514.53457965,0 +1616101200000,57506.15000000,57995.00000000,57434.79000000,57900.05000000,1567.21836000,1616104799999,90568291.24721251,58003,823.22815600,47573781.80871666,0 +1616104800000,57900.06000000,58146.60000000,57623.23000000,57627.64000000,1703.48873100,1616108399999,98643846.84367895,52033,800.32859400,46345304.48002936,0 +1616108400000,57635.11000000,58036.43000000,57354.24000000,57648.16000000,1792.26115700,1616111999999,103432765.42157160,46738,832.61962500,48057292.52991381,0 +1616112000000,57641.00000000,57689.65000000,56270.74000000,56880.00000000,4455.45187500,1616115599999,253070962.09478709,100646,2047.65500000,116275710.26080408,0 +1616115600000,56880.00000000,57413.67000000,56663.23000000,57393.18000000,1844.07931800,1616119199999,105265428.45446349,56616,928.15780800,52978321.32668744,0 +1616119200000,57393.19000000,57763.00000000,57200.00000000,57358.32000000,1694.18144200,1616122799999,97307383.21843027,58815,775.78713600,44556456.19386931,0 +1616122800000,57358.31000000,57898.48000000,57298.81000000,57779.84000000,1431.32020600,1616126399999,82462970.94126710,50245,711.89017200,41013823.76315546,0 +1616126400000,57779.84000000,58259.02000000,57632.38000000,57866.12000000,1888.53228500,1616129999999,109408385.55747506,54755,980.51198600,56816146.68573658,0 +1616130000000,57866.13000000,58391.78000000,57603.92000000,58364.76000000,1694.97517700,1616133599999,98262292.53285442,65184,838.57177100,48616229.52199021,0 +1616133600000,58362.01000000,58492.85000000,57978.71000000,58142.29000000,1609.31248800,1616137199999,93601976.39314127,72093,759.53529400,44177666.93720238,0 +1616137200000,58142.29000000,58381.50000000,57700.00000000,57834.04000000,1715.83562300,1616140799999,99685537.27183893,88932,758.64932200,44074140.42954641,0 +1616140800000,57834.04000000,58568.00000000,57499.63000000,58338.07000000,3166.10615900,1616144399999,184070527.78925468,118845,1568.42710500,91216742.61388867,0 +1616144400000,58338.09000000,58888.00000000,58178.13000000,58300.00000000,2622.97662600,1616147999999,153558830.06692741,85814,1278.53904100,74861504.91367807,0 +1616148000000,58295.02000000,58707.27000000,58101.97000000,58583.92000000,1819.57824000,1616151599999,106206708.27996261,62413,886.68383000,51761378.14575761,0 +1616151600000,58583.92000000,58834.49000000,58402.66000000,58831.33000000,2091.39124600,1616155199999,122595300.34469474,84995,1016.71732600,59604527.28874963,0 +1616155200000,58831.34000000,59249.50000000,58718.57000000,58849.99000000,2998.89340500,1616158799999,176968100.07543716,116170,1509.39615600,89072512.02173588,0 +1616158800000,58849.99000000,58884.00000000,58057.04000000,58280.00000000,3297.06543700,1616162399999,192659656.79324941,107817,1628.43476900,95162627.69846460,0 +1616162400000,58279.99000000,58786.03000000,57950.59000000,58729.99000000,2375.16803100,1616165999999,138727999.56583795,90305,1063.17486400,62097776.87239500,0 +1616166000000,58729.98000000,59164.86000000,58500.00000000,58971.50000000,2704.90537500,1616169599999,159309454.29883239,76398,1378.13950700,81176226.94425808,0 +1616169600000,58977.04000000,59180.00000000,58610.56000000,58859.79000000,2724.40921100,1616173199999,160457239.10271708,81048,1284.64922300,75662984.31666912,0 +1616173200000,58857.51000000,58976.47000000,58625.00000000,58864.30000000,1451.31398100,1616176799999,85356895.91241080,57905,707.29487800,41600812.02682967,0 +1616176800000,58865.57000000,58956.00000000,58345.14000000,58800.00000000,1683.61190300,1616180399999,98818631.87480621,80113,818.89689700,48066970.89750706,0 +1616180400000,58800.00000000,58970.60000000,58643.99000000,58826.56000000,1456.44676300,1616183999999,85633513.74350445,89411,696.73233000,40966148.44637518,0 +1616184000000,58826.56000000,59468.00000000,58101.92000000,58372.40000000,3962.11893500,1616187599999,232999139.19975382,122541,2161.95202000,127191965.26271928,0 +1616187600000,58372.41000000,58755.15000000,58299.08000000,58648.78000000,1105.40938700,1616191199999,64737463.55670261,67783,521.25318200,30529585.70503679,0 +1616191200000,58648.78000000,58648.78000000,58283.94000000,58501.56000000,972.23017900,1616194799999,56836165.13578407,43768,450.74137100,26347224.81248144,0 +1616194800000,58501.55000000,58550.61000000,58000.00000000,58030.01000000,1627.33966900,1616198399999,94710585.73079219,53218,780.72023500,45446600.17880425,0 +1616198400000,58030.01000000,58677.52000000,57820.17000000,58639.33000000,2400.21478100,1616201999999,139775135.61008880,117250,1347.97935500,78500967.45701455,0 +1616202000000,58639.33000000,58879.18000000,58482.57000000,58724.01000000,1418.75610600,1616205599999,83213022.25642246,101473,722.87817700,42402789.32659511,0 +1616205600000,58724.02000000,58913.98000000,58416.16000000,58549.33000000,1292.83658600,1616209199999,75847128.67752989,69251,619.03400700,36318989.33848892,0 +1616209200000,58549.33000000,58581.62000000,58179.05000000,58367.74000000,1369.40514100,1616212799999,79937434.71747051,46038,591.44081400,34524792.40265906,0 +1616212800000,58367.75000000,58606.63000000,58153.28000000,58209.83000000,1090.34821100,1616216399999,63662122.44935170,43737,526.13731800,30719558.56332919,0 +1616216400000,58209.83000000,58362.11000000,58050.00000000,58131.57000000,1005.92984900,1616219999999,58567178.12265729,39647,465.76256300,27119534.26410283,0 +1616220000000,58131.57000000,58373.46000000,57980.00000000,58344.30000000,1229.53603800,1616223599999,71624722.72447132,44474,575.16413900,33509550.96012928,0 +1616223600000,58344.30000000,58536.84000000,58268.00000000,58402.41000000,1346.29394400,1616227199999,78602838.71808992,50903,630.86528300,36832154.86072246,0 +1616227200000,58402.41000000,58798.60000000,58402.40000000,58671.46000000,2269.32666400,1616230799999,133160868.73101746,84561,1187.39108200,69673923.44977065,0 +1616230800000,58671.45000000,58899.00000000,58577.55000000,58780.02000000,1730.98715900,1616234399999,101687855.91921922,68464,980.32261400,57593022.15701652,0 +1616234400000,58780.03000000,58908.26000000,58577.00000000,58687.97000000,1237.61178800,1616237999999,72708435.82915073,48073,611.82429800,35947362.69142132,0 +1616238000000,58685.98000000,59299.00000000,58626.27000000,59242.47000000,2563.59353600,1616241599999,151265724.30349677,83862,1402.49375900,82758094.51402984,0 +1616241600000,59242.91000000,59325.60000000,58756.41000000,59144.54000000,1890.87877900,1616245199999,111643256.77481865,89613,951.30027100,56166468.01419311,0 +1616245200000,59144.54000000,59880.00000000,58610.62000000,59033.13000000,4616.41624000,1616248799999,274375295.41173724,144830,2437.66477000,144919181.18357401,0 +1616248800000,59027.95000000,59368.75000000,58755.30000000,59365.02000000,2675.66907300,1616252399999,158134357.72929599,90798,1349.33902900,79747356.17011844,0 +1616252400000,59365.02000000,59722.00000000,59030.23000000,59244.52000000,2360.94706800,1616255999999,140261533.88830589,99599,1167.31284200,69353759.96468136,0 +1616256000000,59244.51000000,59300.00000000,58901.66000000,59031.13000000,2191.01910100,1616259599999,129425314.87936093,106206,1081.41617800,63877039.82319377,0 +1616259600000,59032.02000000,59297.00000000,59019.00000000,59138.44000000,1417.88486700,1616263199999,83895162.59915379,56570,704.21017900,41666608.98425554,0 +1616263200000,59138.43000000,59474.89000000,59104.28000000,59173.03000000,1437.47696500,1616266799999,85219757.78372868,51039,729.13193800,43227766.82794822,0 +1616266800000,59173.03000000,59424.73000000,59134.89000000,59272.82000000,1012.05506600,1616270399999,59990429.45451150,43892,493.90540200,29275388.50818034,0 +1616270400000,59272.83000000,59381.70000000,58131.55000000,58519.84000000,3576.51468400,1616273999999,209782761.79146679,93892,1574.40247100,92363981.56180753,0 +1616274000000,58519.77000000,58782.77000000,58371.01000000,58728.76000000,935.90892000,1616277599999,54866148.76920476,48358,464.09406300,27208066.08540614,0 +1616277600000,58728.75000000,58800.00000000,58370.65000000,58503.01000000,1162.19642700,1616281199999,68105272.24163728,44509,552.25397300,32361495.99054868,0 +1616281200000,58503.01000000,58525.96000000,57966.85000000,58102.28000000,2245.13478300,1616284799999,130783333.66939774,57092,1046.12219800,60956140.02425656,0 +1616284800000,58100.02000000,58589.10000000,57811.41000000,58331.43000000,2342.92980100,1616288399999,136538084.48522659,69680,1071.69380000,62463637.34090045,0 +1616288400000,58331.42000000,58463.99000000,58091.02000000,58180.00000000,953.47411000,1616291999999,55562369.53512714,41963,471.57221500,27483461.87584013,0 +1616292000000,58179.99000000,58180.00000000,57480.00000000,57615.32000000,2283.57109300,1616295599999,131982856.29604345,68914,1031.96878600,59651950.01712061,0 +1616295600000,57615.33000000,57856.42000000,57363.07000000,57790.00000000,1761.74702000,1616299199999,101663371.52994261,74206,774.97245600,44722649.09867494,0 +1616299200000,57790.00000000,57797.45000000,56717.81000000,56909.83000000,3073.16835200,1616302799999,175780313.09631984,86215,1400.08391000,80068414.86685879,0 +1616302800000,56911.99000000,57242.59000000,56856.66000000,57129.99000000,1641.05936900,1616306399999,93655921.94588568,49850,822.28281100,46929002.35872647,0 +1616306400000,57130.00000000,57413.66000000,56668.00000000,57047.98000000,1874.11392200,1616309999999,107040728.45689568,89964,901.11668200,51477799.54670575,0 +1616310000000,57047.98000000,57312.64000000,56862.07000000,56972.68000000,1201.10772200,1616313599999,68584960.24931010,82421,567.77407600,32420902.28364581,0 +1616313600000,56972.68000000,57325.45000000,56800.00000000,57161.38000000,1533.42174700,1616317199999,87617906.39176203,76623,762.34381100,43565517.29553083,0 +1616317200000,57161.38000000,57260.00000000,55450.11000000,55963.32000000,4428.20952900,1616320799999,249238457.27821915,117612,1862.78710700,104843164.02340083,0 +1616320800000,55960.52000000,56384.33000000,55605.94000000,56134.34000000,3100.61806200,1616324399999,174018493.39656378,77409,1595.71448900,89559114.55119471,0 +1616324400000,56134.34000000,56330.00000000,55811.00000000,56267.65000000,1990.46123800,1616327999999,111699942.41938144,62748,1003.13094700,56304195.87072113,0 +1616328000000,56270.13000000,56291.16000000,55870.23000000,56191.64000000,1993.88243600,1616331599999,111861648.18482057,73949,1045.76484400,58672203.00334655,0 +1616331600000,56191.64000000,57362.68000000,56191.63000000,57026.80000000,3817.15107500,1616335199999,216997391.56100694,133424,1884.98794200,107128557.41369605,0 +1616335200000,57021.95000000,57320.66000000,57000.05000000,57177.37000000,1476.54953400,1616338799999,84452550.78751477,81647,748.03938200,42786152.92264914,0 +1616338800000,57177.37000000,57539.00000000,57013.30000000,57159.04000000,1843.33045400,1616342399999,105609106.64405382,61563,937.73976400,53732812.62977626,0 +1616342400000,57159.04000000,57415.00000000,56750.00000000,57222.31000000,2353.11073100,1616345999999,134543097.31826908,86291,1178.59886900,67387726.55387739,0 +1616346000000,57220.26000000,57303.95000000,56962.26000000,57249.14000000,1477.50516500,1616349599999,84478197.57182931,63505,691.44195400,39535734.17814303,0 +1616349600000,57249.13000000,57481.01000000,57186.82000000,57365.08000000,1076.79595800,1616353199999,61746267.59817861,45033,548.34495900,31446857.79532542,0 +1616353200000,57365.08000000,57676.00000000,57357.94000000,57513.18000000,1742.06422400,1616356799999,100208419.86674434,54295,994.36570000,57198073.86755493,0 +1616356800000,57517.00000000,57997.00000000,57517.00000000,57760.48000000,1929.96849900,1616360399999,111551469.71607171,85083,921.49112100,53254664.60693564,0 +1616360400000,57760.47000000,58098.99000000,57474.46000000,58087.79000000,1423.23587900,1616363999999,82369330.63404686,88451,809.43402600,46859959.40497461,0 +1616364000000,58085.41000000,58113.00000000,57530.82000000,57588.25000000,1502.15820800,1616367599999,86800599.92592376,49980,714.67580600,41297372.24385507,0 +1616367600000,57588.25000000,57789.25000000,57128.89000000,57351.56000000,1744.83614600,1616371199999,100221644.73467261,52720,908.61621900,52199267.52738395,0 +1616371200000,57351.56000000,57449.47000000,56420.00000000,56590.76000000,2801.92626700,1616374799999,159511227.34993432,80233,1291.52256900,73546883.98473089,0 +1616374800000,56585.85000000,56735.00000000,56289.00000000,56623.19000000,1877.89480400,1616378399999,106146306.73804803,53896,892.30534900,50445499.72483795,0 +1616378400000,56623.20000000,57034.96000000,56418.55000000,56969.85000000,1345.87219900,1616381999999,76432376.58302056,41406,654.52106400,37173612.33176436,0 +1616382000000,56969.84000000,57647.89000000,56969.84000000,57563.63000000,1620.72010500,1616385599999,92915275.30407545,50721,788.40620400,45203195.33613145,0 +1616385600000,57564.17000000,57831.41000000,57388.07000000,57615.80000000,1442.60001400,1616389199999,83119342.58225359,45408,750.20054900,43232008.92556114,0 +1616389200000,57615.80000000,57780.10000000,57315.22000000,57597.39000000,1190.09061200,1616392799999,68453599.31324255,40938,631.30461900,36316971.65137910,0 +1616392800000,57597.39000000,57895.78000000,57569.43000000,57678.12000000,1405.51551800,1616396399999,81180072.53030996,65014,703.22747400,40614862.12442252,0 +1616396400000,57678.12000000,57850.00000000,57513.41000000,57576.50000000,1477.31556400,1616399999999,85236518.96565482,82797,760.52052700,43883138.18569509,0 +1616400000000,57576.51000000,57703.29000000,57095.00000000,57210.57000000,1811.99817200,1616403599999,104035984.59794557,59255,843.64639300,48435675.04139424,0 +1616403600000,57210.58000000,57396.99000000,57024.13000000,57372.00000000,1792.56444500,1616407199999,102557149.48416985,61249,936.44394200,53579887.01839904,0 +1616407200000,57372.01000000,58430.73000000,57282.00000000,57908.82000000,3343.84880100,1616410799999,194015333.86772802,92851,1764.35161600,102352164.12642537,0 +1616410800000,57908.82000000,58160.55000000,57555.55000000,57713.79000000,1618.68330300,1616414399999,93649806.04137077,79396,787.39208700,45559240.92842103,0 +1616414400000,57713.79000000,57761.00000000,56857.96000000,57259.48000000,2852.46023200,1616417999999,163502623.71671915,85516,1249.20398500,71606668.77078305,0 +1616418000000,57267.75000000,57414.00000000,56521.01000000,56969.98000000,3973.05211400,1616421599999,226578587.93555710,97449,2226.93106200,127038349.35222041,0 +1616421600000,56969.98000000,57279.26000000,56778.52000000,56990.02000000,2367.48035700,1616425199999,135060741.10554547,70581,1110.84682800,63381210.78553680,0 +1616425200000,56990.02000000,57229.71000000,56866.38000000,57083.00000000,1765.17847300,1616428799999,100730863.45070069,80274,783.60784100,44718133.17019892,0 +1616428800000,57082.99000000,57195.00000000,56191.19000000,56753.60000000,3186.88379200,1616432399999,180496976.74780123,131357,1486.68921200,84200698.55555634,0 +1616432400000,56753.61000000,57190.00000000,56551.04000000,57080.31000000,1802.84405200,1616435999999,102592238.20817184,57615,939.04505400,53427746.32490926,0 +1616436000000,57080.31000000,57175.11000000,56366.00000000,56494.11000000,2352.94605100,1616439599999,133534931.82958492,65710,1149.93163300,65262463.95418620,0 +1616439600000,56492.91000000,56561.60000000,55508.00000000,55524.99000000,3887.35387300,1616443199999,217417256.22068123,107907,1757.33603100,98306562.52081137,0 +1616443200000,55524.99000000,56000.00000000,54179.99000000,54507.62000000,6810.57256100,1616446799999,374982959.28179078,174717,3169.02834400,174521797.60015351,0 +1616446800000,54504.94000000,54956.33000000,54200.00000000,54566.77000000,3177.52924700,1616450399999,173720317.29485479,122333,1605.76399300,87820957.43857936,0 +1616450400000,54566.77000000,54658.87000000,53650.00000000,54614.23000000,5482.64059100,1616453999999,297418671.82235456,112911,2727.73412300,148061680.68348945,0 +1616454000000,54614.99000000,54871.14000000,54060.00000000,54083.25000000,3193.65502200,1616457599999,174190353.35413761,67811,1739.09852900,94889672.03341370,0 +1616457600000,54083.25000000,54760.00000000,53777.68000000,54697.73000000,3111.38298200,1616461199999,169359321.48806101,76981,1449.90908700,78956072.74628498,0 +1616461200000,54681.39000000,55344.26000000,54509.89000000,55120.83000000,3136.55410600,1616464799999,172242309.75594473,63208,1704.80057500,93614276.00034668,0 +1616464800000,55120.83000000,55145.05000000,54438.00000000,54548.58000000,2407.13516200,1616468399999,132073097.72445253,56842,1260.43128900,69151617.90890726,0 +1616468400000,54548.58000000,54742.30000000,54379.96000000,54684.83000000,1868.28540600,1616471999999,101923157.23816557,49728,958.07430000,52273409.44137583,0 +1616472000000,54683.60000000,54780.02000000,54057.28000000,54438.64000000,1925.28416300,1616475599999,104735575.91838238,58804,930.73708500,50624150.91438398,0 +1616475600000,54435.33000000,54471.36000000,53111.66000000,53532.25000000,4706.26226700,1616479199999,252354951.53553537,122164,2096.05363800,112425536.36115415,0 +1616479200000,53532.26000000,53806.65000000,53000.00000000,53306.84000000,4134.57248500,1616482799999,220711968.66368728,108218,1910.60801300,102027627.28618405,0 +1616482800000,53306.84000000,54277.78000000,53306.83000000,54161.34000000,2579.31068500,1616486399999,138655852.90025482,72768,1380.90517300,74257828.68765255,0 +1616486400000,54166.12000000,54482.81000000,53821.79000000,54309.24000000,2327.97458700,1616489999999,126148537.96936443,67620,1141.27102300,61839349.06153722,0 +1616490000000,54309.24000000,54698.30000000,54215.24000000,54607.86000000,1916.51903700,1616493599999,104265823.29169431,60656,940.84217500,51188559.87600498,0 +1616493600000,54602.43000000,54865.37000000,54430.52000000,54671.06000000,1862.74427000,1616497199999,101733390.20100931,56591,909.13491900,49657314.27881122,0 +1616497200000,54671.05000000,54804.98000000,54060.79000000,54249.81000000,2196.96097500,1616500799999,119728525.46655410,65637,1107.09554300,60330606.70631122,0 +1616500800000,54249.80000000,55287.52000000,54234.96000000,55110.00000000,2936.00755100,1616504399999,161275779.25986892,82894,1576.94428500,86601477.76655093,0 +1616504400000,55110.00000000,55450.00000000,55020.81000000,55263.36000000,2692.72391700,1616507999999,148785566.49087356,76122,1258.37749700,69538143.33867124,0 +1616508000000,55263.35000000,55367.34000000,54744.86000000,55184.25000000,2359.37426300,1616511599999,129942554.18421825,74552,1187.05767300,65378157.41766447,0 +1616511600000,55185.06000000,55356.31000000,54919.72000000,55165.19000000,1857.12265600,1616515199999,102459149.92956987,58405,861.27869100,47523308.38980538,0 +1616515200000,55165.20000000,55760.00000000,54830.01000000,55548.52000000,2642.91064000,1616518799999,146358183.32594861,76457,1345.99041000,74544053.91249981,0 +1616518800000,55548.52000000,55767.01000000,55401.00000000,55710.87000000,2130.55535000,1616522399999,118490038.55690664,76235,1051.04156200,58453622.16245961,0 +1616522400000,55705.78000000,55830.90000000,55362.18000000,55364.69000000,1880.51975300,1616525999999,104635595.34151700,64129,879.14894800,48920929.59875126,0 +1616526000000,55364.68000000,55541.81000000,54825.42000000,55008.46000000,2847.21136700,1616529599999,156951291.73596590,85941,1458.84093800,80427794.45161654,0 +1616529600000,55008.45000000,55080.16000000,54318.70000000,54452.60000000,2952.88122100,1616533199999,161716826.35639441,90165,1549.23165000,84854921.62285177,0 +1616533200000,54453.30000000,54759.56000000,54190.10000000,54646.59000000,1816.23829000,1616536799999,98891795.36927970,62680,985.19547400,53644698.90738132,0 +1616536800000,54646.58000000,54906.78000000,54359.15000000,54387.91000000,1981.08289400,1616540399999,108292192.28130133,53815,868.19852200,47449972.86481284,0 +1616540400000,54387.91000000,54816.01000000,54299.95000000,54340.89000000,1519.75140000,1616543999999,82919289.83251141,79737,752.24127000,41038721.11723732,0 +1616544000000,54342.80000000,54669.35000000,53596.32000000,53688.07000000,2878.75426500,1616547599999,155551408.22227117,77847,1428.23242900,77192218.91941071,0 +1616547600000,53691.25000000,54588.00000000,53511.39000000,54466.36000000,2069.62147300,1616551199999,111900928.17014262,53512,1003.03013300,54222277.88259269,0 +1616551200000,54466.38000000,54647.87000000,54350.00000000,54430.79000000,1756.51100600,1616554799999,95699346.08002542,45589,745.57320100,40619126.31955856,0 +1616554800000,54430.79000000,54769.44000000,54051.35000000,54350.54000000,1667.11248500,1616558399999,90720483.01972345,44344,717.65786400,39055830.90927197,0 +1616558400000,54350.54000000,54580.00000000,53966.89000000,54122.07000000,1650.39079900,1616561999999,89595053.32201413,44963,776.40264800,42152171.35246611,0 +1616562000000,54127.12000000,54294.82000000,53783.23000000,54100.00000000,2037.76106000,1616565599999,110112223.99485043,84112,1061.28869900,57352901.51932588,0 +1616565600000,54100.00000000,55000.00000000,53700.00000000,54662.79000000,3668.39656900,1616569199999,199442187.71947095,95215,1909.91984900,103780541.74010558,0 +1616569200000,54661.64000000,55612.92000000,54606.00000000,55464.20000000,4769.80029300,1616572799999,263851963.16444796,103773,2423.07429800,134023367.44869755,0 +1616572800000,55464.46000000,56400.13000000,55452.14000000,56280.41000000,4871.58581200,1616576399999,273041085.20244553,162454,2448.51989500,137253356.33358640,0 +1616576400000,56280.40000000,56662.08000000,56280.40000000,56404.73000000,3431.05606800,1616579999999,193735178.66180754,94783,1718.52029200,97041353.40019452,0 +1616580000000,56405.11000000,56592.85000000,56028.00000000,56465.75000000,3062.55839300,1616583599999,172464238.20031060,74043,1536.60997600,86533653.90556176,0 +1616583600000,56465.74000000,56600.54000000,56256.51000000,56541.03000000,1881.59611200,1616587199999,106175943.96314848,55058,973.29741400,54926971.48586247,0 +1616587200000,56536.08000000,57038.31000000,56536.08000000,56900.01000000,3523.67933600,1616590799999,200364741.51211092,87707,1889.89349400,107467342.96187261,0 +1616590800000,56900.00000000,57200.00000000,56368.42000000,56759.91000000,3226.30560000,1616594399999,183420203.94672230,148723,1582.11030300,89955718.60459568,0 +1616594400000,56761.86000000,56929.99000000,56450.00000000,56539.35000000,2514.75323900,1616597999999,142547204.49858636,100545,1268.99312600,71931766.29005245,0 +1616598000000,56539.34000000,56641.81000000,56000.00000000,56298.12000000,2954.00683600,1616601599999,166382192.12277658,100677,1502.21666800,84613926.23650695,0 +1616601600000,56298.12000000,56422.02000000,55729.46000000,55762.89000000,2997.53171600,1616605199999,167825985.28421889,100162,1479.47991700,82836693.54239147,0 +1616605200000,55762.89000000,56400.00000000,55570.82000000,56125.89000000,2956.20302600,1616608799999,165719682.77496397,72526,1199.34307700,67211925.26658294,0 +1616608800000,56125.90000000,56370.14000000,55300.00000000,55378.91000000,2463.77060200,1616612399999,137560449.34312896,69102,1190.55857000,66465103.11659430,0 +1616612400000,55380.64000000,55571.12000000,54666.66000000,54736.53000000,3623.33929400,1616615999999,199638470.11340974,100074,1761.73370400,97070813.81605629,0 +1616616000000,54736.52000000,54743.38000000,53202.00000000,54058.85000000,7329.51347200,1616619599999,395485214.78828580,177333,3287.50398000,177418185.89877426,0 +1616619600000,54058.85000000,54250.00000000,53540.05000000,53749.99000000,3305.88222100,1616623199999,178083270.81082235,108086,1507.36472600,81231854.41667767,0 +1616623200000,53749.99000000,53749.99000000,51700.00000000,52534.03000000,11193.61641800,1616626799999,589015075.15365663,282465,4162.92819500,219014081.40070485,0 +1616626800000,52534.03000000,52987.87000000,52300.00000000,52303.65000000,3703.71892600,1616630399999,194827083.97712048,118895,1748.87760900,92015496.03937699,0 +1616630400000,52303.66000000,52900.00000000,52000.00000000,52626.91000000,3818.55095700,1616633999999,200450080.56963453,92858,1765.43595700,92712596.84464090,0 +1616634000000,52626.91000000,52768.46000000,51748.08000000,51830.21000000,4295.49111100,1616637599999,224589381.98383145,115065,1744.03579500,91200782.07496712,0 +1616637600000,51831.13000000,52555.00000000,51500.00000000,52255.37000000,4425.19588600,1616641199999,230458328.69211754,136670,2353.76078200,122563812.50369456,0 +1616641200000,52255.38000000,52561.65000000,51818.84000000,52122.86000000,2267.35784400,1616644799999,118262107.04763841,71486,1140.63903100,59497229.49147399,0 +1616644800000,52131.51000000,52518.73000000,51905.58000000,52250.97000000,2280.57600700,1616648399999,119232385.39634225,51434,1172.34162600,61306793.85894235,0 +1616648400000,52251.96000000,52850.00000000,52135.14000000,52686.15000000,2898.57613500,1616651999999,152565712.00503198,57773,1508.61654700,79373011.07798306,0 +1616652000000,52686.15000000,53287.00000000,52653.81000000,52975.46000000,2716.60009400,1616655599999,143920679.28504265,69694,1346.67962100,71345751.08485464,0 +1616655600000,52975.46000000,53130.00000000,52200.00000000,52270.71000000,2325.33150700,1616659199999,122659234.04926998,88971,1105.86691400,58332374.18134711,0 +1616659200000,52270.72000000,52794.66000000,52101.00000000,52611.36000000,2720.76383900,1616662799999,142635288.72351974,70456,1303.76901600,68357327.59089941,0 +1616662800000,52611.36000000,53000.00000000,52365.00000000,52944.42000000,2363.32549700,1616666399999,124632201.85269174,54796,1254.87434600,66192681.54965097,0 +1616666400000,52944.95000000,53067.67000000,52520.00000000,52958.00000000,2287.57664200,1616669999999,120883638.70860772,58153,1130.16331400,59726541.53665456,0 +1616670000000,52955.72000000,53160.85000000,52134.27000000,52163.19000000,3108.30368400,1616673599999,163792245.89433620,65244,1597.71674000,84267299.83006734,0 +1616673600000,52163.20000000,52408.64000000,50438.88000000,51076.92000000,10807.72007300,1616677199999,553156328.02624602,204711,4966.28792600,253954059.43797068,0 +1616677200000,51076.93000000,51976.95000000,50427.56000000,51653.76000000,6586.26208100,1616680799999,337522102.57548612,120381,3358.83894400,172164883.21954525,0 +1616680800000,51649.90000000,52066.21000000,51046.40000000,51296.96000000,4571.04064800,1616684399999,235699668.78455467,103180,2352.25979600,121267023.38923817,0 +1616684400000,51296.96000000,51521.68000000,50620.00000000,50996.15000000,5364.28269200,1616687999999,273722391.00535959,122707,2664.79042000,136009452.44271864,0 +1616688000000,50996.15000000,51700.00000000,50550.00000000,51306.95000000,5642.86629400,1616691599999,288380030.63168987,136824,2694.64565600,137723867.71011495,0 +1616691600000,51303.96000000,51811.13000000,51102.45000000,51620.60000000,2738.11289100,1616695199999,141213953.34081945,73647,1365.56004100,70429570.24703839,0 +1616695200000,51620.61000000,52532.00000000,51500.00000000,52236.72000000,3466.09995100,1616698799999,180434431.52875690,77150,1896.86907000,98760375.93244444,0 +1616698800000,52225.00000000,52300.00000000,51619.72000000,52195.19000000,2450.56717600,1616702399999,127509658.96445912,62484,1214.30305800,63196955.66676113,0 +1616702400000,52195.19000000,52700.00000000,51820.00000000,51980.75000000,2724.34316400,1616705999999,142350337.90325796,69042,1297.19804000,67806356.60360115,0 +1616706000000,51981.60000000,52575.39000000,51937.19000000,52437.10000000,1473.66235700,1616709599999,77047746.78310463,54897,785.14608000,41061910.93976086,0 +1616709600000,52437.21000000,52720.24000000,51578.93000000,51741.60000000,3342.12628800,1616713199999,174483103.70195988,71206,1578.51001900,82421963.14397177,0 +1616713200000,51734.03000000,52048.41000000,51220.72000000,51293.78000000,2725.80172000,1616716799999,140726147.50410202,70596,1349.08899400,69678949.22868479,0 +1616716800000,51293.78000000,52258.47000000,51214.60000000,52083.14000000,3107.22228900,1616720399999,161203741.48680420,76103,1564.03721000,81155462.99447099,0 +1616720400000,52083.13000000,52350.00000000,51966.66000000,52255.41000000,2051.39237900,1616723999999,107099565.46150144,56433,1172.44353700,61223620.85473877,0 +1616724000000,52255.41000000,52364.87000000,51551.00000000,51696.70000000,2151.71252000,1616727599999,111613727.47233746,50258,963.67258200,50016797.42882324,0 +1616727600000,51696.70000000,52723.68000000,51696.70000000,52407.19000000,2341.37913200,1616731199999,122330161.64175278,60617,1162.85447800,60756284.69271860,0 +1616731200000,52407.19000000,52774.71000000,52172.34000000,52693.13000000,1990.73609700,1616734799999,104360255.49163349,63258,988.11893300,51812192.72997649,0 +1616734800000,52693.13000000,52899.01000000,52500.86000000,52825.67000000,2442.40859200,1616738399999,128747568.68613190,59654,1096.18089800,57790510.20795073,0 +1616738400000,52822.29000000,52883.09000000,52462.16000000,52582.45000000,1853.44596500,1616741999999,97622109.18512037,52665,855.88947200,45083272.11983136,0 +1616742000000,52582.44000000,53600.90000000,52400.86000000,53569.85000000,4262.21365600,1616745599999,226172721.70545823,96447,2253.45557400,119601995.96011808,0 +1616745600000,53569.24000000,53826.48000000,53164.34000000,53365.17000000,4277.03815300,1616749199999,228930046.36871684,107906,2012.82223900,107767269.47585222,0 +1616749200000,53365.17000000,53600.00000000,53205.29000000,53331.62000000,2018.78349400,1616752799999,107858768.78490826,90208,992.50190400,53027966.55061846,0 +1616752800000,53331.62000000,53579.98000000,53169.00000000,53378.06000000,1879.14152100,1616756399999,100279148.67613374,83361,985.09292800,52572921.95404697,0 +1616756400000,53378.06000000,53450.00000000,52570.00000000,52710.96000000,4910.15029700,1616759999999,259774910.38714589,136866,2400.58644100,127011157.75202571,0 +1616760000000,52710.95000000,53242.96000000,52508.19000000,53001.57000000,2859.89410700,1616763599999,151424408.70949303,78430,1535.95176200,81325257.57926955,0 +1616763600000,53001.57000000,53325.35000000,52731.49000000,53316.82000000,2320.57870300,1616767199999,123115623.86085248,64320,1229.35551600,65228938.90248027,0 +1616767200000,53316.81000000,53500.00000000,53108.36000000,53414.09000000,2174.35898400,1616770799999,115808702.46777224,59857,1127.90610200,60077808.03137052,0 +1616770800000,53414.10000000,53542.00000000,53210.01000000,53308.27000000,2174.15690500,1616774399999,115970527.50414414,70500,1026.41002900,54752839.00056230,0 +1616774400000,53315.54000000,54060.24000000,52888.81000000,53776.05000000,4853.62403400,1616777999999,260457166.12043516,110983,2581.39113600,138578980.88302339,0 +1616778000000,53776.14000000,53908.20000000,53500.00000000,53823.98000000,2110.34306600,1616781599999,113357603.19732892,63599,994.72314700,53435857.75605738,0 +1616781600000,53826.34000000,53913.79000000,53463.49000000,53682.52000000,2058.32871800,1616785199999,110444768.58990754,56784,935.66443000,50205576.37231101,0 +1616785200000,53682.51000000,53813.90000000,53528.35000000,53778.55000000,1472.06874700,1616788799999,78989614.45684412,44923,750.21060400,40253223.94046864,0 +1616788800000,53773.38000000,54270.53000000,53773.38000000,53960.00000000,3098.79430600,1616792399999,167456588.00422865,85794,1435.50703800,77589075.87193469,0 +1616792400000,53960.00000000,54599.66000000,53950.16000000,54574.41000000,2342.53501700,1616795999999,127349702.94799847,77107,1188.46925700,64612879.41575459,0 +1616796000000,54574.40000000,54773.00000000,54329.79000000,54383.14000000,2638.52615500,1616799599999,143971966.12851574,65988,1162.57323100,63445421.96028515,0 +1616799600000,54383.15000000,55073.46000000,54292.00000000,55025.59000000,2424.94185500,1616803199999,132696743.41647237,61089,1406.72679000,77000730.90242663,0 +1616803200000,55025.59000000,55555.00000000,54716.31000000,54745.38000000,3813.28749100,1616806799999,210558188.92293044,89810,2078.13138200,114763238.17050419,0 +1616806800000,54745.37000000,54972.32000000,54558.67000000,54682.64000000,2538.82245100,1616810399999,139077370.26333832,46940,1194.90105200,65472778.77159020,0 +1616810400000,54682.64000000,54886.51000000,54495.12000000,54745.00000000,1287.98930800,1616813999999,70496326.53284203,38556,629.80439400,34475358.55821082,0 +1616814000000,54745.01000000,54838.98000000,54560.51000000,54760.97000000,983.71561600,1616817599999,53797137.45597051,34111,471.42434400,25781122.65192854,0 +1616817600000,54759.96000000,55236.76000000,54660.11000000,54944.72000000,1853.10508800,1616821199999,101929616.43429739,45673,927.56069900,51013311.08651071,0 +1616821200000,54944.72000000,55378.70000000,54698.28000000,55177.81000000,1819.66166300,1616824799999,100074621.52002179,45339,899.51962700,49484126.01661243,0 +1616824800000,55177.89000000,55283.65000000,54957.43000000,55027.16000000,1532.80929200,1616828399999,84473486.50331581,44599,728.06527300,40127410.30989917,0 +1616828400000,55027.16000000,55088.14000000,54733.65000000,54950.28000000,1643.40177400,1616831999999,90254339.32602816,45888,771.92583100,42392538.15125774,0 +1616832000000,54950.27000000,55146.23000000,54641.63000000,54925.06000000,1774.05187700,1616835599999,97343324.86190110,51405,825.59863200,45315219.63881574,0 +1616835600000,54925.05000000,55030.24000000,54781.64000000,55013.42000000,1104.07671200,1616839199999,60612014.97437757,39025,592.93297900,32553218.45573852,0 +1616839200000,55013.42000000,55105.85000000,54672.98000000,54680.00000000,1823.37695100,1616842799999,100048615.84434317,48410,954.79092300,52404322.41498533,0 +1616842800000,54680.01000000,54814.89000000,54311.60000000,54442.89000000,2715.09874800,1616846399999,148052315.22014372,71198,1302.61919800,71036710.98991807,0 +1616846400000,54442.89000000,54592.97000000,53950.00000000,54291.28000000,3025.90670800,1616849999999,163956828.11981612,82878,1466.85499800,79480493.05146479,0 +1616850000000,54291.29000000,54847.47000000,54066.42000000,54735.64000000,1817.70857700,1616853599999,98875964.55337676,53433,941.21802600,51204991.78189068,0 +1616853600000,54735.64000000,54745.81000000,54376.08000000,54630.06000000,1515.53858600,1616857199999,82710006.44784728,73639,723.93461500,39507717.34045950,0 +1616857200000,54630.06000000,55041.79000000,54501.29000000,54961.85000000,1871.17756700,1616860799999,102630822.11146984,59849,1043.41067700,57235895.25939040,0 +1616860800000,54961.85000000,56220.00000000,54949.27000000,56167.46000000,4967.78600700,1616864399999,276296469.26793608,146020,2782.79195200,154797598.87943919,0 +1616864400000,56163.52000000,56271.00000000,55838.73000000,56084.74000000,2788.99092700,1616867999999,156303282.98407852,114796,1421.27478500,79649976.80420796,0 +1616868000000,56081.46000000,56086.00000000,55556.00000000,55728.93000000,1829.78972500,1616871599999,102078097.66506941,57505,873.15263000,48717247.56064160,0 +1616871600000,55728.92000000,55900.00000000,55621.00000000,55765.01000000,1160.07360300,1616875199999,64694044.51713007,45178,566.66566600,31601666.54312198,0 +1616875200000,55765.01000000,55900.01000000,55680.68000000,55858.74000000,1197.78080300,1616878799999,66865724.21912843,42396,568.27281000,31725433.01574969,0 +1616878800000,55858.73000000,56700.36000000,55675.00000000,56433.17000000,3146.20652000,1616882399999,177153409.04362109,104593,1251.05327000,70359768.94070693,0 +1616882400000,56433.17000000,56605.93000000,56024.67000000,56370.94000000,2002.30136400,1616885999999,112698006.35896190,94181,923.44259100,51979259.73473495,0 +1616886000000,56373.50000000,56440.00000000,55730.00000000,55817.14000000,1892.81769700,1616889599999,106090162.71398531,53354,800.60211700,44885913.12274446,0 +1616889600000,55817.14000000,56200.00000000,55572.00000000,56020.28000000,2235.45500000,1616893199999,124776057.31375610,62844,1098.59957800,61334890.83932521,0 +1616893200000,56020.29000000,56182.88000000,55720.00000000,56068.69000000,1365.79256800,1616896799999,76486642.20641871,75351,688.42456400,38556009.88051891,0 +1616896800000,56068.69000000,56113.08000000,55742.94000000,55804.92000000,1407.04222200,1616900399999,78662433.63180383,67635,660.52041700,36929855.25078275,0 +1616900400000,55804.92000000,56161.67000000,55738.17000000,56052.05000000,1153.92000100,1616903999999,64597522.46181432,35879,609.31927000,34112360.97682889,0 +1616904000000,56052.52000000,56496.00000000,56052.52000000,56272.49000000,1608.60462400,1616907599999,90513603.12576843,62710,851.97516000,47935957.83942802,0 +1616907600000,56272.49000000,56407.86000000,56104.49000000,56269.49000000,965.54662500,1616911199999,54295462.77117824,35334,475.68744000,26748622.09901928,0 +1616911200000,56264.90000000,56319.56000000,55831.43000000,55935.61000000,1197.02946100,1616914799999,67090845.13916098,41015,550.49140100,30849219.04566741,0 +1616914800000,55935.61000000,56400.01000000,55865.62000000,56200.66000000,1269.24642400,1616918399999,71229641.28343878,40309,649.10535800,36415932.64458981,0 +1616918400000,56200.66000000,56300.00000000,55976.99000000,56296.57000000,1089.73930400,1616921999999,61187723.74379152,51167,514.75863900,28904012.72157900,0 +1616922000000,56296.57000000,56559.75000000,56026.19000000,56114.95000000,1703.62729600,1616925599999,95976040.03285566,53325,845.76674400,47654835.17881137,0 +1616925600000,56117.75000000,56181.83000000,55683.56000000,56085.93000000,1817.70847800,1616929199999,101694218.68295016,55706,861.80915500,48214347.15659487,0 +1616929200000,56085.93000000,56085.94000000,55777.00000000,55787.03000000,1395.39065100,1616932799999,78046762.47714711,77955,604.99011500,33836544.57376214,0 +1616932800000,55787.02000000,56000.00000000,55291.13000000,55525.24000000,2202.09845400,1616936399999,122365045.02834841,72499,983.72505800,54674165.58883575,0 +1616936400000,55525.25000000,55895.65000000,55461.01000000,55750.00000000,1325.18108600,1616939999999,73843442.16354856,46718,689.98490400,38450010.15488302,0 +1616940000000,55750.00000000,55842.50000000,55500.25000000,55800.00000000,1498.58557500,1616943599999,83437514.53453176,82162,824.50173800,45909959.36144047,0 +1616943600000,55800.00000000,56375.19000000,55654.10000000,56354.35000000,2105.25225400,1616947199999,118116692.12387639,116205,1159.91396500,65077998.92674479,0 +1616947200000,56356.98000000,56490.00000000,56016.12000000,56275.59000000,2003.53328500,1616950799999,112683455.67809744,122117,1083.97224400,60967773.61198476,0 +1616950800000,56275.59000000,56325.68000000,55803.19000000,55967.73000000,1986.58486200,1616954399999,111327313.81614129,73812,994.92543200,55751289.59572361,0 +1616954400000,55967.73000000,56000.00000000,55159.17000000,55192.08000000,2296.06143500,1616957999999,127597057.31964615,98361,970.73839700,53944980.68752933,0 +1616958000000,55192.08000000,55414.01000000,54691.84000000,55208.69000000,3037.57113200,1616961599999,167193396.55173506,99041,1448.09051900,79716592.63892804,0 +1616961600000,55208.70000000,55210.47000000,54743.18000000,54860.00000000,1697.20807300,1616965199999,93358763.69516436,48978,793.58749100,43654358.98349944,0 +1616965200000,54859.99000000,55370.45000000,54819.40000000,55140.01000000,1060.81353600,1616968799999,58396461.40825655,45187,566.47489400,31189257.44195137,0 +1616968800000,55140.01000000,55655.53000000,55000.00000000,55600.01000000,1412.65683200,1616972399999,78194033.40293175,42840,727.08090300,40254121.26236848,0 +1616972400000,55600.01000000,55884.40000000,55511.80000000,55777.63000000,1215.73833300,1616975999999,67707200.85285509,44133,608.28254900,33876449.49821212,0 +1616976000000,55777.65000000,56013.76000000,55290.00000000,55409.67000000,2071.04547900,1616979599999,115328946.29623365,65853,1058.11918400,58941601.78172665,0 +1616979600000,55409.68000000,55500.00000000,54977.80000000,55241.28000000,1598.26657600,1616983199999,88174215.88755206,42237,815.55528500,44997031.46995951,0 +1616983200000,55241.29000000,55515.36000000,55151.26000000,55349.99000000,1797.37321700,1616986799999,99524934.40911369,55712,793.78474100,43941663.89633333,0 +1616986800000,55354.67000000,55554.40000000,55276.51000000,55371.60000000,1157.88863600,1616990399999,64182444.67418246,43554,598.46616000,33174266.97238507,0 +1616990400000,55371.61000000,55522.00000000,55107.08000000,55315.01000000,1701.17971000,1616993999999,94034508.05690524,41399,949.36692600,52474859.53412208,0 +1616994000000,55315.01000000,55425.26000000,54848.98000000,55048.80000000,2153.12934600,1616997599999,118593995.64283484,48496,1056.61297000,58217933.65360399,0 +1616997600000,55048.80000000,55656.64000000,54800.01000000,55401.26000000,2624.40515100,1617001199999,145049141.44089716,57299,1386.21812100,76643520.67276970,0 +1617001200000,55401.26000000,56167.37000000,55358.94000000,55911.99000000,2920.30807700,1617004799999,163231921.36289134,71453,1468.16003800,82061550.27542268,0 +1617004800000,55911.99000000,57230.00000000,55911.99000000,57126.15000000,4953.17895100,1617008399999,280273899.54828792,121645,2864.44451700,162139540.48968718,0 +1617008400000,57129.58000000,58225.00000000,56966.54000000,57922.20000000,6364.37953800,1617011999999,366418067.01212099,196931,3265.45814300,188067573.91604340,0 +1617012000000,57922.20000000,58350.00000000,57777.87000000,58024.51000000,4216.17275300,1617015599999,244694727.97123165,114396,2128.60634200,123511781.77295208,0 +1617015600000,58024.50000000,58100.00000000,57609.81000000,57854.32000000,3166.06761800,1617019199999,183121495.98477236,83322,1783.24176900,103144315.32135820,0 +1617019200000,57854.14000000,58405.82000000,57792.05000000,58035.18000000,3524.58542700,1617022799999,204922801.06191140,104038,1912.60890200,111202240.97322648,0 +1617022800000,58035.19000000,58200.00000000,57808.80000000,57960.17000000,2105.23642700,1617026399999,122113580.99902324,70519,1088.52919600,63138292.93043591,0 +1617026400000,57960.65000000,58174.24000000,57837.83000000,58130.06000000,3009.31286400,1617029999999,174710051.40184007,81033,1576.54641600,91529961.34626998,0 +1617030000000,58130.05000000,58182.13000000,57267.98000000,57719.74000000,6372.19390400,1617033599999,367698873.44186746,119376,2750.83258200,158620090.59605364,0 +1617033600000,57719.74000000,57845.00000000,57170.00000000,57624.77000000,3104.75509000,1617037199999,178757579.06012564,112954,1450.19861400,83505593.05370778,0 +1617037200000,57622.63000000,58290.00000000,57571.42000000,57924.69000000,3251.68148300,1617040799999,188539539.19729034,129259,1743.42300800,101091142.61955894,0 +1617040800000,57924.69000000,58021.19000000,57561.22000000,57819.99000000,2358.37922700,1617044399999,136323805.24272664,74306,1182.06909700,68327740.25483105,0 +1617044400000,57820.00000000,57870.01000000,57317.02000000,57676.42000000,2131.84129600,1617047999999,122920792.15640929,69948,1014.50226400,58501397.22307647,0 +1617048000000,57676.41000000,57733.95000000,57103.43000000,57277.13000000,2539.76849000,1617051599999,145862942.49307925,71736,1220.82565200,70127618.82793776,0 +1617051600000,57281.79000000,57641.47000000,57160.00000000,57547.60000000,1773.72325000,1617055199999,101843500.17786626,68698,930.68027900,53443616.66314266,0 +1617055200000,57547.60000000,57900.00000000,57478.74000000,57747.01000000,1508.92329700,1617058799999,87089305.83361645,53386,683.24983900,39440004.75300571,0 +1617058800000,57747.00000000,57782.20000000,57297.31000000,57635.47000000,1454.14159100,1617062399999,83720040.38186638,85887,652.30451100,37556834.65844935,0 +1617062400000,57635.46000000,57769.01000000,57405.23000000,57520.41000000,1518.86521600,1617065999999,87465062.91814267,48026,729.82436800,42027940.79360449,0 +1617066000000,57520.41000000,57612.40000000,57259.48000000,57439.67000000,2383.17463600,1617069599999,136867004.91287573,47284,859.34133400,49351905.02889852,0 +1617069600000,57439.67000000,57450.00000000,57175.02000000,57322.02000000,1655.60849800,1617073199999,94837975.50820101,43755,789.68075100,45232343.69098869,0 +1617073200000,57322.84000000,57391.74000000,57117.36000000,57181.33000000,1542.71398500,1617076799999,88314309.28355520,50051,678.57167900,38843352.44940175,0 +1617076800000,57181.33000000,57839.16000000,57071.35000000,57567.01000000,2296.11506500,1617080399999,131847984.28645300,53331,1022.34422600,58709715.58729569,0 +1617080400000,57567.01000000,57692.97000000,57369.50000000,57670.13000000,1700.34384000,1617083999999,97798019.89366861,45992,879.17370600,50572579.09743021,0 +1617084000000,57670.14000000,58277.00000000,57505.49000000,58056.00000000,2326.61064000,1617087599999,134751998.94810390,65792,1296.15693700,75094362.00608593,0 +1617087600000,58056.01000000,58272.60000000,57938.38000000,58116.17000000,2286.43578300,1617091199999,132842065.85690621,89608,1100.25818200,63930632.08591835,0 +1617091200000,58116.16000000,58200.00000000,57726.72000000,57940.00000000,2180.46204100,1617094799999,126375544.28008422,65215,1085.04134500,62887334.52707004,0 +1617094800000,57940.00000000,58923.26000000,57842.82000000,58873.91000000,4935.51160900,1617098399999,288798913.04362479,117981,2774.32116000,162370557.67149478,0 +1617098400000,58873.91000000,59335.00000000,58625.00000000,58842.87000000,5932.47726500,1617101999999,350371808.64148619,148029,3135.48199900,185186684.01270213,0 +1617102000000,58842.87000000,59246.93000000,58837.60000000,59240.34000000,2607.64886000,1617105599999,153932693.35447709,77002,1462.82457500,86361226.59975722,0 +1617105600000,59240.33000000,59368.00000000,59015.32000000,59112.81000000,2817.34673100,1617109199999,166730083.48264003,80325,1528.22515700,90444899.25447350,0 +1617109200000,59112.81000000,59265.18000000,58819.19000000,58890.01000000,3403.89104400,1617112799999,200801285.28601236,87357,1526.73265000,90072826.99409722,0 +1617112800000,58890.01000000,58999.14000000,58626.92000000,58865.90000000,2524.06003800,1617116399999,148462062.65103608,84866,1232.67507500,72506202.06124762,0 +1617116400000,58865.90000000,58948.40000000,58500.00000000,58526.42000000,2265.27843200,1617119999999,133010137.85156953,68431,1081.48309000,63513212.35139124,0 +1617120000000,58526.43000000,58825.00000000,58470.00000000,58698.26000000,2018.91882000,1617123599999,118411705.78234949,68812,955.85755100,56070177.48376798,0 +1617123600000,58698.26000000,58888.00000000,58656.71000000,58700.00000000,1371.58600300,1617127199999,80626365.56949211,51314,686.19165400,40336960.28473891,0 +1617127200000,58699.99000000,59107.84000000,58699.99000000,58853.02000000,1916.95905200,1617130799999,113014689.52405256,58984,1128.64343300,66551057.15028870,0 +1617130800000,58853.02000000,59060.00000000,58700.00000000,59060.00000000,1508.34278900,1617134399999,88829363.90160433,50704,808.93419800,47645503.91391312,0 +1617134400000,59060.00000000,59086.65000000,58380.02000000,58627.00000000,2548.96789200,1617137999999,149425767.90078410,73902,1091.99253600,64049218.63463485,0 +1617138000000,58627.00000000,58840.00000000,58542.18000000,58722.88000000,833.34634400,1617141599999,48899761.22614474,45462,424.17697100,24891465.58338964,0 +1617141600000,58722.89000000,58900.00000000,58615.00000000,58682.41000000,1112.28554000,1617145199999,65351002.59584944,47622,524.66519200,30826197.05793409,0 +1617145200000,58682.41000000,58769.96000000,58531.70000000,58746.57000000,1435.49299900,1617148799999,84178500.75591707,42899,738.92891100,43336303.60937723,0 +1617148800000,58746.57000000,59015.00000000,58631.65000000,58991.52000000,1856.65897800,1617152399999,109296782.49070419,50873,1007.80582200,59334863.41574539,0 +1617152400000,58991.52000000,59050.00000000,58799.81000000,58885.76000000,1462.52542900,1617155999999,86169707.05261345,69577,704.26948200,41495303.39039286,0 +1617156000000,58885.76000000,58913.74000000,58638.00000000,58646.12000000,1675.45249900,1617159599999,98498070.28046075,62156,799.09776200,46975424.69170163,0 +1617159600000,58646.11000000,58714.28000000,58369.00000000,58608.63000000,2120.52541700,1617163199999,124137053.40944241,67770,830.77275200,48640734.74089529,0 +1617163200000,58608.62000000,58779.63000000,58476.81000000,58716.86000000,1677.41118800,1617166799999,98367051.53985620,89192,719.62003500,42193412.16569014,0 +1617166800000,58716.87000000,58719.00000000,58550.00000000,58710.95000000,1450.80283800,1617170399999,85028068.69057727,55520,723.82156800,42417111.64578463,0 +1617170400000,58710.96000000,59800.00000000,58651.08000000,59687.56000000,3882.81602800,1617173999999,230554277.57013244,122063,2264.64883400,134482173.04852253,0 +1617174000000,59687.56000000,59800.00000000,57500.18000000,58173.83000000,4724.35382100,1617177599999,277638882.92866280,130942,2242.19520600,131899837.78532271,0 +1617177600000,58173.82000000,58275.45000000,56769.00000000,57975.33000000,6030.92628900,1617181199999,347871145.55522117,164094,2797.41271800,161410102.28062567,0 +1617181200000,57983.77000000,58263.87000000,57697.22000000,57959.05000000,2145.27057600,1617184799999,124345771.92504257,62110,929.34340200,53887503.04761828,0 +1617184800000,57959.05000000,58088.66000000,57254.90000000,57718.44000000,2719.46263800,1617188399999,156807399.02013939,73737,1304.84043300,75244264.49328016,0 +1617188400000,57718.44000000,58137.01000000,57630.63000000,58015.02000000,1758.37729100,1617191999999,101869366.29738325,56290,900.70539500,52179882.36324988,0 +1617192000000,58015.02000000,58326.01000000,57641.06000000,58159.98000000,2438.46892900,1617195599999,141585307.26241322,67917,1226.43656400,71218887.68414101,0 +1617195600000,58159.99000000,58813.10000000,58059.02000000,58598.55000000,2612.02426100,1617199199999,152728839.07119546,81208,1426.74893200,83424079.83187165,0 +1617199200000,58598.55000000,58783.63000000,58370.20000000,58588.16000000,1701.22005700,1617202799999,99654763.16196278,60649,802.35669400,47001346.66996654,0 +1617202800000,58588.15000000,59430.54000000,58586.73000000,59304.75000000,3850.19529900,1617206399999,227594348.75084859,114524,2062.22434000,121908008.91494210,0 +1617206400000,59304.76000000,59648.52000000,58782.80000000,59000.00000000,3236.75426100,1617209999999,191676527.00814682,102849,1758.15755800,104160176.44341033,0 +1617210000000,58999.99000000,59269.03000000,58880.00000000,59251.99000000,2257.73872300,1617213599999,133352749.95385355,69215,1492.08909500,88128255.27330304,0 +1617213600000,59251.99000000,59585.61000000,59165.85000000,59299.45000000,2328.76026400,1617217199999,138240288.46227170,79040,1350.03023200,80136456.81664591,0 +1617217200000,59304.45000000,59567.28000000,58453.30000000,58553.12000000,3276.30590300,1617220799999,193887301.21751742,97127,1740.88181600,103076769.90146989,0 +1617220800000,58553.12000000,59087.00000000,58328.55000000,58934.60000000,3283.19091600,1617224399999,192746174.57383441,86303,1756.55816400,103123186.26419529,0 +1617224400000,58935.10000000,59289.45000000,58700.00000000,58940.50000000,1671.19972700,1617227999999,98577068.47579318,68641,866.58065300,51119834.72804941,0 +1617228000000,58940.50000000,59009.85000000,58558.00000000,58621.94000000,1447.62271200,1617231599999,85052315.52218886,48355,715.99932200,42068025.01783044,0 +1617231600000,58621.94000000,58895.20000000,58540.00000000,58740.55000000,1367.47862200,1617235199999,80296823.58431382,48072,652.21640800,38297152.29579528,0 diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go index 5a01a982ad..3a6aea5ce5 100644 --- a/pkg/datatype/floats/slice.go +++ b/pkg/datatype/floats/slice.go @@ -2,6 +2,7 @@ package floats import ( "math" + "sort" "gonum.org/v1/gonum/floats" ) @@ -52,6 +53,12 @@ func (s Slice) Min() float64 { return floats.Min(s) } +func (s Slice) Sort() (b Slice) { + b = s + sort.Float64s(b) + return b +} + func (s Slice) Sub(b Slice) (c Slice) { if len(s) != len(b) { return c diff --git a/pkg/indicator/v2/price.go b/pkg/indicator/v2/price.go index 5f7d9eab9a..34a9502387 100644 --- a/pkg/indicator/v2/price.go +++ b/pkg/indicator/v2/price.go @@ -1,6 +1,8 @@ package indicatorv2 import ( + "math" + "github.com/c9s/bbgo/pkg/types" ) @@ -69,6 +71,24 @@ func Volumes(source KLineSubscription) *PriceStream { func HLC3(source KLineSubscription) *PriceStream { return Price(source, types.KLineHLC3Mapper) } + func HL2(source KLineSubscription) *PriceStream { return Price(source, types.KLineHL2Mapper) } + +func LogClose(source KLineSubscription) *PriceStream { + s := &PriceStream{ + Float64Series: types.NewFloat64Series(), + } + + if source == nil { + return s + } + + source.AddSubscriber(func(k types.KLine) { + if source.Length() > 0 { + s.PushAndEmit(math.Log(k.Close.Div(source.Last(0).Close).Float64())) + } + }) + return s +} diff --git a/pkg/indicator/v2/trend/parabolic_sar.go b/pkg/indicator/v2/trend/parabolic_sar.go new file mode 100644 index 0000000000..7174685a0b --- /dev/null +++ b/pkg/indicator/v2/trend/parabolic_sar.go @@ -0,0 +1,120 @@ +package trend + +import ( + "math" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// Parabolic SAR. It is a popular technical indicator for identifying the trend +// and as a trailing stop. +// +// PSAR = PSAR[i - 1] - ((PSAR[i - 1] - EP) * AF) +// +// If the trend is Falling: +// - PSAR is the maximum of PSAR or the previous two high values. +// - If the current high is greather than or equals to PSAR, use EP. +// +// If the trend is Rising: +// - PSAR is the minimum of PSAR or the previous two low values. +// - If the current low is less than or equals to PSAR, use EP. +// +// If PSAR is greater than the closing, trend is falling, and the EP +// is set to the minimum of EP or the low. +// +// If PSAR is lower than or equals to the closing, trend is rising, and the EP +// is set to the maximum of EP or the high. +// +// If the trend is the same, and AF is less than 0.20, increment it by 0.02. +// If the trend is not the same, set AF to 0.02. +// +// Based on video https://www.youtube.com/watch?v=MuEpGBAH7pw&t=0s. + +// Trend indicator. +type Trend int + +const ( + Falling Trend = -1 + Rising Trend = 1 + psarAfStep = 0.02 + psarAfMax = 0.20 +) + +type PSARStream struct { + *types.Float64Series + Trend []Trend + af, ep float64 +} + +func ParabolicSar(source v2.KLineSubscription) *PSARStream { + var ( + low = v2.LowPrices(source) + high = v2.HighPrices(source) + closing = v2.ClosePrices(source) + s = &PSARStream{ + Float64Series: types.NewFloat64Series(), + Trend: []Trend{}, + } + ) + source.AddSubscriber(func(v types.KLine) { + var ( + psar float64 + i = source.Length() - 1 + ) + if i == 0 { + s.Trend = append(s.Trend, Falling) + psar = high.Last(0) + s.af = psarAfStep + s.ep = low.Last(0) + s.PushAndEmit(psar) + return + } + + var prevPsar = s.Slice.Last(0) + + psar = prevPsar - ((prevPsar - s.ep) * s.af) + + if s.Trend[i-1] == Falling { + psar = math.Max(psar, high.Last(1)) + if i > 1 { + psar = math.Max(psar, high.Last(2)) + } + if high.Last(0) >= psar { + psar = s.ep + } + } else { + psar = math.Min(psar, low.Last(1)) + if i > 1 { + psar = math.Min(psar, low.Last(2)) + } + if low.Last(0) <= psar { + psar = s.ep + } + } + + var prevEp = s.ep + + if psar > closing.Last(0) { + s.Trend = append(s.Trend, Falling) + s.ep = math.Min(s.ep, low.Last(0)) + } else { + s.Trend = append(s.Trend, Rising) + s.ep = math.Max(s.ep, high.Last(0)) + } + + if s.Trend[i] != s.Trend[i-1] { + s.af = psarAfStep + } else if prevEp != s.ep && s.af < psarAfMax { + s.af += psarAfStep + } + + s.PushAndEmit(psar) + }) + + return s +} + +func (s *PSARStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) +} diff --git a/pkg/indicator/v2/trend/parabolic_sar_test.go b/pkg/indicator/v2/trend/parabolic_sar_test.go new file mode 100644 index 0000000000..94383f363a --- /dev/null +++ b/pkg/indicator/v2/trend/parabolic_sar_test.go @@ -0,0 +1,67 @@ +package trend + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestParabolicSAR(t *testing.T) { + ts := []types.KLine{ + {Open: n(3836.86), High: n(3836.86), Low: n(3643.25), Close: n(3790.55)}, + {Open: n(3766.57), High: n(3766.57), Low: n(3542.73), Close: n(3546.20)}, + {Open: n(3576.17), High: n(3576.17), Low: n(3371.75), Close: n(3507.31)}, + {Open: n(3513.55), High: n(3513.55), Low: n(3334.02), Close: n(3340.81)}, + {Open: n(3529.75), High: n(3529.75), Low: n(3314.75), Close: n(3529.60)}, + {Open: n(3756.17), High: n(3756.17), Low: n(3558.21), Close: n(3717.41)}, + {Open: n(3717.17), High: n(3717.17), Low: n(3517.79), Close: n(3544.35)}, + {Open: n(3572.62), High: n(3572.62), Low: n(3447.90), Close: n(3478.14)}, + {Open: n(3612.43), High: n(3612.43), Low: n(3494.39), Close: n(3612.08)}, + } + + expectedValues := []float64{ + 3836.86, + 3836.86, + 3836.86, + 3808.95, + 3770.96, + 3314.75, + 3314.75, + 3323.58, + 3332.23, + } + + expectedTrend := []Trend{ + Falling, + Falling, + Falling, + Falling, + Falling, + Rising, + Rising, + Rising, + Rising, + } + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ParabolicSar(kLines) + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + for i, v := range expectedValues { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected PSAR.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } + + for i, v := range expectedTrend { + assert.Equal(t, v, ind.Trend[i], "Expected PSAR.Trend[%d] to be %v, but got %v", i, v, ind.Trend[i]) + } +} + +func n(n float64) fixedpoint.Value { + return fixedpoint.NewFromFloat(n) +} diff --git a/pkg/indicator/v2/volume/obv.go b/pkg/indicator/v2/volume/obv.go new file mode 100644 index 0000000000..166cce0032 --- /dev/null +++ b/pkg/indicator/v2/volume/obv.go @@ -0,0 +1,41 @@ +package volume + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type OBVStream struct { + *types.Float64Series +} + +// The [Obv](https://pkg.go.dev/github.com/cinar/indicator#Obv) function calculates a technical +// trading momentum indicator that uses volume flow to predict changes in stock price. +func OBV(source v2.KLineSubscription) *OBVStream { + s := &OBVStream{ + Float64Series: types.NewFloat64Series(), + } + + source.AddSubscriber(func(v types.KLine) { + var obv = .0 + + if source.Length() > 1 { + prev := source.Last(1) + obv = s.Slice.Last(0) + + if v.Close > prev.Close { + obv += v.Volume.Float64() + } else if v.Close < prev.Close { + obv -= v.Volume.Float64() + } + } + + s.PushAndEmit(obv) + }) + + return s +} + +func (s *OBVStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volume/obv_test.go b/pkg/indicator/v2/volume/obv_test.go new file mode 100644 index 0000000000..32387d7972 --- /dev/null +++ b/pkg/indicator/v2/volume/obv_test.go @@ -0,0 +1,38 @@ +package volume + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestOBV(t *testing.T) { + close := []byte(`[53.26,53.30,53.32,53.72,54.19,53.92,54.65,54.60,54.21,54.53,53.79,53.66,53.56,53.57,53.94,53.27]`) + volume := []byte(`[88888,8200,8100,8300,8900,9200,13300,10300,9900,10100,11300,12600,10700,11500,23800,14600]`) + buildKLines := func(close, volume []fixedpoint.Value) (kLines []types.KLine) { + for i := range close { + kLines = append(kLines, types.KLine{Close: close[i], Volume: volume[i]}) + } + return kLines + } + var c, v []fixedpoint.Value + _ = json.Unmarshal(close, &c) + _ = json.Unmarshal(volume, &v) + + expected := []float64{0, 8200, 16300, 24600, 33500, 24300, 37600, 27300, 17400, 27500, 16200, 3600, -7100, 4400, 28200, 13600} + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := OBV(kLines) + k := buildKLines(c, v) + for _, candle := range k { + stream.EmitKLineClosed(candle) + } + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected OBV.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv b/pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv new file mode 100644 index 0000000000..903858f076 --- /dev/null +++ b/pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv @@ -0,0 +1,1440 @@ +1651795200000,36533.70,36540.00,36501.00,36505.20,264.779,1651795259999,9670700.33840,3057,71.011,2593768.86330,0 +1651795260000,36506.30,36523.10,36492.30,36522.70,180.741,1651795319999,6598288.01340,2214,70.811,2585241.60220,0 +1651795320000,36522.70,36559.10,36518.90,36549.60,280.910,1651795379999,10263878.29160,2898,155.711,5689249.26850,0 +1651795380000,36549.90,36550.00,36490.00,36534.40,235.291,1651795439999,8591157.31110,2690,78.925,2881502.53680,0 +1651795440000,36534.40,36577.50,36534.40,36574.80,218.490,1651795499999,7988553.23400,2184,133.092,4866125.50710,0 +1651795500000,36574.90,36679.30,36561.40,36611.60,1180.452,1651795559999,43233700.14416,8720,852.525,31228536.48026,0 +1651795560000,36611.60,36614.60,36588.20,36612.70,252.435,1651795619999,9240546.27360,2494,104.381,3821126.58030,0 +1651795620000,36612.80,36647.10,36586.10,36594.50,361.987,1651795679999,13254573.37270,3565,220.110,8060195.17170,0 +1651795680000,36594.60,36598.10,36543.00,36566.60,236.064,1651795739999,8631772.05423,2650,66.766,2441168.29810,0 +1651795740000,36565.90,36565.90,36525.90,36530.80,129.389,1651795799999,4728306.04240,1697,45.836,1674990.33390,0 +1651795800000,36530.90,36544.80,36502.00,36502.60,196.733,1651795859999,7186350.43160,2201,66.478,2428519.05280,0 +1651795860000,36502.60,36542.60,36502.00,36536.00,170.532,1651795919999,6228765.93180,1868,100.253,3661624.33820,0 +1651795920000,36535.90,36544.90,36501.00,36502.10,144.590,1651795979999,5281843.54940,1853,66.928,2445167.78170,0 +1651795980000,36502.10,36508.20,36481.40,36486.20,194.894,1651796039999,7111668.26234,2557,56.351,2056283.27610,0 +1651796040000,36486.10,36488.00,36456.50,36468.90,278.855,1651796099999,10170352.26920,2866,91.712,3344833.82150,0 +1651796100000,36469.00,36498.30,36452.00,36494.00,205.859,1651796159999,7508030.44498,2539,74.080,2701853.99640,0 +1651796160000,36494.90,36499.60,36418.80,36424.30,483.092,1651796219999,17606740.32775,3542,95.065,3464379.92190,0 +1651796220000,36424.30,36455.00,36417.90,36455.00,219.514,1651796279999,7997504.99510,2220,84.997,3097016.83090,0 +1651796280000,36454.90,36454.90,36428.20,36438.80,133.064,1651796339999,4848458.28430,1249,74.445,2712369.98730,0 +1651796340000,36438.80,36488.60,36436.90,36457.10,376.722,1651796399999,13735227.71760,2589,227.732,8302818.25310,0 +1651796400000,36457.10,36464.00,36445.00,36445.90,149.496,1651796459999,5449391.89170,1175,77.283,2817065.22480,0 +1651796460000,36445.80,36475.40,36445.80,36475.40,108.687,1651796519999,3962204.94830,874,77.699,2832552.99970,0 +1651796520000,36475.40,36480.30,36461.70,36472.70,87.026,1651796579999,3174101.78460,951,49.218,1795082.06140,0 +1651796580000,36472.60,36483.70,36461.70,36478.70,96.456,1651796639999,3518032.27920,989,61.587,2246217.65980,0 +1651796640000,36478.80,36495.30,36473.60,36482.30,85.992,1651796699999,3137374.46600,1115,61.956,2260457.10180,0 +1651796700000,36482.40,36486.40,36462.50,36476.50,74.050,1651796759999,2700987.22470,888,31.387,1144836.66790,0 +1651796760000,36476.50,36479.80,36465.40,36479.70,46.815,1651796819999,1707348.69810,684,25.715,937841.92720,0 +1651796820000,36479.80,36479.80,36464.20,36478.60,65.664,1651796879999,2394912.08810,707,13.269,483958.81900,0 +1651796880000,36478.60,36498.80,36475.80,36498.80,79.499,1651796939999,2900676.11680,803,62.808,2291686.49300,0 +1651796940000,36498.80,36499.80,36481.80,36482.00,56.618,1651796999999,2065888.34370,846,24.081,878660.14630,0 +1651797000000,36481.30,36481.30,36439.90,36445.30,135.685,1651797059999,4947441.82440,1564,45.904,1673734.94190,0 +1651797060000,36445.80,36445.90,36383.20,36400.60,433.285,1651797119999,15773318.26744,3938,83.709,3047007.74480,0 +1651797120000,36400.70,36424.50,36400.60,36406.60,143.237,1651797179999,5215141.71090,1520,59.665,2172272.79150,0 +1651797180000,36406.60,36416.10,36393.90,36416.00,92.201,1651797239999,3356784.32980,1074,24.218,881762.32920,0 +1651797240000,36416.10,36418.40,36394.50,36412.40,108.663,1651797299999,3956196.41830,1292,38.120,1387776.00970,0 +1651797300000,36412.50,36418.80,36408.10,36418.80,67.796,1651797359999,2468624.73700,796,35.281,1284691.47910,0 +1651797360000,36418.80,36419.10,36395.20,36398.60,101.303,1651797419999,3688322.49200,988,24.971,909296.11060,0 +1651797420000,36398.60,36417.60,36398.60,36398.90,139.441,1651797479999,5076907.14100,1391,45.262,1647963.58790,0 +1651797480000,36398.80,36398.90,36380.50,36380.50,143.699,1651797539999,5229193.75480,1312,56.849,2068732.10180,0 +1651797540000,36380.60,36389.60,36363.80,36376.60,333.643,1651797599999,12136309.65340,2233,100.031,3638542.00880,0 +1651797600000,36376.60,36378.50,36360.70,36378.40,249.297,1651797659999,9067201.22970,1656,129.592,4713570.41420,0 +1651797660000,36378.50,36394.10,36378.40,36390.10,63.818,1651797719999,2322207.72400,915,44.050,1602907.20930,0 +1651797720000,36390.10,36407.90,36379.50,36388.40,130.506,1651797779999,4749650.64330,1033,98.201,3573964.16720,0 +1651797780000,36388.40,36400.00,36385.70,36400.00,53.061,1651797839999,1930958.06780,628,35.802,1302897.52000,0 +1651797840000,36400.00,36400.00,36382.30,36389.00,48.983,1651797899999,1782772.21580,769,27.983,1018477.55470,0 +1651797900000,36388.90,36389.00,36351.50,36356.30,170.158,1651797959999,6187308.51365,1494,71.221,2589626.15340,0 +1651797960000,36356.20,36361.30,36340.70,36359.20,195.326,1651798019999,7100334.52990,1622,108.045,3927658.33770,0 +1651798020000,36359.20,36382.80,36355.90,36381.90,117.594,1651798079999,4276955.11370,1075,80.318,2921232.21010,0 +1651798080000,36381.90,36381.90,36348.60,36354.00,169.616,1651798139999,6167483.74750,1175,85.296,3101564.11340,0 +1651798140000,36354.10,36364.00,36352.00,36352.00,37.685,1651798199999,1370091.31320,683,14.911,542116.96270,0 +1651798200000,36352.00,36362.70,36351.20,36357.30,88.140,1651798259999,3204551.03610,780,69.818,2538388.30020,0 +1651798260000,36357.30,36363.60,36343.00,36349.40,115.286,1651798319999,4190832.12120,1134,53.529,1945901.69410,0 +1651798320000,36349.40,36349.50,36282.00,36300.40,466.357,1651798379999,16930016.16279,4867,160.017,5808420.36660,0 +1651798380000,36300.30,36314.40,36282.00,36307.30,212.435,1651798439999,7710996.56950,1905,114.704,4163542.85360,0 +1651798440000,36307.40,36317.10,36268.00,36281.60,198.972,1651798499999,7220735.36590,2260,96.473,3501760.31110,0 +1651798500000,36281.70,36310.10,36274.60,36296.70,161.226,1651798559999,5851642.92180,1702,90.985,3302286.56950,0 +1651798560000,36296.70,36334.30,36296.70,36321.90,150.261,1651798619999,5457394.39220,1594,83.146,3019754.11620,0 +1651798620000,36321.90,36345.80,36321.90,36329.10,132.897,1651798679999,4828732.67990,1353,82.831,3009695.85570,0 +1651798680000,36329.20,36358.80,36328.00,36356.00,102.925,1651798739999,3740465.58510,1369,77.196,2805387.21430,0 +1651798740000,36356.00,36377.10,36349.90,36351.50,160.102,1651798799999,5822564.87880,1662,86.983,3163246.08060,0 +1651798800000,36351.50,36383.00,36348.00,36369.20,212.140,1651798859999,7714816.98010,1831,114.774,4174111.82980,0 +1651798860000,36369.20,36376.30,36367.90,36370.00,95.248,1651798919999,3464200.08070,906,65.901,2396858.83460,0 +1651798920000,36370.00,36383.30,36310.00,36313.10,178.433,1651798979999,6485235.42570,1794,68.796,2500480.92740,0 +1651798980000,36313.00,36340.00,36302.00,36339.90,137.832,1651799039999,5006424.32840,1626,82.235,2986720.38710,0 +1651799040000,36339.90,36347.50,36330.00,36339.60,89.692,1651799099999,3259345.69880,946,41.533,1509292.49850,0 +1651799100000,36339.60,36339.60,36300.10,36307.20,82.471,1651799159999,2995105.24240,1072,29.223,1061255.54760,0 +1651799160000,36307.30,36333.00,36285.00,36330.20,104.928,1651799219999,3809482.68420,1425,54.716,1986491.93320,0 +1651799220000,36330.20,36344.70,36324.70,36329.70,105.905,1651799279999,3848199.18090,1171,66.736,2424851.34300,0 +1651799280000,36329.80,36329.80,36301.90,36304.90,68.483,1651799339999,2486955.84840,873,22.275,808855.25140,0 +1651799340000,36304.90,36311.70,36296.60,36303.70,100.212,1651799399999,3638075.29780,948,77.299,2806282.65780,0 +1651799400000,36303.80,36320.90,36299.30,36308.70,61.795,1651799459999,2243691.03970,1002,31.736,1152225.76660,0 +1651799460000,36308.60,36318.60,36308.60,36312.00,50.410,1651799519999,1830494.53520,830,27.731,1006950.75950,0 +1651799520000,36312.00,36314.10,36303.50,36307.00,57.545,1651799579999,2089484.27060,872,23.562,855544.25040,0 +1651799580000,36307.00,36307.10,36281.00,36281.00,127.081,1651799639999,4612157.38410,1099,22.310,809630.51380,0 +1651799640000,36281.10,36288.10,36249.70,36255.90,267.356,1651799699999,9696782.30389,2585,90.061,3266385.35380,0 +1651799700000,36255.90,36277.00,36248.70,36263.90,211.770,1651799759999,7679197.72070,2104,117.985,4278436.50450,0 +1651799760000,36263.90,36308.00,36262.50,36301.90,110.535,1651799819999,4010364.26910,1191,84.119,3051872.67780,0 +1651799820000,36302.00,36343.90,36301.90,36322.90,139.926,1651799879999,5082858.83280,1865,80.179,2912339.99850,0 +1651799880000,36322.90,36323.00,36300.00,36302.10,72.012,1651799939999,2614947.89340,916,32.262,1171529.10500,0 +1651799940000,36302.10,36302.10,36276.50,36276.50,61.924,1651799999999,2247380.76230,1039,24.090,874283.76660,0 +1651800000000,36276.60,36290.10,36267.70,36269.90,89.058,1651800059999,3230726.57900,1230,41.114,1491489.50170,0 +1651800060000,36270.00,36289.50,36220.30,36230.60,329.222,1651800119999,11934465.45660,3421,92.281,3345685.96640,0 +1651800120000,36230.50,36257.10,36217.00,36224.70,180.799,1651800179999,6551016.09890,2379,75.490,2735280.23000,0 +1651800180000,36224.70,36224.70,36205.20,36221.00,184.256,1651800239999,6672835.36700,2019,83.897,3038496.28540,0 +1651800240000,36221.10,36224.70,36131.40,36144.30,672.904,1651800299999,24340492.73441,4653,113.289,4100130.37900,0 +1651800300000,36144.30,36218.80,36128.80,36211.90,531.095,1651800359999,19212066.12150,4623,259.757,9397916.03530,0 +1651800360000,36211.80,36253.50,36191.70,36199.00,268.792,1651800419999,9736346.15606,2727,183.218,6636713.19356,0 +1651800420000,36198.90,36263.00,36198.90,36254.30,254.899,1651800479999,9234678.06530,2090,187.846,6804930.14250,0 +1651800480000,36254.40,36263.30,36235.90,36242.20,176.673,1651800539999,6404361.00150,1381,51.371,1862474.59930,0 +1651800540000,36242.20,36266.00,36225.30,36236.50,130.639,1651800599999,4734958.53700,1354,89.859,3256893.85040,0 +1651800600000,36236.50,36249.80,36206.60,36248.60,179.159,1651800659999,6491166.30960,1518,94.573,3426744.42270,0 +1651800660000,36248.50,36257.60,36242.60,36256.50,58.693,1651800719999,2127658.76460,1130,33.871,1227860.93190,0 +1651800720000,36256.50,36266.00,36249.10,36249.20,72.034,1651800779999,2611764.16000,957,38.843,1408356.18270,0 +1651800780000,36249.10,36249.20,36206.00,36215.00,106.001,1651800839999,3839574.22070,1412,33.318,1206772.16930,0 +1651800840000,36215.00,36215.00,36184.60,36191.90,118.649,1651800899999,4295218.39470,1371,34.700,1256258.80810,0 +1651800900000,36191.80,36213.80,36191.30,36212.10,82.786,1651800959999,2997105.99350,1130,39.094,1415302.46440,0 +1651800960000,36212.20,36213.90,36194.40,36213.00,110.766,1651801019999,4010467.05460,1221,39.725,1438332.91640,0 +1651801020000,36213.00,36232.80,36210.20,36218.80,63.085,1651801079999,2285165.79400,986,24.693,894455.06630,0 +1651801080000,36218.70,36227.00,36213.10,36223.80,114.877,1651801139999,4160931.30750,1014,78.703,2850701.06390,0 +1651801140000,36223.70,36227.30,36218.30,36220.90,59.258,1651801199999,2146505.47630,818,30.348,1099255.77110,0 +1651801200000,36220.90,36246.50,36220.00,36243.70,88.571,1651801259999,3209524.68580,1052,79.095,2866145.95830,0 +1651801260000,36243.70,36269.00,36243.60,36256.90,165.340,1651801319999,5995175.41810,1456,95.706,3470163.76500,0 +1651801320000,36257.00,36275.90,36255.20,36269.70,175.535,1651801379999,6365773.26710,1322,100.856,3657660.84300,0 +1651801380000,36269.70,36271.00,36241.00,36244.80,110.364,1651801439999,4001044.98890,1102,38.881,1409460.56940,0 +1651801440000,36244.70,36248.50,36222.00,36244.20,95.926,1651801499999,3475877.92450,1067,50.878,1843604.39660,0 +1651801500000,36244.20,36244.20,36226.80,36226.80,39.434,1651801559999,1428833.10250,777,22.863,828380.72770,0 +1651801560000,36226.00,36237.10,36217.00,36236.80,91.337,1651801619999,3308504.67400,875,41.425,1500585.68540,0 +1651801620000,36236.70,36254.90,36236.70,36246.90,74.877,1651801679999,2714063.04460,1050,48.894,1772229.81450,0 +1651801680000,36246.80,36273.60,36246.80,36256.80,124.189,1651801739999,4503054.13240,1329,75.585,2740696.86630,0 +1651801740000,36257.70,36262.40,36211.70,36219.20,256.616,1651801799999,9296070.16680,1833,43.114,1562009.04340,0 +1651801800000,36219.30,36219.30,36193.90,36194.00,125.352,1651801859999,4538976.86280,1291,61.905,2241576.19410,0 +1651801860000,36193.90,36204.00,36192.20,36198.00,63.088,1651801919999,2283688.15940,782,30.265,1095508.91230,0 +1651801920000,36198.00,36208.10,36190.10,36205.10,59.293,1651801979999,2146347.40760,846,27.529,996534.70250,0 +1651801980000,36205.10,36223.20,36203.40,36223.20,54.865,1651802039999,1986782.43680,825,31.405,1137264.45330,0 +1651802040000,36223.20,36248.70,36217.10,36240.60,88.056,1651802099999,3190341.67590,851,43.296,1568589.45210,0 +1651802100000,36240.50,36253.40,36240.50,36253.30,50.685,1651802159999,1837168.33650,612,29.192,1058111.46500,0 +1651802160000,36253.40,36263.90,36245.50,36263.90,95.049,1651802219999,3445984.66560,892,49.955,1811132.38910,0 +1651802220000,36263.90,36276.00,36261.00,36275.90,232.561,1651802279999,8435177.96550,1286,114.259,4144296.63460,0 +1651802280000,36275.90,36285.70,36275.90,36285.70,92.406,1651802339999,3352568.85010,892,66.040,2395979.86540,0 +1651802340000,36285.60,36296.40,36283.50,36293.00,100.288,1651802399999,3639285.28140,985,57.736,2095171.92680,0 +1651802400000,36293.00,36297.70,36292.00,36292.60,134.336,1651802459999,4875547.81250,835,78.003,2831039.45190,0 +1651802460000,36292.50,36316.10,36290.80,36316.10,155.536,1651802519999,5645585.87519,1346,103.651,3762375.81899,0 +1651802520000,36316.10,36329.00,36296.20,36303.70,269.417,1651802579999,9784558.01420,2113,126.101,4579934.57530,0 +1651802580000,36303.70,36313.30,36294.60,36313.30,90.393,1651802639999,3281541.42980,939,43.293,1571700.77150,0 +1651802640000,36313.20,36326.80,36313.20,36317.10,224.759,1651802699999,8163367.84760,1360,120.476,4375567.29900,0 +1651802700000,36317.10,36362.00,36317.10,36348.90,320.718,1651802759999,11656896.15041,2370,213.009,7742161.03501,0 +1651802760000,36348.90,36350.00,36345.00,36345.10,65.178,1651802819999,2369019.10670,1141,33.998,1235701.51360,0 +1651802820000,36345.10,36365.90,36345.00,36362.10,95.984,1651802879999,3489790.71190,1225,68.404,2487037.82800,0 +1651802880000,36362.00,36362.10,36341.20,36361.10,159.341,1651802939999,5792545.07540,1008,44.951,1634133.81570,0 +1651802940000,36361.10,36386.40,36359.20,36379.30,217.826,1651802999999,7922852.22080,2031,94.194,3426287.28770,0 +1651803000000,36379.30,36411.50,36370.30,36409.10,352.490,1651803059999,12826655.51742,3142,180.732,6577203.97902,0 +1651803060000,36409.20,36413.30,36377.70,36408.80,240.542,1651803119999,8755188.64690,2490,73.607,2679455.54910,0 +1651803120000,36408.70,36413.00,36387.50,36407.10,135.680,1651803179999,4938901.26860,1744,87.232,3175474.57130,0 +1651803180000,36407.10,36428.50,36407.10,36418.90,180.713,1651803239999,6581339.83792,1839,130.773,4762587.52992,0 +1651803240000,36418.90,36439.20,36418.90,36433.40,122.685,1651803299999,4469769.05266,1258,66.323,2416243.82686,0 +1651803300000,36433.50,36445.00,36419.90,36443.80,219.117,1651803359999,7983510.69692,2640,94.563,3445458.35322,0 +1651803360000,36443.80,36499.20,36438.80,36494.20,425.714,1651803419999,15524857.30971,3550,311.144,11347337.07461,0 +1651803420000,36494.30,36515.20,36467.10,36494.40,359.740,1651803479999,13126778.31435,3580,126.866,4630215.84725,0 +1651803480000,36494.50,36507.90,36474.30,36474.90,333.269,1651803539999,12162009.79070,2677,135.139,4931972.34620,0 +1651803540000,36474.30,36486.10,36450.00,36450.10,183.873,1651803599999,6705601.19480,2388,41.212,1503082.08870,0 +1651803600000,36450.10,36460.40,36423.50,36460.40,221.455,1651803659999,8068992.00370,2525,103.066,3755478.37970,0 +1651803660000,36460.40,36464.70,36438.80,36439.80,63.607,1651803719999,2318748.12310,1023,22.471,819214.73370,0 +1651803720000,36439.70,36496.90,36439.70,36496.80,136.025,1651803779999,4959997.26230,1678,99.838,3640536.12800,0 +1651803780000,36496.90,36496.90,36451.60,36464.80,115.505,1651803839999,4212100.20650,1617,22.733,829040.16470,0 +1651803840000,36464.70,36496.70,36450.80,36480.50,190.813,1651803899999,6960635.33650,2343,62.510,2280413.39020,0 +1651803900000,36480.50,36485.90,36474.10,36481.00,107.528,1651803959999,3922765.68130,1155,56.193,2049981.84280,0 +1651803960000,36481.00,36481.00,36456.90,36474.30,150.678,1651804019999,5495154.48660,1653,52.837,1926829.14480,0 +1651804020000,36474.30,36494.30,36464.00,36494.30,98.011,1651804079999,3575084.19100,1088,75.070,2738412.19140,0 +1651804080000,36494.30,36520.90,36491.40,36505.60,287.629,1651804139999,10500100.77670,2442,182.008,6643765.11580,0 +1651804140000,36504.60,36529.90,36501.50,36524.60,184.312,1651804199999,6730638.77404,1997,84.333,3079816.07224,0 +1651804200000,36524.50,36528.90,36495.70,36495.80,108.193,1651804259999,3950233.37620,1586,42.750,1560933.22270,0 +1651804260000,36495.70,36505.00,36455.90,36475.60,351.842,1651804319999,12834329.70360,2904,66.204,2415234.55950,0 +1651804320000,36475.60,36479.10,36455.90,36455.90,115.193,1651804379999,4200992.63960,1254,31.162,1136508.81600,0 +1651804380000,36455.90,36480.00,36453.00,36469.70,196.254,1651804439999,7156333.97900,1280,145.584,5308480.19000,0 +1651804440000,36469.70,36475.00,36460.00,36474.90,63.627,1651804499999,2320373.13740,681,27.116,988905.34630,0 +1651804500000,36475.00,36479.90,36466.00,36469.00,78.625,1651804559999,2867788.82030,924,21.462,782786.77050,0 +1651804560000,36469.10,36469.10,36460.00,36460.50,64.746,1651804619999,2360947.58440,648,16.249,592488.61320,0 +1651804620000,36460.60,36473.70,36450.00,36464.80,276.074,1651804679999,10065277.80870,1466,71.188,2595502.82560,0 +1651804680000,36464.80,36470.70,36461.90,36463.80,59.683,1651804739999,2176460.69660,568,27.995,1020888.16360,0 +1651804740000,36463.80,36463.90,36451.90,36463.60,46.344,1651804799999,1689616.30610,648,11.551,421118.69030,0 +1651804800000,36463.50,36463.60,36441.20,36444.20,156.292,1651804859999,5696943.68830,1177,27.227,992452.06470,0 +1651804860000,36444.20,36467.00,36441.20,36467.00,78.095,1651804919999,2846767.29010,812,52.790,1924425.72380,0 +1651804920000,36466.90,36467.00,36457.50,36463.90,85.604,1651804979999,3121411.18010,731,43.074,1570550.00580,0 +1651804980000,36463.80,36466.00,36457.80,36461.80,44.081,1651805039999,1607368.91490,484,23.137,843659.46890,0 +1651805040000,36461.80,36479.10,36461.00,36478.30,76.226,1651805099999,2779965.77400,709,44.358,1617788.93130,0 +1651805100000,36478.20,36479.60,36467.10,36477.90,50.141,1651805159999,1828749.62960,614,12.646,461229.15400,0 +1651805160000,36478.40,36481.40,36464.90,36470.90,68.530,1651805219999,2499716.88650,719,20.826,759647.29400,0 +1651805220000,36470.90,36471.00,36456.80,36456.80,38.089,1651805279999,1388959.21940,558,8.040,293198.14770,0 +1651805280000,36456.80,36468.00,36450.40,36454.00,57.361,1651805339999,2091365.45880,779,21.890,798059.50180,0 +1651805340000,36453.90,36454.00,36446.00,36450.80,63.397,1651805399999,2310779.98840,651,36.482,1329733.32560,0 +1651805400000,36450.90,36461.70,36445.50,36461.70,74.985,1651805459999,2733347.98760,877,43.225,1575647.93620,0 +1651805460000,36461.60,36477.80,36461.60,36477.60,75.511,1651805519999,2753846.85450,624,49.152,1792631.79850,0 +1651805520000,36477.60,36482.30,36473.50,36480.20,63.060,1651805579999,2300340.78840,688,35.982,1312567.26840,0 +1651805580000,36480.30,36480.30,36437.90,36441.30,149.648,1651805639999,5457121.29650,1186,26.953,982799.36920,0 +1651805640000,36441.30,36445.40,36417.90,36441.00,302.826,1651805699999,11032234.00680,1648,136.411,4969384.13830,0 +1651805700000,36441.00,36449.20,36401.00,36412.20,224.999,1651805759999,8194438.50660,1780,48.267,1758107.67380,0 +1651805760000,36412.20,36420.10,36405.70,36413.50,88.098,1651805819999,3207939.16450,1079,51.083,1860112.55750,0 +1651805820000,36413.80,36417.70,36409.40,36412.40,66.601,1651805879999,2425154.79050,668,16.714,608617.35950,0 +1651805880000,36412.40,36426.90,36408.70,36410.00,67.922,1651805939999,2473510.67420,817,26.267,956550.02370,0 +1651805940000,36410.10,36415.90,36396.50,36415.90,100.542,1651805999999,3660196.90360,980,25.788,938886.33970,0 +1651806000000,36415.80,36426.90,36415.80,36417.30,91.949,1651806059999,3349018.44910,855,30.687,1117637.79870,0 +1651806060000,36416.10,36421.00,36412.80,36412.90,69.211,1651806119999,2520330.58330,653,34.736,1264897.91040,0 +1651806120000,36413.00,36429.90,36412.90,36429.90,40.931,1651806179999,1490555.25980,567,30.005,1092683.04540,0 +1651806180000,36429.90,36453.40,36429.80,36452.40,157.470,1651806239999,5739269.16240,1237,87.155,3176461.45990,0 +1651806240000,36452.30,36452.30,36427.50,36433.00,68.669,1651806299999,2502026.38500,897,38.201,1391766.54250,0 +1651806300000,36433.00,36433.10,36422.40,36425.30,69.334,1651806359999,2525748.70550,786,35.670,1299390.21150,0 +1651806360000,36425.30,36438.50,36425.30,36437.90,55.935,1651806419999,2037820.74840,797,41.718,1519841.36520,0 +1651806420000,36437.90,36452.00,36437.90,36440.10,51.743,1651806479999,1885887.12020,768,36.048,1313815.98200,0 +1651806480000,36440.00,36450.40,36440.00,36444.80,52.522,1651806539999,1914176.63380,639,35.494,1293557.40880,0 +1651806540000,36444.80,36448.70,36427.80,36433.30,23.821,1651806599999,867998.81420,688,12.184,443942.05660,0 +1651806600000,36433.40,36433.40,36388.40,36392.60,187.899,1651806659999,6840825.29290,1571,56.172,2045216.24740,0 +1651806660000,36392.80,36399.80,36367.00,36367.10,221.185,1651806719999,8046695.98850,2257,68.486,2491695.65480,0 +1651806720000,36367.10,36408.80,36367.10,36398.30,105.069,1651806779999,3823020.71360,1307,53.680,1952964.92800,0 +1651806780000,36398.30,36408.00,36398.30,36407.40,38.354,1651806839999,1396252.39630,672,14.481,527170.07250,0 +1651806840000,36407.40,36416.00,36398.80,36402.70,48.172,1651806899999,1753693.18440,656,29.832,1086022.22300,0 +1651806900000,36402.80,36402.80,36379.40,36387.30,61.032,1651806959999,2220966.73010,1009,18.652,678736.84760,0 +1651806960000,36388.20,36399.20,36388.10,36390.80,62.299,1651807019999,2267383.03640,803,27.593,1004184.67630,0 +1651807020000,36390.80,36390.90,36362.70,36366.40,119.476,1651807079999,4346048.51540,1384,44.096,1603845.09360,0 +1651807080000,36366.50,36382.50,36366.40,36382.50,76.207,1651807139999,2771734.35520,955,54.010,1964417.16630,0 +1651807140000,36382.50,36400.60,36382.40,36396.30,49.620,1651807199999,1805859.77040,727,29.986,1091311.45670,0 +1651807200000,36396.40,36396.80,36371.80,36381.80,48.593,1651807259999,1768071.14640,721,11.711,426087.09760,0 +1651807260000,36381.70,36382.20,36375.50,36377.20,25.523,1651807319999,928550.52690,527,6.865,249757.64950,0 +1651807320000,36377.20,36377.30,36360.30,36360.30,36.364,1651807379999,1322538.46000,664,6.871,249899.02360,0 +1651807380000,36360.30,36382.10,36360.30,36378.90,71.449,1651807439999,2598425.44580,975,22.912,833249.47450,0 +1651807440000,36378.90,36381.30,36367.30,36379.30,59.554,1651807499999,2166302.39080,801,25.449,925701.56740,0 +1651807500000,36379.40,36379.40,36351.10,36359.90,113.911,1651807559999,4141960.58645,1144,29.111,1058514.64910,0 +1651807560000,36360.00,36360.00,36345.00,36357.30,83.656,1651807619999,3040903.25710,1303,26.644,968521.89560,0 +1651807620000,36357.40,36357.40,36348.90,36353.70,44.869,1651807679999,1631111.78530,659,18.213,662081.54430,0 +1651807680000,36353.70,36366.90,36353.70,36364.70,39.684,1651807739999,1443013.46780,602,27.089,985011.54530,0 +1651807740000,36364.80,36365.90,36360.70,36363.50,35.885,1651807799999,1304940.35880,462,19.256,700238.17270,0 +1651807800000,36363.40,36372.90,36345.90,36372.90,91.328,1651807859999,3320469.51930,1040,57.715,2098467.63840,0 +1651807860000,36372.90,36401.80,36372.80,36400.40,247.654,1651807919999,9012506.59790,1803,206.928,7530457.82700,0 +1651807920000,36400.40,36406.70,36396.10,36396.20,71.965,1651807979999,2619721.32250,980,36.542,1330222.40390,0 +1651807980000,36396.20,36411.80,36396.10,36400.90,61.964,1651808039999,2255717.39130,818,36.328,1322424.31340,0 +1651808040000,36400.80,36406.10,36396.20,36406.10,59.434,1651808099999,2163420.47130,617,37.658,1370793.35090,0 +1651808100000,36406.00,36423.10,36406.00,36413.00,106.970,1651808159999,3895352.81530,1207,83.804,3051744.45770,0 +1651808160000,36413.00,36437.70,36413.00,36416.70,131.748,1651808219999,4799070.30890,1254,89.957,3276809.57570,0 +1651808220000,36416.80,36416.80,36400.00,36408.00,92.966,1651808279999,3384683.28880,848,27.021,983729.94340,0 +1651808280000,36407.90,36408.00,36404.80,36405.00,46.900,1651808339999,1707448.40280,532,36.556,1330859.60590,0 +1651808340000,36404.90,36410.20,36404.80,36406.10,30.001,1651808399999,1092212.11690,511,21.084,767584.57770,0 +1651808400000,36406.10,36406.20,36400.20,36400.90,31.122,1651808459999,1132931.47530,490,14.530,528939.84730,0 +1651808460000,36400.90,36400.90,36382.00,36395.00,76.950,1651808519999,2800412.97800,858,24.518,892261.24700,0 +1651808520000,36395.00,36395.00,36352.00,36370.70,132.977,1651808579999,4836220.15710,1302,40.275,1464624.29190,0 +1651808580000,36370.60,36370.70,36336.60,36353.00,173.247,1651808639999,6297106.75996,1481,45.415,1650765.76550,0 +1651808640000,36353.00,36353.10,36343.10,36348.10,68.123,1651808699999,2476026.84420,1003,27.345,993889.05460,0 +1651808700000,36348.20,36359.40,36347.40,36354.90,93.789,1651808759999,3409399.38420,917,64.667,2350733.79850,0 +1651808760000,36355.00,36395.00,36354.90,36394.90,70.706,1651808819999,2571966.69250,1100,48.963,1781022.15390,0 +1651808820000,36395.00,36395.70,36371.00,36377.00,77.079,1651808879999,2804417.74050,789,22.526,819415.35500,0 +1651808880000,36376.90,36390.00,36376.90,36390.00,25.832,1651808939999,939851.93430,442,21.780,792410.51890,0 +1651808940000,36389.90,36394.00,36385.00,36394.00,78.167,1651808999999,2844413.52490,553,47.384,1724238.56700,0 +1651809000000,36395.60,36411.70,36395.60,36400.90,134.660,1651809059999,4902168.80410,1133,66.284,2412957.50360,0 +1651809060000,36400.80,36406.40,36397.00,36402.30,100.836,1651809119999,3670603.01920,725,68.925,2508959.61330,0 +1651809120000,36402.60,36428.50,36402.60,36424.80,94.918,1651809179999,3457121.83630,1176,62.606,2280162.90080,0 +1651809180000,36423.70,36434.20,36419.60,36430.60,78.490,1651809239999,2859329.14070,905,56.485,2057694.81870,0 +1651809240000,36430.70,36430.90,36421.70,36424.00,40.518,1651809299999,1475891.24150,610,23.309,849044.11850,0 +1651809300000,36423.90,36432.70,36415.40,36418.00,84.898,1651809359999,3092404.26920,886,40.553,1477179.28450,0 +1651809360000,36418.00,36418.10,36361.20,36364.30,60.523,1651809419999,2202477.71210,933,11.379,414105.34730,0 +1651809420000,36364.30,36376.30,36364.10,36371.20,95.059,1651809479999,3457181.95130,922,63.903,2324080.94360,0 +1651809480000,36371.20,36382.80,36369.40,36382.20,97.743,1651809539999,3555453.03340,755,78.611,2859529.91570,0 +1651809540000,36382.20,36446.40,36382.20,36441.40,202.423,1651809599999,7372805.87640,1436,130.802,4763418.21820,0 +1651809600000,36442.50,36459.70,36437.70,36437.70,192.268,1651809659999,7008155.54411,1782,115.449,4208159.29701,0 +1651809660000,36437.70,36438.50,36406.40,36421.10,133.001,1651809719999,4844446.17380,1314,42.978,1565303.85330,0 +1651809720000,36421.00,36428.00,36421.00,36421.10,30.169,1651809779999,1098866.18900,457,16.619,605318.42450,0 +1651809780000,36421.20,36430.00,36420.00,36426.20,64.832,1651809839999,2361417.26970,640,17.319,630838.50740,0 +1651809840000,36426.10,36428.90,36413.80,36425.20,43.564,1651809899999,1586638.05810,729,29.188,1063037.32220,0 +1651809900000,36425.20,36428.80,36421.20,36421.20,36.984,1651809959999,1347122.82860,650,8.500,309610.60280,0 +1651809960000,36421.30,36421.30,36390.60,36390.60,88.827,1651810019999,3233500.13680,1073,42.133,1533599.49710,0 +1651810020000,36390.60,36390.70,36366.50,36368.70,79.669,1651810079999,2898294.81480,1005,36.310,1320878.55380,0 +1651810080000,36368.80,36397.00,36368.80,36385.40,118.638,1651810139999,4316447.45540,1116,73.876,2687923.59970,0 +1651810140000,36385.50,36390.30,36357.30,36369.50,86.821,1651810199999,3157554.51180,943,37.990,1381657.57130,0 +1651810200000,36369.60,36377.30,36361.30,36361.40,67.388,1651810259999,2450815.17180,898,23.944,870822.75420,0 +1651810260000,36361.30,36361.40,36325.90,36346.40,308.944,1651810319999,11227675.49925,2160,63.994,2325617.34540,0 +1651810320000,36346.40,36347.70,36324.50,36329.00,81.281,1651810379999,2953237.85900,1150,33.594,1220615.57550,0 +1651810380000,36329.00,36348.00,36323.90,36344.90,144.182,1651810439999,5238821.54950,1418,55.452,2014988.61040,0 +1651810440000,36345.00,36356.60,36312.40,36317.90,107.353,1651810499999,3900635.86784,1465,49.861,1811701.84630,0 +1651810500000,36317.90,36355.20,36311.80,36345.30,101.003,1651810559999,3670313.12600,1193,53.272,1935980.42220,0 +1651810560000,36345.20,36358.00,36336.40,36358.00,65.418,1651810619999,2378073.45400,931,38.624,1404058.26130,0 +1651810620000,36358.00,36368.00,36357.90,36359.00,59.113,1651810679999,2149487.32580,686,32.982,1199307.40680,0 +1651810680000,36359.10,36359.10,36331.00,36334.80,84.126,1651810739999,3057179.22140,868,14.827,538815.11720,0 +1651810740000,36334.80,36348.00,36259.80,36292.10,975.860,1651810799999,35422341.30717,4763,354.341,12860864.80620,0 +1651810800000,36292.00,36311.50,36288.80,36303.40,396.578,1651810859999,14395610.88660,2239,241.303,8759106.10940,0 +1651810860000,36303.40,36310.00,36299.00,36310.00,53.499,1651810919999,1942359.97850,612,35.242,1279555.50400,0 +1651810920000,36310.00,36310.00,36297.30,36299.90,33.091,1651810979999,1201345.66400,535,12.729,462128.09020,0 +1651810980000,36300.00,36321.00,36300.00,36321.00,55.838,1651811039999,2027553.39890,627,38.710,1405575.02880,0 +1651811040000,36321.00,36327.00,36311.50,36312.40,43.014,1651811099999,1562305.01070,614,21.503,781024.63670,0 +1651811100000,36312.40,36335.20,36312.40,36328.20,61.025,1651811159999,2216896.60930,710,44.479,1615775.03830,0 +1651811160000,36328.20,36328.20,36308.60,36318.00,69.464,1651811219999,2522685.44230,929,19.704,715598.49670,0 +1651811220000,36318.00,36318.60,36309.70,36309.70,39.510,1651811279999,1434823.74300,604,12.342,448226.78220,0 +1651811280000,36309.80,36325.00,36309.70,36315.10,46.530,1651811339999,1689783.55520,686,30.891,1121785.24150,0 +1651811340000,36315.00,36339.40,36315.00,36318.50,67.743,1651811399999,2461076.34130,825,44.607,1620634.96540,0 +1651811400000,36318.40,36332.60,36318.40,36331.00,37.288,1651811459999,1354571.66550,603,26.886,976688.19110,0 +1651811460000,36330.90,36334.10,36320.20,36323.40,56.425,1651811519999,2049610.35650,606,25.918,941440.15320,0 +1651811520000,36323.30,36334.70,36313.40,36313.40,69.543,1651811579999,2525959.10240,765,25.266,917716.71220,0 +1651811580000,36313.40,36328.00,36313.40,36328.00,24.042,1651811639999,873213.37910,377,16.125,585644.77650,0 +1651811640000,36328.00,36339.50,36327.90,36338.30,29.309,1651811699999,1064976.32070,480,18.422,669369.85070,0 +1651811700000,36338.30,36353.00,36338.20,36343.90,42.231,1651811759999,1534927.08640,712,25.871,940290.96580,0 +1651811760000,36343.90,36348.30,36322.40,36331.90,82.585,1651811819999,3000764.11380,889,38.401,1395332.76330,0 +1651811820000,36331.80,36337.70,36323.90,36325.80,22.804,1651811879999,828523.22030,499,13.911,505422.70930,0 +1651811880000,36325.90,36332.00,36321.10,36321.10,38.601,1651811939999,1402164.36600,568,16.320,592826.22120,0 +1651811940000,36321.10,36323.10,36301.70,36305.10,89.656,1651811999999,3255564.08900,924,16.778,609248.81810,0 +1651812000000,36305.10,36317.60,36302.30,36317.20,75.405,1651812059999,2738083.74110,1083,34.035,1235837.62590,0 +1651812060000,36317.10,36345.10,36317.10,36338.30,46.374,1651812119999,1685019.23980,586,35.638,1294899.73630,0 +1651812120000,36338.30,36338.30,36320.10,36328.90,33.835,1651812179999,1229258.50830,437,20.046,728260.18100,0 +1651812180000,36328.80,36337.40,36324.60,36334.40,40.409,1651812239999,1468119.26830,499,25.779,936611.43890,0 +1651812240000,36334.40,36340.00,36331.00,36340.00,33.290,1651812299999,1209588.49960,469,19.814,719944.12700,0 +1651812300000,36340.00,36365.90,36329.20,36356.90,74.920,1651812359999,2723440.61780,966,43.463,1580004.84910,0 +1651812360000,36356.90,36378.60,36356.80,36376.60,104.895,1651812419999,3815013.77660,930,89.291,3247562.47980,0 +1651812420000,36376.50,36376.90,36354.10,36365.30,67.322,1651812479999,2448174.13360,758,36.540,1328813.97360,0 +1651812480000,36365.20,36387.10,36365.20,36376.50,108.556,1651812539999,3949049.64460,1135,86.296,3139274.80990,0 +1651812540000,36376.50,36393.40,36376.40,36391.40,60.943,1651812599999,2217424.91190,689,45.260,1646854.15330,0 +1651812600000,36391.50,36397.70,36373.30,36373.40,87.568,1651812659999,3186384.04900,976,27.702,1008035.52520,0 +1651812660000,36373.40,36373.40,36356.90,36358.70,46.748,1651812719999,1700042.91320,663,14.396,523502.38790,0 +1651812720000,36358.70,36369.00,36350.00,36357.40,77.106,1651812779999,2803306.90130,840,23.541,855865.98870,0 +1651812780000,36357.30,36357.40,36339.00,36339.00,25.620,1651812839999,931203.08000,457,8.855,321827.37890,0 +1651812840000,36339.10,36339.10,36327.00,36327.20,52.352,1651812899999,1902005.56580,780,31.383,1140172.71740,0 +1651812900000,36327.20,36330.00,36313.00,36313.10,92.339,1651812959999,3354098.16860,806,18.407,668630.36210,0 +1651812960000,36313.00,36359.40,36311.50,36350.40,241.158,1651813019999,8761642.52560,1642,172.686,6274016.46810,0 +1651813020000,36350.30,36389.40,36350.30,36367.70,73.767,1651813079999,2683358.09290,842,46.949,1707849.41850,0 +1651813080000,36367.60,36384.30,36367.60,36373.30,72.202,1651813139999,2626522.00710,699,37.209,1353504.60720,0 +1651813140000,36373.40,36417.20,36367.60,36414.90,182.811,1651813199999,6653343.64670,1834,124.275,4523264.75010,0 +1651813200000,36414.80,36414.90,36392.60,36393.80,110.668,1651813259999,4028959.51190,1289,48.359,1760677.94110,0 +1651813260000,36393.80,36434.10,36391.10,36432.90,154.803,1651813319999,5637965.63450,1770,73.996,2695047.25680,0 +1651813320000,36433.90,36442.30,36411.60,36414.40,96.336,1651813379999,3509724.10790,1101,39.828,1451049.69810,0 +1651813380000,36414.40,36414.40,36405.10,36410.30,57.977,1651813439999,2110875.90310,845,23.616,859817.95640,0 +1651813440000,36410.20,36440.70,36409.50,36429.00,143.904,1651813499999,5241632.27770,1064,115.147,4194189.93170,0 +1651813500000,36429.00,36449.80,36403.20,36408.00,106.389,1651813559999,3875900.76256,1250,39.360,1434150.23146,0 +1651813560000,36407.90,36407.90,36395.00,36395.10,46.276,1651813619999,1684446.67310,696,17.691,643942.38010,0 +1651813620000,36395.10,36395.20,36379.00,36381.70,109.187,1651813679999,3972767.34930,928,15.136,550701.54360,0 +1651813680000,36381.60,36381.70,36373.10,36378.60,61.367,1651813739999,2232362.90900,761,24.750,900291.40190,0 +1651813740000,36378.70,36382.30,36358.70,36378.10,126.782,1651813799999,4611134.36590,1152,81.349,2958860.74810,0 +1651813800000,36378.10,36385.00,36363.90,36366.70,76.407,1651813859999,2779320.26400,949,35.251,1282303.88700,0 +1651813860000,36366.80,36404.10,36366.70,36397.70,63.141,1651813919999,2298056.29180,928,45.960,1672800.75680,0 +1651813920000,36397.80,36400.00,36397.70,36400.00,16.959,1651813979999,617276.52490,267,11.459,417084.82770,0 +1651813980000,36399.90,36430.00,36389.70,36424.20,120.501,1651814039999,4387919.21080,1337,75.035,2732260.64710,0 +1651814040000,36424.20,36424.20,36403.50,36408.90,62.914,1651814099999,2290910.93270,729,21.178,771154.17600,0 +1651814100000,36409.00,36424.00,36398.90,36398.90,61.820,1651814159999,2250791.00110,715,33.114,1205687.72700,0 +1651814160000,36399.00,36407.00,36392.50,36406.90,36.594,1651814219999,1331968.37340,546,13.898,505878.78200,0 +1651814220000,36406.90,36443.70,36406.90,36432.60,101.748,1651814279999,3707094.66600,947,79.255,2887544.07980,0 +1651814280000,36432.60,36434.30,36412.40,36430.00,184.206,1651814339999,6709386.70050,1140,43.048,1567899.80530,0 +1651814340000,36429.90,36441.10,36420.00,36423.70,75.684,1651814399999,2757010.28610,748,25.252,919940.67690,0 +1651814400000,36423.80,36449.00,36423.10,36439.20,76.667,1651814459999,2793522.72590,1007,49.013,1785974.69770,0 +1651814460000,36439.20,36460.50,36438.90,36452.40,121.384,1651814519999,4424300.25461,1066,101.460,3698199.59991,0 +1651814520000,36452.50,36460.60,36445.00,36445.00,103.491,1651814579999,3772416.05810,997,35.851,1306846.44100,0 +1651814580000,36445.00,36450.20,36437.90,36446.60,69.413,1651814639999,2529671.03550,873,29.345,1069473.18720,0 +1651814640000,36446.60,36449.00,36437.70,36442.00,35.338,1651814699999,1287863.10210,515,20.608,751041.83870,0 +1651814700000,36442.00,36450.00,36441.90,36450.00,28.548,1651814759999,1040516.03540,421,17.273,629563.12660,0 +1651814760000,36449.90,36450.00,36435.00,36441.80,106.474,1651814819999,3880185.60340,869,25.817,940892.06150,0 +1651814820000,36441.90,36441.90,36441.00,36441.00,21.553,1651814879999,785427.80180,353,7.902,287963.34320,0 +1651814880000,36441.10,36450.70,36424.90,36443.00,75.316,1651814939999,2744101.99060,687,26.493,965352.49060,0 +1651814940000,36443.10,36449.10,36441.60,36445.40,41.806,1651814999999,1523666.42150,586,18.592,677617.98270,0 +1651815000000,36445.40,36457.40,36413.20,36415.60,129.268,1651815059999,4709897.63010,1318,69.035,2515332.50450,0 +1651815060000,36415.70,36425.40,36405.40,36411.70,126.949,1651815119999,4622792.31840,1016,44.411,1617315.79930,0 +1651815120000,36411.70,36442.00,36411.60,36442.00,62.503,1651815179999,2276758.83700,831,40.880,1489200.55880,0 +1651815180000,36442.00,36454.30,36434.50,36443.10,51.247,1651815239999,1867836.37300,923,13.700,499321.11520,0 +1651815240000,36443.10,36450.00,36420.20,36422.40,71.741,1651815299999,2613947.52480,830,22.497,819692.96170,0 +1651815300000,36422.80,36448.50,36422.70,36448.40,48.048,1651815359999,1750471.35200,803,30.195,1100040.62890,0 +1651815360000,36448.50,36453.70,36444.10,36447.20,68.171,1651815419999,2484854.58820,662,44.462,1620647.38910,0 +1651815420000,36447.20,36458.10,36438.20,36450.00,48.299,1651815479999,1760555.01890,830,26.588,969174.19620,0 +1651815480000,36450.10,36475.40,36450.00,36470.70,59.778,1651815539999,2179660.71710,908,43.152,1573438.84760,0 +1651815540000,36470.70,36477.50,36470.60,36470.60,82.202,1651815599999,2998314.74680,793,57.639,2102391.90280,0 +1651815600000,36470.60,36471.70,36454.70,36461.70,71.879,1651815659999,2621079.06300,839,44.301,1615539.32520,0 +1651815660000,36461.60,36471.60,36454.80,36466.00,56.182,1651815719999,2048625.24120,760,27.478,1001948.51830,0 +1651815720000,36465.80,36471.60,36462.20,36465.80,18.810,1651815779999,685938.79730,452,6.169,224963.83670,0 +1651815780000,36465.80,36465.90,36457.90,36462.80,46.733,1651815839999,1703964.12650,518,8.038,293079.56540,0 +1651815840000,36461.00,36468.80,36453.30,36453.40,73.370,1651815899999,2675169.53830,744,37.510,1367687.73840,0 +1651815900000,36453.40,36456.20,36448.00,36449.90,62.807,1651815959999,2289447.66500,741,25.804,940613.88050,0 +1651815960000,36450.00,36450.00,36439.20,36444.70,51.960,1651816019999,1893662.63070,680,20.048,730647.99480,0 +1651816020000,36444.80,36450.00,36441.00,36448.80,26.267,1651816079999,957306.23640,559,11.595,422585.73500,0 +1651816080000,36448.70,36475.00,36446.60,36475.00,69.010,1651816139999,2515735.80140,675,55.030,2006113.13700,0 +1651816140000,36475.00,36475.00,36456.80,36456.80,41.412,1651816199999,1510256.68790,648,14.219,518547.12770,0 +1651816200000,36456.90,36473.10,36456.90,36467.10,94.904,1651816259999,3460881.41200,749,42.112,1535618.15240,0 +1651816260000,36467.10,36494.90,36466.70,36484.30,255.906,1651816319999,9336355.23024,1460,221.080,8065805.61764,0 +1651816320000,36484.30,36484.30,36463.00,36463.00,76.934,1651816379999,2805894.13340,756,19.075,695718.22880,0 +1651816380000,36463.10,36463.10,36441.70,36441.70,45.404,1651816439999,1655079.23770,630,13.692,499161.82740,0 +1651816440000,36441.70,36460.40,36440.00,36449.90,118.224,1651816499999,4309458.10140,1144,54.821,1998315.67900,0 +1651816500000,36449.90,36456.30,36448.00,36449.60,29.345,1651816559999,1069694.42030,559,16.827,613369.78040,0 +1651816560000,36449.50,36455.20,36428.80,36451.60,89.257,1651816619999,3252715.70750,1025,41.181,1500701.24810,0 +1651816620000,36451.60,36483.10,36451.60,36479.40,55.551,1651816679999,2026059.97150,784,33.376,1217288.99870,0 +1651816680000,36479.30,36485.20,36474.50,36478.50,40.260,1651816739999,1468771.78780,623,23.128,843772.58460,0 +1651816740000,36479.60,36485.00,36477.20,36482.60,42.394,1651816799999,1546634.00170,591,18.779,685087.18710,0 +1651816800000,36482.60,36492.00,36482.50,36487.80,109.958,1651816859999,4012141.93390,1130,39.136,1427998.68830,0 +1651816860000,36487.80,36487.80,36471.20,36474.90,76.023,1651816919999,2773269.89990,826,17.752,647577.13530,0 +1651816920000,36475.00,36482.70,36466.60,36471.40,47.349,1651816979999,1727109.22690,704,18.286,667002.14340,0 +1651816980000,36471.30,36486.70,36471.30,36477.30,34.865,1651817039999,1271840.35040,644,22.920,836116.41380,0 +1651817040000,36478.10,36513.40,36478.10,36511.40,244.331,1651817099999,8918159.70348,2383,194.088,7084180.54658,0 +1651817100000,36511.40,36521.40,36504.20,36519.30,175.223,1651817159999,6397847.78325,1799,69.071,2522050.67495,0 +1651817160000,36519.30,36532.60,36505.60,36522.20,186.082,1651817219999,6795479.80224,1880,130.784,4776300.74514,0 +1651817220000,36522.20,36535.90,36516.20,36520.50,121.092,1651817279999,4422960.51111,1570,71.578,2614468.49791,0 +1651817280000,36520.50,36520.60,36475.30,36477.50,124.372,1651817339999,4539187.51100,1574,30.316,1106424.95210,0 +1651817340000,36477.60,36482.20,36456.60,36480.00,113.117,1651817399999,4125249.48050,1427,40.488,1476457.08610,0 +1651817400000,36480.00,36498.70,36479.90,36488.60,67.462,1651817459999,2461663.77590,965,34.696,1266032.29170,0 +1651817460000,36488.60,36492.70,36475.50,36477.40,47.751,1651817519999,1742166.07110,811,14.407,525631.40100,0 +1651817520000,36477.30,36482.00,36450.00,36451.50,277.480,1651817579999,10119539.71570,1677,43.665,1592039.50580,0 +1651817580000,36451.50,36458.60,36442.10,36456.70,112.631,1651817639999,4105277.38660,966,38.378,1398881.57180,0 +1651817640000,36456.70,36468.70,36449.70,36449.70,93.964,1651817699999,3425757.84230,930,48.351,1762935.73100,0 +1651817700000,36449.60,36449.60,36425.90,36432.40,147.076,1651817759999,5358863.09990,1698,47.453,1729014.90430,0 +1651817760000,36432.40,36436.70,36419.50,36420.60,77.035,1651817819999,2806352.88620,1157,20.662,752684.49350,0 +1651817820000,36420.50,36424.70,36400.00,36416.90,152.411,1651817879999,5549722.13910,1689,51.331,1869081.04330,0 +1651817880000,36416.80,36424.20,36409.10,36413.40,78.520,1651817939999,2859471.17280,1053,45.182,1645441.61250,0 +1651817940000,36413.40,36433.00,36413.30,36427.90,72.954,1651817999999,2657400.56310,697,62.209,2266032.17260,0 +1651818000000,36427.90,36434.90,36418.40,36434.20,95.445,1651818059999,3476752.86960,843,49.863,1816422.44190,0 +1651818060000,36434.20,36435.60,36426.00,36435.50,38.842,1651818119999,1415030.50000,535,13.869,505258.13200,0 +1651818120000,36435.50,36462.90,36432.80,36456.80,99.986,1651818179999,3644106.00760,910,82.174,2994876.84140,0 +1651818180000,36456.80,36471.80,36437.50,36440.90,102.304,1651818239999,3729731.14770,1223,58.275,2124660.39620,0 +1651818240000,36440.90,36462.00,36440.90,36458.40,95.695,1651818299999,3488091.58040,844,48.681,1774554.17940,0 +1651818300000,36458.40,36459.10,36424.50,36433.40,94.363,1651818359999,3439003.08620,1082,30.939,1127527.00220,0 +1651818360000,36433.40,36434.80,36423.00,36428.50,57.920,1651818419999,2110053.00690,616,28.507,1038554.79120,0 +1651818420000,36428.50,36435.70,36415.00,36419.60,53.386,1651818479999,1944471.03970,706,15.152,551951.50060,0 +1651818480000,36419.70,36419.80,36413.00,36419.70,47.737,1651818539999,1738470.44010,548,19.295,702689.76670,0 +1651818540000,36419.80,36419.80,36383.60,36397.00,174.323,1651818599999,6345358.50230,1847,46.741,1701258.64440,0 +1651818600000,36397.00,36410.40,36380.70,36409.30,92.554,1651818659999,3368434.43450,1065,33.214,1208955.22790,0 +1651818660000,36409.40,36410.00,36401.20,36403.90,48.695,1651818719999,1772724.48910,669,19.358,704719.32590,0 +1651818720000,36403.90,36417.80,36403.70,36403.70,51.045,1651818779999,1858637.82920,586,13.863,504737.72980,0 +1651818780000,36403.80,36418.40,36403.80,36407.50,41.737,1651818839999,1519709.87810,506,24.239,882594.11160,0 +1651818840000,36407.50,36419.40,36407.40,36419.40,37.957,1651818899999,1382089.44680,450,17.845,649800.42460,0 +1651818900000,36419.30,36420.80,36412.30,36412.60,60.744,1651818959999,2212219.30810,508,39.997,1456637.01760,0 +1651818960000,36412.50,36412.60,36395.60,36411.50,74.209,1651819019999,2701329.95190,922,39.940,1453823.03700,0 +1651819020000,36411.50,36445.00,36411.50,36438.50,63.389,1651819079999,2309589.57200,977,40.637,1480649.55340,0 +1651819080000,36438.50,36442.10,36425.20,36438.90,64.816,1651819139999,2361616.91520,616,20.380,742594.88030,0 +1651819140000,36438.90,36450.00,36436.20,36440.10,55.252,1651819199999,2013663.71570,647,42.732,1557372.36280,0 +1651819200000,36440.10,36451.40,36440.00,36447.10,78.188,1651819259999,2849757.36230,636,68.906,2511470.97690,0 +1651819260000,36447.10,36449.30,36442.10,36449.30,20.940,1651819319999,763160.16470,307,10.498,382599.08220,0 +1651819320000,36449.20,36449.30,36400.00,36400.10,129.207,1651819379999,4707182.88320,862,10.855,395375.42110,0 +1651819380000,36400.10,36422.20,36400.00,36418.00,47.893,1651819439999,1743930.01330,697,26.885,978868.71800,0 +1651819440000,36418.00,36426.00,36418.00,36419.70,16.077,1651819499999,585558.80680,308,7.082,257933.24640,0 +1651819500000,36419.70,36426.40,36419.70,36424.20,24.714,1651819559999,900168.45590,374,14.500,528143.98570,0 +1651819560000,36424.10,36426.30,36417.30,36426.30,77.500,1651819619999,2822571.08960,487,38.872,1415738.80680,0 +1651819620000,36426.30,36427.70,36422.60,36425.70,23.325,1651819679999,849654.77980,366,6.154,224172.93160,0 +1651819680000,36426.70,36430.90,36416.60,36430.10,28.786,1651819739999,1048544.59320,555,16.276,592862.67480,0 +1651819740000,36430.10,36430.10,36400.00,36400.10,39.271,1651819799999,1430041.07850,535,12.963,472069.55540,0 +1651819800000,36400.00,36415.30,36400.00,36400.10,61.257,1651819859999,2230008.28550,772,30.279,1102295.94140,0 +1651819860000,36400.10,36400.90,36389.80,36397.80,80.261,1651819919999,2921021.83820,706,44.955,1636005.75360,0 +1651819920000,36397.70,36398.10,36390.70,36398.00,42.486,1651819979999,1546254.28250,558,15.066,548309.12850,0 +1651819980000,36398.00,36398.10,36390.10,36390.10,41.764,1651820039999,1520005.94580,527,17.791,647487.00540,0 +1651820040000,36390.20,36395.90,36369.50,36383.60,147.852,1651820099999,5378849.53440,1306,39.287,1429241.10410,0 +1651820100000,36383.50,36398.00,36383.50,36395.60,68.579,1651820159999,2495757.57640,792,38.057,1384949.60540,0 +1651820160000,36395.60,36398.90,36390.70,36398.80,87.312,1651820219999,3177891.79790,577,51.822,1886139.07490,0 +1651820220000,36398.80,36398.80,36383.00,36391.70,33.112,1651820279999,1204926.13320,591,15.581,566946.77570,0 +1651820280000,36391.70,36406.20,36390.70,36392.10,165.135,1651820339999,6010725.70360,991,129.095,4699052.70940,0 +1651820340000,36392.90,36398.30,36387.00,36397.80,40.673,1651820399999,1480269.82290,620,18.357,668097.45430,0 +1651820400000,36397.80,36407.30,36359.90,36380.90,367.645,1651820459999,13375096.72710,2317,92.444,3363694.65380,0 +1651820460000,36380.90,36383.00,36349.00,36363.00,219.689,1651820519999,7988653.71525,2040,78.967,2871571.40510,0 +1651820520000,36362.90,36371.30,36335.30,36371.20,265.619,1651820579999,9655222.01296,2501,100.681,3659953.46060,0 +1651820580000,36371.30,36387.60,36371.20,36378.50,82.900,1651820639999,3015653.79690,979,45.767,1664851.65710,0 +1651820640000,36378.40,36393.20,36378.40,36388.00,102.673,1651820699999,3735806.35480,1061,71.135,2588300.55700,0 +1651820700000,36387.90,36405.10,36371.00,36371.10,78.619,1651820759999,2860992.31320,1183,38.404,1397648.60340,0 +1651820760000,36371.10,36382.10,36351.40,36371.70,124.390,1651820819999,4523523.92620,1310,60.059,2183950.69730,0 +1651820820000,36371.80,36393.90,36371.70,36386.30,87.691,1651820879999,3190654.72070,1029,34.866,1268525.40520,0 +1651820880000,36386.30,36406.20,36380.00,36383.40,77.261,1651820939999,2811629.87050,960,47.023,1711233.31660,0 +1651820940000,36383.30,36392.60,36383.30,36388.10,17.056,1651820999999,620681.76260,440,8.303,302149.91040,0 +1651821000000,36388.10,36388.10,36369.60,36376.50,62.569,1651821059999,2276125.66900,764,26.864,977272.44860,0 +1651821060000,36376.40,36384.60,36361.20,36371.20,142.316,1651821119999,5176089.30010,966,23.345,849139.71860,0 +1651821120000,36371.20,36390.00,36364.10,36386.00,82.949,1651821179999,3017510.58870,867,37.663,1370155.08150,0 +1651821180000,36386.10,36400.00,36386.00,36389.50,59.065,1651821239999,2149724.86010,629,38.608,1405144.42840,0 +1651821240000,36389.50,36398.40,36378.90,36398.40,54.171,1651821299999,1971129.41050,678,33.962,1235788.29110,0 +1651821300000,36398.70,36404.10,36389.70,36404.10,91.057,1651821359999,3314173.69930,1037,63.668,2317239.73460,0 +1651821360000,36404.10,36425.20,36402.40,36417.80,102.215,1651821419999,3722458.16780,1417,73.615,2680875.69550,0 +1651821420000,36417.80,36423.30,36411.80,36416.10,57.568,1651821479999,2096547.09280,643,34.984,1274101.03900,0 +1651821480000,36416.10,36416.10,36401.90,36405.30,32.315,1651821539999,1176463.69570,510,15.563,566567.89310,0 +1651821540000,36405.20,36428.10,36405.20,36428.10,48.716,1651821599999,1774201.07120,754,34.444,1254397.21170,0 +1651821600000,36428.00,36437.00,36411.60,36411.70,99.723,1651821659999,3632791.59880,1177,60.910,2219016.89150,0 +1651821660000,36411.70,36411.70,36394.10,36400.70,89.131,1651821719999,3244716.47850,834,30.947,1126607.46830,0 +1651821720000,36400.80,36400.80,36388.00,36388.10,59.337,1651821779999,2159521.88430,612,23.293,847760.13050,0 +1651821780000,36388.00,36390.00,36371.00,36371.00,75.130,1651821839999,2733245.93090,1004,32.624,1186887.23270,0 +1651821840000,36371.00,36389.90,36369.40,36369.40,64.567,1651821899999,2348877.51690,815,23.064,838986.87060,0 +1651821900000,36369.40,36389.00,36360.20,36382.30,81.234,1651821959999,2954643.92350,1141,46.117,1677469.72260,0 +1651821960000,36382.30,36415.60,36379.50,36394.30,99.897,1651822019999,3636226.97130,989,65.431,2381614.01140,0 +1651822020000,36394.40,36401.50,36360.00,36369.10,72.751,1651822079999,2646329.07430,965,26.783,974238.86670,0 +1651822080000,36369.00,36370.90,36339.90,36353.30,126.135,1651822139999,4585140.79050,1313,49.421,1796479.91060,0 +1651822140000,36353.40,36366.80,36340.10,36352.70,140.090,1651822199999,5092382.68660,1169,54.947,1997455.52390,0 +1651822200000,36352.70,36352.80,36323.00,36324.60,158.354,1651822259999,5754219.11390,1842,38.250,1390039.33320,0 +1651822260000,36324.70,36349.40,36320.00,36346.80,131.283,1651822319999,4770157.51640,1512,58.892,2140101.17520,0 +1651822320000,36346.80,36364.80,36341.90,36364.60,83.096,1651822379999,3020605.00130,1046,60.850,2211933.15430,0 +1651822380000,36364.70,36364.70,36338.10,36347.10,160.494,1651822439999,5833569.06490,1332,61.756,2244688.54620,0 +1651822440000,36347.10,36347.50,36332.60,36334.40,120.655,1651822499999,4384624.30160,1254,29.593,1075424.27660,0 +1651822500000,36334.40,36346.20,36228.90,36234.50,2103.637,1651822559999,76314497.55144,9345,649.269,23547996.15360,0 +1651822560000,36234.50,36255.30,36133.00,36169.20,1623.453,1651822619999,58759047.15661,13000,601.161,21761902.02910,0 +1651822620000,36169.20,36237.30,36150.30,36205.60,675.534,1651822679999,24455460.79820,6125,361.672,13093667.85370,0 +1651822680000,36205.50,36229.50,36161.10,36167.30,361.998,1651822739999,13105317.60200,3660,136.562,4945144.84250,0 +1651822740000,36167.20,36172.00,35900.00,36055.00,3027.017,1651822799999,109086971.02914,22607,1006.876,36285014.32849,0 +1651822800000,36055.00,36066.10,35860.00,35958.10,2570.629,1651822859999,92394978.18656,20124,1070.068,38465177.44761,0 +1651822860000,35958.10,35972.40,35800.00,35877.90,1836.788,1651822919999,65877678.45485,15830,691.052,24792907.07060,0 +1651822920000,35877.90,35944.90,35861.50,35899.70,1078.876,1651822979999,38738264.08420,8584,712.183,25573926.13090,0 +1651822980000,35899.60,35950.00,35873.90,35885.80,774.734,1651823039999,27822748.34300,6704,389.319,13983291.16150,0 +1651823040000,35885.90,35932.60,35881.20,35897.90,533.327,1651823099999,19149686.15780,4809,272.193,9773746.59210,0 +1651823100000,35897.60,35915.80,35826.30,35867.50,1013.349,1651823159999,36352595.22010,7440,401.929,14423900.79720,0 +1651823160000,35867.60,35919.40,35828.80,35848.50,634.748,1651823219999,22771155.74810,5511,280.024,10047855.96520,0 +1651823220000,35848.50,35874.50,35828.10,35871.30,579.391,1651823279999,20774212.73640,6049,323.850,11612251.13410,0 +1651823280000,35871.30,35929.80,35871.20,35917.80,1166.661,1651823339999,41881859.96920,9617,698.101,25061615.50240,0 +1651823340000,35917.80,36125.00,35911.00,36079.80,2467.453,1651823399999,88934679.70420,16016,1751.127,63104342.89760,0 +1651823400000,36080.10,36251.40,36074.50,36210.10,1534.121,1651823459999,55470660.82428,11945,1084.816,39229889.35058,0 +1651823460000,36210.00,36235.40,36133.10,36173.70,846.715,1651823519999,30630550.97570,7387,322.078,11650841.92300,0 +1651823520000,36173.80,36173.80,36108.00,36160.90,656.366,1651823579999,23723249.50360,5979,319.879,11560705.51220,0 +1651823580000,36160.80,36344.10,36157.50,36337.10,1401.948,1651823639999,50839946.76349,11019,1011.196,36673023.57399,0 +1651823640000,36337.20,36422.40,36305.00,36327.70,1497.522,1651823699999,54437306.78026,12400,739.919,26903043.43226,0 +1651823700000,36327.70,36432.90,36320.30,36386.80,1162.203,1651823759999,42292118.85640,8799,699.186,25445210.10770,0 +1651823760000,36385.40,36431.80,36359.50,36369.30,605.644,1651823819999,22044384.17750,5952,320.534,11669189.64890,0 +1651823820000,36369.30,36419.30,36369.10,36398.70,446.891,1651823879999,16263386.71890,4478,263.015,9571871.45820,0 +1651823880000,36401.00,36414.30,36369.10,36390.80,368.331,1651823939999,13405200.56570,3790,153.873,5600205.90980,0 +1651823940000,36390.80,36390.80,36359.20,36359.30,311.452,1651823999999,11327560.77630,3230,120.592,4385961.78680,0 +1651824000000,36359.30,36362.60,36216.30,36264.90,1473.299,1651824059999,53470087.55005,10944,505.685,18354662.06410,0 +1651824060000,36264.90,36289.60,36185.90,36256.30,873.351,1651824119999,31647224.08622,7402,368.866,13369445.60360,0 +1651824120000,36256.20,36264.50,36151.10,36183.70,718.686,1651824179999,26010941.00068,6096,322.058,11655471.64940,0 +1651824180000,36183.70,36229.90,36148.20,36229.80,555.653,1651824239999,20102363.32090,5611,314.554,11380787.21240,0 +1651824240000,36229.90,36276.00,36195.60,36211.90,422.981,1651824299999,15327248.28486,4808,261.023,9459833.73546,0 +1651824300000,36212.00,36220.40,36185.60,36204.60,200.826,1651824359999,7270355.85240,2856,102.004,3692821.19280,0 +1651824360000,36204.70,36324.60,36204.60,36314.10,559.344,1651824419999,20295574.22179,5258,392.043,14224426.16719,0 +1651824420000,36314.10,36510.80,36314.10,36464.90,1937.687,1651824479999,70602220.70936,14301,1470.131,53565274.67456,0 +1651824480000,36464.30,36468.10,36376.50,36382.70,638.506,1651824539999,23252633.31680,6216,200.515,7303715.46530,0 +1651824540000,36382.70,36398.90,36325.30,36381.50,464.080,1651824599999,16876843.03691,4977,210.655,7661667.49590,0 +1651824600000,36381.40,36403.30,36354.50,36355.30,238.206,1651824659999,8665465.98040,2595,73.900,2688376.87040,0 +1651824660000,36355.40,36398.10,36350.00,36379.90,150.977,1651824719999,5491962.98430,2314,68.060,2475922.49700,0 +1651824720000,36380.00,36386.90,36332.60,36333.00,230.429,1651824779999,8379483.10310,2436,84.227,3063422.47900,0 +1651824780000,36333.00,36333.30,36230.40,36245.10,541.968,1651824839999,19662717.90510,5333,166.199,6030917.18470,0 +1651824840000,36244.90,36288.60,36240.40,36243.50,463.046,1651824899999,16791038.44840,3839,238.881,8663316.22930,0 +1651824900000,36243.60,36285.00,36242.10,36244.40,274.113,1651824959999,9939398.75350,3248,145.344,5270256.50790,0 +1651824960000,36244.50,36244.50,36196.60,36217.10,652.455,1651825019999,23628957.74278,5187,235.165,8515788.36950,0 +1651825020000,36217.20,36240.00,36201.10,36225.20,266.301,1651825079999,9645314.35800,2706,103.677,3755716.55460,0 +1651825080000,36225.20,36239.80,36171.20,36234.10,312.447,1651825139999,11310114.93665,3916,115.721,4189778.68770,0 +1651825140000,36234.20,36359.20,36222.20,36273.80,700.434,1651825199999,25426971.06025,6386,440.073,15974469.00945,0 +1651825200000,36273.90,36320.00,36226.40,36239.90,285.626,1651825259999,10361497.44106,3376,157.614,5718364.61090,0 +1651825260000,36240.00,36264.00,36213.50,36255.70,174.352,1651825319999,6318187.49900,2561,72.647,2632771.83390,0 +1651825320000,36255.80,36305.40,36255.80,36281.70,173.308,1651825379999,6287370.39030,2155,108.766,3945999.21170,0 +1651825380000,36281.80,36327.10,36281.70,36307.10,189.336,1651825439999,6874597.95290,2112,147.156,5343006.74450,0 +1651825440000,36307.10,36319.30,36278.30,36305.50,360.872,1651825499999,13098210.78630,3080,106.344,3860139.48110,0 +1651825500000,36305.50,36339.30,36305.40,36329.50,173.068,1651825559999,6286661.82320,2071,122.857,4462788.98450,0 +1651825560000,36329.50,36345.60,36307.10,36310.10,165.968,1651825619999,6028860.32460,1984,84.517,3070360.25280,0 +1651825620000,36310.10,36312.60,36265.50,36269.50,215.346,1651825679999,7813385.51650,2113,74.454,2701055.37820,0 +1651825680000,36269.60,36302.20,36265.00,36296.70,125.634,1651825739999,4558112.60820,1738,57.243,2076905.87420,0 +1651825740000,36296.70,36308.60,36278.50,36289.40,132.509,1651825799999,4809658.69470,1631,76.957,2793407.00420,0 +1651825800000,36288.40,36329.90,36281.30,36315.90,115.973,1651825859999,4210839.90830,1645,69.323,2517087.99450,0 +1651825860000,36315.90,36320.40,36286.10,36295.80,76.330,1651825919999,2770691.35040,1348,33.023,1198803.75010,0 +1651825920000,36295.90,36378.40,36295.90,36360.00,369.807,1651825979999,13443611.68795,3763,291.854,10609744.34755,0 +1651825980000,36360.00,36398.50,36342.50,36350.60,265.792,1651826039999,9666166.16030,3215,143.030,5202152.15660,0 +1651826040000,36350.60,36366.50,36327.30,36338.70,88.004,1651826099999,3198336.11450,1530,41.612,1512355.14400,0 +1651826100000,36338.60,36353.50,36323.40,36335.10,131.189,1651826159999,4766830.56560,1631,40.915,1486657.75220,0 +1651826160000,36335.10,36350.30,36325.60,36328.10,85.539,1651826219999,3107940.46600,1178,43.566,1582900.20290,0 +1651826220000,36329.70,36334.80,36279.00,36284.70,310.810,1651826279999,11283228.04410,2106,162.628,5903620.29180,0 +1651826280000,36284.80,36298.80,36266.10,36274.10,139.971,1651826339999,5078503.31900,1685,44.431,1612110.15750,0 +1651826340000,36274.00,36285.50,36244.00,36259.90,189.214,1651826399999,6860977.93596,2099,65.712,2383018.59320,0 +1651826400000,36259.80,36273.20,36208.20,36216.50,356.661,1651826459999,12925188.53610,3347,102.335,3708855.67450,0 +1651826460000,36216.60,36221.80,36200.00,36221.80,206.648,1651826519999,7482462.00630,2314,86.060,3116303.68910,0 +1651826520000,36221.80,36260.20,36220.00,36231.90,153.925,1651826579999,5578078.38570,2039,100.307,3635034.14660,0 +1651826580000,36232.00,36232.00,36182.00,36214.10,319.666,1651826639999,11573240.94438,2848,151.701,5492010.10080,0 +1651826640000,36214.00,36244.10,36202.20,36213.70,138.131,1651826699999,5004002.34030,1646,85.152,3084785.10090,0 +1651826700000,36213.70,36215.00,36168.40,36184.30,344.912,1651826759999,12483089.74451,2928,117.095,4237354.75650,0 +1651826760000,36184.40,36211.90,36168.00,36197.70,350.276,1651826819999,12676260.21741,3229,234.106,8472026.07720,0 +1651826820000,36197.70,36262.70,36193.30,36249.20,263.503,1651826879999,9547405.43570,3087,165.670,6002691.77360,0 +1651826880000,36249.20,36249.20,36202.30,36241.10,105.492,1651826939999,3821312.94920,1659,54.839,1986181.85010,0 +1651826940000,36241.10,36251.80,36215.20,36231.70,90.486,1651826999999,3278511.80600,1604,37.717,1366600.88390,0 +1651827000000,36231.80,36246.70,36209.80,36246.60,99.894,1651827059999,3618998.41890,1536,40.771,1476996.84350,0 +1651827060000,36247.40,36249.90,36224.50,36224.60,167.523,1651827119999,6070522.90040,1696,55.191,1999998.38870,0 +1651827120000,36224.50,36290.40,36212.60,36283.60,185.669,1651827179999,6732230.57410,2439,116.512,4225051.30370,0 +1651827180000,36283.70,36284.00,36256.20,36264.30,139.461,1651827239999,5058396.68610,1458,58.636,2126798.60240,0 +1651827240000,36264.30,36264.40,36185.90,36193.00,279.093,1651827299999,10106268.90620,2436,38.766,1403546.31010,0 +1651827300000,36192.90,36217.00,36185.90,36202.20,182.199,1651827359999,6595846.56600,2209,79.830,2889882.16170,0 +1651827360000,36202.10,36231.80,36194.00,36231.80,100.647,1651827419999,3644585.27990,1402,45.543,1649266.67280,0 +1651827420000,36231.80,36251.70,36231.80,36249.10,74.778,1651827479999,2710218.98490,1172,39.038,1414881.78400,0 +1651827480000,36249.10,36249.10,36198.10,36206.40,127.458,1651827539999,4616532.91360,1695,46.192,1673235.67040,0 +1651827540000,36206.30,36220.00,36191.50,36197.50,153.547,1651827599999,5558763.40240,1633,53.076,1921650.29110,0 +1651827600000,36197.50,36229.90,36191.90,36217.50,106.162,1651827659999,3844328.93080,1512,56.280,2037972.84280,0 +1651827660000,36217.50,36221.00,36200.00,36200.70,97.920,1651827719999,3545876.04890,1026,25.993,941194.99660,0 +1651827720000,36200.80,36216.70,36193.10,36201.10,102.260,1651827779999,3702286.74820,1236,55.631,2014134.94030,0 +1651827780000,36201.00,36239.40,36201.00,36231.50,77.063,1651827839999,2791983.45620,1199,49.679,1799869.31850,0 +1651827840000,36231.60,36248.00,36231.50,36248.00,62.705,1651827899999,2272532.48820,997,43.355,1571256.48770,0 +1651827900000,36247.90,36248.00,36223.10,36241.40,85.979,1651827959999,3115749.98640,1235,33.102,1199613.00910,0 +1651827960000,36241.30,36242.60,36226.60,36238.80,91.678,1651828019999,3322027.50920,1103,19.475,705734.89920,0 +1651828020000,36238.80,36244.50,36205.20,36205.90,126.508,1651828079999,4583079.05300,1225,24.098,873150.40880,0 +1651828080000,36205.80,36205.90,36165.80,36171.00,236.425,1651828139999,8553834.96690,2841,112.627,4074519.51610,0 +1651828140000,36171.10,36208.30,36166.00,36199.10,154.105,1651828199999,5577061.36530,1946,102.729,3717928.14630,0 +1651828200000,36199.10,36228.50,36199.10,36216.70,174.074,1651828259999,6303998.96700,1787,87.397,3165029.22900,0 +1651828260000,36216.70,36225.20,36203.60,36203.90,50.527,1651828319999,1829872.14030,906,14.701,532399.93570,0 +1651828320000,36204.00,36209.90,36188.00,36192.00,87.932,1651828379999,3182967.67570,1409,48.393,1751718.24340,0 +1651828380000,36191.90,36197.20,36171.30,36176.00,108.083,1651828439999,3910628.84760,1547,48.478,1754028.69440,0 +1651828440000,36176.00,36207.20,36175.90,36205.00,127.999,1651828499999,4632988.72050,1618,85.132,3081302.22320,0 +1651828500000,36204.90,36210.00,36196.70,36201.20,128.108,1651828559999,4638076.04080,1310,83.700,3030362.91920,0 +1651828560000,36200.40,36238.00,36196.10,36196.10,114.742,1651828619999,4156614.01420,1491,54.415,1971327.27860,0 +1651828620000,36196.50,36196.50,36150.90,36168.50,311.834,1651828679999,11277490.93977,3275,117.352,4243928.97100,0 +1651828680000,36168.40,36179.90,36151.40,36169.40,137.040,1651828739999,4956056.41340,1682,58.966,2132519.46570,0 +1651828740000,36169.50,36215.00,36169.40,36210.00,154.096,1651828799999,5576847.42990,1612,89.386,3235007.26650,0 +1651828800000,36209.90,36267.30,36203.80,36256.70,402.644,1651828859999,14593357.56736,3465,307.584,11148057.91196,0 +1651828860000,36256.70,36256.70,36241.30,36244.00,160.826,1651828919999,5829927.90040,1611,80.912,2933078.01210,0 +1651828920000,36244.00,36246.00,36222.00,36245.90,91.071,1651828979999,3299603.74670,1142,31.589,1144606.44910,0 +1651828980000,36245.90,36262.50,36238.60,36241.20,87.775,1651829039999,3181869.82900,1204,50.765,1840322.78280,0 +1651829040000,36241.20,36264.50,36241.10,36256.80,83.793,1651829099999,3038047.27460,1150,46.260,1677261.24480,0 +1651829100000,36256.90,36315.50,36256.80,36294.20,328.581,1651829159999,11925050.12169,3736,260.773,9463876.95159,0 +1651829160000,36294.30,36321.90,36294.20,36308.90,367.719,1651829219999,13350856.16170,3046,219.023,7952020.44410,0 +1651829220000,36308.90,36315.00,36300.00,36300.00,268.837,1651829279999,9759361.33240,1135,31.271,1135269.75760,0 +1651829280000,36300.10,36325.00,36276.40,36314.30,517.473,1651829339999,18783858.17420,2271,106.428,3863374.24840,0 +1651829340000,36314.20,36314.30,36286.70,36298.80,82.900,1651829399999,3009008.41400,1184,29.928,1086226.95770,0 +1651829400000,36298.70,36311.70,36285.40,36307.00,71.380,1651829459999,2591195.64440,1219,38.633,1402397.22720,0 +1651829460000,36307.10,36329.00,36305.60,36323.90,122.610,1651829519999,4453249.42850,1452,92.638,3364677.03800,0 +1651829520000,36323.90,36346.00,36317.10,36337.10,174.219,1651829579999,6329959.66286,2116,116.182,4221263.94886,0 +1651829580000,36337.00,36349.40,36336.00,36336.00,125.878,1651829639999,4574856.65530,1740,77.224,2806595.36840,0 +1651829640000,36336.10,36342.40,36326.80,36329.90,99.938,1651829699999,3631217.88610,1262,26.310,956029.76070,0 +1651829700000,36329.60,36356.00,36329.50,36345.10,306.545,1651829759999,11141886.47955,2311,198.349,7209324.43045,0 +1651829760000,36345.20,36360.00,36334.50,36334.50,90.806,1651829819999,3300393.56290,1416,37.709,1370673.68800,0 +1651829820000,36334.50,36358.70,36334.50,36358.60,94.819,1651829879999,3446108.79820,1106,64.898,2358711.53750,0 +1651829880000,36358.70,36391.20,36348.00,36381.30,244.249,1651829939999,8884405.59030,2591,160.626,5842917.13100,0 +1651829940000,36381.30,36400.00,36367.60,36381.40,364.252,1651829999999,13253865.88854,2084,261.319,9508821.26834,0 +1651830000000,36381.40,36416.90,36370.00,36370.00,280.455,1651830059999,10206943.71532,2717,150.929,5493722.79502,0 +1651830060000,36370.00,36370.00,36337.00,36355.50,249.851,1651830119999,9083003.88540,2613,90.197,3278939.99110,0 +1651830120000,36355.50,36357.10,36334.60,36343.90,145.860,1651830179999,5301152.83890,1390,54.476,1979910.45420,0 +1651830180000,36343.80,36346.40,36310.40,36319.20,191.601,1651830239999,6959960.52920,2130,69.260,2515853.11870,0 +1651830240000,36319.20,36339.80,36319.20,36339.80,88.589,1651830299999,3218378.44350,1122,50.222,1824497.46510,0 +1651830300000,36339.80,36353.50,36319.80,36349.90,201.370,1651830359999,7316003.55850,1550,126.073,4580410.36820,0 +1651830360000,36350.00,36363.30,36347.90,36363.10,126.280,1651830419999,4590869.77590,1360,88.939,3233336.44560,0 +1651830420000,36363.10,36365.90,36338.00,36341.90,91.895,1651830479999,3340526.50330,976,44.261,1608911.72420,0 +1651830480000,36341.90,36364.60,36341.80,36358.30,103.947,1651830539999,3779075.07620,997,55.255,2008784.87960,0 +1651830540000,36358.40,36365.30,36350.00,36350.80,85.689,1651830599999,3115460.78850,837,49.667,1805811.62780,0 +1651830600000,36350.80,36362.30,36348.10,36353.20,52.836,1651830659999,1920819.69150,700,24.590,893931.46300,0 +1651830660000,36352.60,36358.90,36349.50,36350.80,58.551,1651830719999,2128557.98210,711,30.404,1105271.80250,0 +1651830720000,36350.70,36352.50,36320.00,36342.40,161.355,1651830779999,5862770.15750,1496,72.804,2645073.88050,0 +1651830780000,36342.40,36343.60,36330.60,36342.30,56.077,1651830839999,2037705.87200,805,28.182,1024036.23880,0 +1651830840000,36342.30,36362.40,36336.20,36356.10,66.852,1651830899999,2430017.91330,1081,32.995,1199340.15140,0 +1651830900000,36356.00,36356.10,36338.90,36339.00,81.075,1651830959999,2946830.81450,1034,47.189,1715228.03320,0 +1651830960000,36339.00,36358.30,36338.90,36348.00,92.678,1651831019999,3368672.76580,923,38.947,1415658.41380,0 +1651831020000,36348.00,36369.50,36345.80,36369.40,159.134,1651831079999,5785250.56890,1257,136.114,4948435.79390,0 +1651831080000,36369.40,36388.60,36369.40,36381.90,171.413,1651831139999,6236248.52900,1394,113.525,4130087.46160,0 +1651831140000,36381.90,36389.80,36375.40,36382.40,69.494,1651831199999,2528339.25960,770,45.448,1653514.29370,0 +1651831200000,36382.40,36404.40,36371.80,36397.90,172.352,1651831259999,6271569.48340,1914,91.097,3315019.89390,0 +1651831260000,36397.80,36400.00,36335.60,36335.70,134.476,1651831319999,4891109.83540,1729,38.825,1412513.11900,0 +1651831320000,36335.60,36339.40,36310.00,36333.70,416.395,1651831379999,15126047.75700,2716,122.956,4466927.48340,0 +1651831380000,36333.70,36348.10,36327.10,36329.10,66.512,1651831439999,2416686.55590,954,34.346,1247933.66620,0 +1651831440000,36329.00,36335.90,36300.20,36312.00,153.835,1651831499999,5586546.92120,1479,32.840,1192615.29220,0 +1651831500000,36311.90,36321.60,36297.10,36299.80,151.127,1651831559999,5486857.72690,1755,65.646,2383381.65660,0 +1651831560000,36299.80,36303.90,36262.50,36294.40,577.105,1651831619999,20937298.91680,4474,159.662,5792550.66940,0 +1651831620000,36294.40,36340.60,36294.30,36311.00,185.991,1651831679999,6754973.17930,1847,129.513,4703519.43350,0 +1651831680000,36311.00,36320.90,36305.10,36313.60,72.527,1651831739999,2633700.26040,1000,38.432,1395612.72790,0 +1651831740000,36313.70,36327.70,36313.70,36323.60,49.175,1651831799999,1786142.10670,831,25.327,919919.30880,0 +1651831800000,36323.60,36323.60,36300.00,36313.70,87.975,1651831859999,3194593.40100,1159,33.874,1229999.31400,0 +1651831860000,36314.30,36315.50,36300.00,36314.40,61.089,1651831919999,2217968.40460,860,9.176,333161.32930,0 +1651831920000,36314.50,36329.70,36308.90,36309.00,52.843,1651831979999,1919233.52780,835,23.928,869125.77780,0 +1651831980000,36309.00,36309.00,36256.50,36274.10,169.551,1651832039999,6150140.00920,2111,51.412,1864856.49240,0 +1651832040000,36275.50,36281.10,36250.00,36261.80,140.534,1651832099999,5096346.98165,1730,44.993,1631733.36000,0 +1651832100000,36261.90,36271.10,36254.30,36254.30,75.535,1651832159999,2739050.95500,1209,37.805,1370900.38120,0 +1651832160000,36254.40,36257.30,36230.20,36245.40,167.688,1651832219999,6077203.81470,2212,56.602,2051394.02790,0 +1651832220000,36245.40,36248.80,36234.60,36243.60,86.160,1651832279999,3122676.86020,1017,35.295,1279196.34590,0 +1651832280000,36244.70,36245.30,36210.40,36239.70,209.506,1651832339999,7589720.72050,2042,84.813,3072408.31100,0 +1651832340000,36239.60,36239.70,36221.30,36225.50,130.747,1651832399999,4737298.48490,1225,69.554,2520120.99180,0 +1651832400000,36225.40,36259.60,36218.00,36252.00,137.093,1651832459999,4968832.13360,1872,97.475,3532844.88180,0 +1651832460000,36251.90,36252.00,36238.60,36245.20,73.753,1651832519999,2673191.61920,1141,37.925,1374605.46560,0 +1651832520000,36245.20,36260.70,36242.00,36242.10,93.411,1651832579999,3386369.52840,1102,58.295,2113359.48330,0 +1651832580000,36242.10,36253.50,36240.00,36240.00,35.099,1651832639999,1272200.63020,731,11.889,430939.05170,0 +1651832640000,36240.00,36259.20,36240.00,36242.70,55.578,1651832699999,2014869.67870,854,28.347,1027625.05460,0 +1651832700000,36242.70,36246.50,36236.60,36241.00,73.092,1651832759999,2648883.41130,914,44.499,1612650.05080,0 +1651832760000,36240.90,36255.40,36235.00,36238.20,76.661,1651832819999,2778797.75070,1007,44.513,1613585.13890,0 +1651832820000,36238.30,36244.30,36236.30,36236.30,45.912,1651832879999,1663869.96740,707,16.837,610186.21270,0 +1651832880000,36236.20,36236.20,36222.00,36222.20,100.170,1651832939999,3628934.83650,1084,50.663,1835401.30730,0 +1651832940000,36222.20,36237.90,36200.00,36233.70,231.823,1651832999999,8395249.91810,2114,70.335,2547302.77960,0 +1651833000000,36233.80,36238.70,36201.00,36202.40,99.247,1651833059999,3594345.22350,1457,49.961,1809619.95320,0 +1651833060000,36202.30,36227.90,36200.00,36219.80,255.854,1651833119999,9265064.15170,2117,83.828,3035761.59230,0 +1651833120000,36219.80,36254.30,36219.80,36236.80,138.091,1651833179999,5004665.32800,1471,113.888,4127513.46550,0 +1651833180000,36236.80,36236.90,36203.80,36209.10,134.703,1651833239999,4878286.94530,1468,71.024,2572058.71160,0 +1651833240000,36209.20,36222.00,36200.00,36200.10,66.541,1651833299999,2409157.98600,1176,22.284,806831.93680,0 +1651833300000,36200.10,36216.40,36195.00,36197.40,169.487,1651833359999,6135807.58648,1531,41.978,1519735.38910,0 +1651833360000,36196.90,36216.00,36177.00,36212.50,330.697,1651833419999,11970227.64704,2686,196.940,7129007.90130,0 +1651833420000,36211.10,36215.10,36179.70,36198.90,193.063,1651833479999,6988013.76060,1655,112.631,4076925.13790,0 +1651833480000,36198.90,36213.00,36183.80,36210.20,103.021,1651833539999,3728715.46710,1278,59.039,2136836.05650,0 +1651833540000,36210.10,36211.00,36202.20,36204.60,48.473,1651833599999,1754974.85740,867,22.217,804365.25290,0 +1651833600000,36204.50,36210.10,36170.00,36187.40,163.348,1651833659999,5912061.17691,1855,67.694,2450227.16470,0 +1651833660000,36187.40,36205.00,35959.30,36054.20,2352.556,1651833719999,84888645.00099,16261,644.201,23260238.32320,0 +1651833720000,36056.40,36105.90,36030.80,36105.90,881.407,1651833779999,31790884.27980,7807,444.375,16030240.97840,0 +1651833780000,36105.90,36124.40,36098.20,36121.40,329.711,1651833839999,11905846.05380,2922,242.425,8754222.09600,0 +1651833840000,36121.30,36121.30,36078.30,36080.70,256.831,1651833899999,9270233.08060,2760,113.969,4113764.38050,0 +1651833900000,36082.80,36140.70,36077.90,36135.60,281.899,1651833959999,10181166.38360,3169,194.759,7034050.77740,0 +1651833960000,36135.50,36139.90,36110.00,36114.40,135.449,1651834019999,4893209.69500,2069,75.874,2741049.12850,0 +1651834020000,36114.40,36126.70,36073.80,36109.90,480.006,1651834079999,17327356.04540,2948,159.396,5753243.23530,0 +1651834080000,36109.80,36121.70,36109.40,36118.20,79.334,1651834139999,2865244.61780,984,54.790,1978781.62900,0 +1651834140000,36118.20,36121.60,36092.90,36093.40,131.196,1651834199999,4736828.81980,1507,62.526,2257480.90310,0 +1651834200000,36093.50,36093.50,36005.30,36006.80,680.409,1651834259999,24519179.48790,6069,168.682,6079171.57060,0 +1651834260000,36006.80,36059.60,35903.30,36055.90,1178.534,1651834319999,42395670.60040,10642,489.335,17612446.55659,0 +1651834320000,36055.80,36055.90,36007.50,36011.40,264.928,1651834379999,9546065.41820,3440,124.608,4490114.90450,0 +1651834380000,36011.40,36017.20,35976.00,35992.00,210.546,1651834439999,7579408.88550,2763,93.368,3361184.90970,0 +1651834440000,35991.10,36027.90,35988.60,36013.60,206.756,1651834499999,7444787.95510,2538,125.526,4520003.15780,0 +1651834500000,36012.20,36021.50,35966.10,35971.00,218.172,1651834559999,7852594.09330,2740,97.526,3510315.68090,0 +1651834560000,35971.00,35972.60,35811.00,35870.80,1548.487,1651834619999,55565684.54605,13258,438.554,15736518.81140,0 +1651834620000,35870.80,35916.40,35755.00,35807.70,1520.955,1651834679999,54505408.95396,12350,484.214,17360524.68460,0 +1651834680000,35807.90,35894.00,35781.30,35875.20,747.105,1651834739999,26774992.93099,7213,420.478,15071858.97109,0 +1651834740000,35875.10,35973.60,35862.80,35927.90,703.573,1651834799999,25268161.28160,6570,518.925,18637325.38960,0 +1651834800000,35928.00,35929.00,35822.70,35829.90,472.833,1651834859999,16966457.19339,5650,197.508,7087152.30650,0 +1651834860000,35829.90,35897.50,35824.60,35895.00,577.439,1651834919999,20710893.71280,5803,320.666,11502611.52370,0 +1651834920000,35895.70,36019.40,35895.60,35971.90,1258.570,1651834979999,45278939.33807,9618,800.924,28815086.02827,0 +1651834980000,35972.00,36112.60,35964.50,36045.60,942.930,1651835039999,33995523.33051,8652,630.440,22729181.46021,0 +1651835040000,36045.60,36048.40,35975.00,35987.60,423.372,1651835099999,15245840.52360,4692,151.066,5439501.64140,0 +1651835100000,35987.50,36048.90,35980.00,35999.10,381.255,1651835159999,13728823.04250,3963,201.429,7254747.71640,0 +1651835160000,35999.10,36002.50,35934.30,35959.00,351.744,1651835219999,12648036.52511,4074,126.562,4550935.21880,0 +1651835220000,35959.40,35964.30,35925.00,35951.40,224.784,1651835279999,8079668.44640,3193,101.958,3664876.25340,0 +1651835280000,35951.50,35954.90,35931.10,35931.80,184.429,1651835339999,6628964.62300,2252,92.457,3323144.13670,0 +1651835340000,35931.80,35935.00,35875.20,35882.70,514.062,1651835399999,18454064.94849,4612,116.359,4177243.14610,0 +1651835400000,35882.70,35883.50,35800.10,35816.70,842.464,1651835459999,30191722.34971,7946,223.258,8002323.54630,0 +1651835460000,35816.60,35818.80,35715.10,35810.60,1601.445,1651835519999,57286027.35322,13897,737.900,26402068.90910,0 +1651835520000,35810.70,35810.70,35672.10,35730.40,1813.760,1651835579999,64805530.50390,13176,654.502,23382439.36200,0 +1651835580000,35730.50,35811.50,35729.60,35790.70,779.817,1651835639999,27897775.34730,7514,521.491,18657110.70600,0 +1651835640000,35790.70,35861.30,35762.90,35779.10,716.375,1651835699999,25652378.99933,6979,498.806,17863466.20479,0 +1651835700000,35779.00,35837.10,35764.00,35790.30,415.303,1651835759999,14867600.17180,5160,242.486,8681540.51140,0 +1651835760000,35790.30,35813.80,35759.20,35781.70,506.939,1651835819999,18140943.25250,4817,160.946,5760234.03480,0 +1651835820000,35781.80,35830.00,35781.80,35803.10,249.925,1651835879999,8948384.10940,3702,145.363,5204603.35560,0 +1651835880000,35803.10,35826.40,35770.00,35800.20,418.863,1651835939999,14996309.41190,3773,270.843,9698737.81490,0 +1651835940000,35800.20,35813.70,35787.30,35804.80,145.509,1651835999999,5209431.43970,2093,69.102,2474009.64600,0 +1651836000000,35804.70,35836.70,35761.80,35771.00,329.989,1651836059999,11813733.13050,3290,194.935,6978471.44210,0 +1651836060000,35771.00,35827.80,35762.30,35813.30,329.787,1651836119999,11804635.00680,3264,204.548,7321268.58340,0 +1651836120000,35813.20,35834.20,35781.10,35793.90,149.365,1651836179999,5348507.76420,2368,72.536,2597688.99740,0 +1651836180000,35794.00,35804.30,35773.60,35789.10,244.783,1651836239999,8761105.98410,2342,165.742,5932351.15670,0 +1651836240000,35789.10,35809.20,35773.10,35791.60,180.407,1651836299999,6457559.32910,2398,89.304,3196711.94960,0 +1651836300000,35791.60,35802.70,35732.00,35739.00,333.320,1651836359999,11916168.79590,3816,128.047,4578012.87530,0 +1651836360000,35739.10,35740.50,35666.00,35666.60,1171.627,1651836419999,41817400.06180,11141,364.107,12995819.89640,0 +1651836420000,35666.50,35718.30,35640.00,35646.70,1045.087,1651836479999,37274184.72045,9900,395.308,14103006.73630,0 +1651836480000,35646.70,35699.40,35550.00,35669.80,2350.926,1651836539999,83725375.84487,17101,930.445,33151336.14365,0 +1651836540000,35669.80,35728.00,35669.60,35704.60,639.158,1651836599999,22817096.64712,6375,323.468,11547562.88102,0 +1651836600000,35704.60,35749.40,35672.00,35719.50,500.188,1651836659999,17867512.74710,5334,267.447,9554593.06340,0 +1651836660000,35717.10,35739.50,35624.30,35624.80,437.776,1651836719999,15618157.25520,5185,169.152,6035875.10030,0 +1651836720000,35624.80,35680.40,35600.20,35660.00,487.247,1651836779999,17363732.52900,5345,249.593,8895789.33850,0 +1651836780000,35662.30,35735.60,35658.70,35727.70,545.787,1651836839999,19485845.19340,5083,388.554,13872968.25720,0 +1651836840000,35727.80,35819.90,35727.70,35805.50,917.809,1651836899999,32825669.44104,7316,670.979,23997837.64764,0 +1651836900000,35805.50,35830.00,35767.80,35782.90,533.081,1651836959999,19086066.98590,5965,294.300,10537808.40910,0 +1651836960000,35782.50,35817.20,35770.60,35803.80,370.684,1651837019999,13267670.37950,3555,185.682,6646751.10640,0 +1651837020000,35803.70,35972.40,35799.90,35925.50,1440.671,1651837079999,51712152.83322,10616,1113.519,39969688.71002,0 +1651837080000,35925.50,35972.40,35845.00,35845.10,772.099,1651837139999,27727983.30849,7414,330.211,11861027.40140,0 +1651837140000,35845.10,35892.50,35823.90,35872.50,387.114,1651837199999,13880438.66040,4373,212.029,7603318.31240,0 +1651837200000,35872.40,35935.10,35837.30,35844.70,362.353,1651837259999,13005849.49160,4324,206.863,7425708.38570,0 +1651837260000,35844.90,35879.20,35800.00,35803.10,362.297,1651837319999,12982747.05510,3979,179.291,6426799.11220,0 +1651837320000,35803.10,35818.30,35764.30,35800.00,401.209,1651837379999,14358651.96740,4317,184.678,6609576.25340,0 +1651837380000,35799.90,35815.00,35780.00,35810.00,434.489,1651837439999,15553337.30880,3181,166.748,5969594.00770,0 +1651837440000,35809.90,35810.00,35781.70,35785.90,148.466,1651837499999,5314190.86250,1701,88.146,3155200.73900,0 +1651837500000,35786.00,35809.00,35769.10,35805.00,331.943,1651837559999,11880380.37130,2600,202.289,7240639.90010,0 +1651837560000,35805.10,35815.00,35796.70,35809.90,261.687,1651837619999,9371340.12280,2179,202.379,7247629.91950,0 +1651837620000,35810.00,35810.00,35779.90,35808.40,163.761,1651837679999,5861542.89560,1802,70.622,2527600.24610,0 +1651837680000,35808.50,35823.00,35803.60,35823.00,297.226,1651837739999,10645451.66790,1742,240.868,8627009.26350,0 +1651837740000,35822.90,35858.60,35811.30,35811.30,816.864,1651837799999,29269622.37140,4334,615.474,22053173.13260,0 +1651837800000,35811.30,35833.50,35811.00,35830.80,155.100,1651837859999,5556466.39100,1227,119.979,4298303.65080,0 +1651837860000,35830.70,35850.00,35825.10,35849.90,198.498,1651837919999,7113677.13580,1824,79.094,2834597.58890,0 +1651837920000,35850.00,35875.70,35835.60,35865.10,192.773,1651837979999,6912858.22180,2132,117.672,4219862.19930,0 +1651837980000,35865.10,35865.10,35773.70,35786.40,401.874,1651838039999,14396567.07790,3274,73.346,2627883.20710,0 +1651838040000,35786.50,35795.80,35751.00,35770.60,355.283,1651838099999,12709560.76138,3536,185.640,6641343.06390,0 +1651838100000,35770.70,35819.50,35765.00,35806.10,285.081,1651838159999,10205269.11660,2561,119.284,4269952.32420,0 +1651838160000,35806.10,35841.40,35806.10,35818.80,189.800,1651838219999,6799059.86440,2168,118.564,4247108.38460,0 +1651838220000,35818.80,35822.20,35767.80,35776.40,191.639,1651838279999,6860020.49520,2213,43.045,1540915.61010,0 +1651838280000,35776.00,35779.10,35750.10,35779.10,124.984,1651838339999,4470127.46590,1977,50.517,1806959.42070,0 +1651838340000,35779.00,35797.30,35762.90,35766.00,139.143,1651838399999,4978663.68520,1799,66.319,2373082.89640,0 +1651838400000,35765.90,35817.30,35758.00,35803.80,244.953,1651838459999,8766333.15970,3278,149.399,5346926.15370,0 +1651838460000,35803.80,35850.00,35803.70,35841.30,342.160,1651838519999,12261120.69910,3221,235.954,8455386.42610,0 +1651838520000,35841.30,35888.00,35829.50,35880.30,322.612,1651838579999,11570376.11849,3747,190.304,6825218.06099,0 +1651838580000,35880.30,35891.50,35854.90,35860.10,355.331,1651838639999,12746784.85540,3526,153.890,5520534.75620,0 +1651838640000,35860.00,35896.10,35850.60,35871.20,314.828,1651838699999,11292705.29260,2827,137.995,4950810.31000,0 +1651838700000,35871.10,35884.00,35812.90,35814.00,131.992,1651838759999,4731518.92110,2391,52.524,1883031.96010,0 +1651838760000,35813.90,35847.90,35800.80,35803.80,149.508,1651838819999,5355402.24970,2070,65.306,2339388.35910,0 +1651838820000,35803.70,35827.60,35800.00,35804.30,141.389,1651838879999,5063853.76140,2020,60.335,2161027.37070,0 +1651838880000,35804.20,35829.50,35788.30,35804.70,178.391,1651838939999,6388003.44190,2017,106.609,3817766.88710,0 +1651838940000,35804.70,35817.40,35786.70,35789.30,114.541,1651838999999,4100664.74510,1668,50.969,1824794.01380,0 +1651839000000,35789.30,35800.00,35780.00,35785.90,88.542,1651839059999,3169000.11250,1486,35.043,1254250.40330,0 +1651839060000,35786.00,35806.20,35754.20,35765.40,312.910,1651839119999,11194270.86624,2818,79.370,2839868.53290,0 +1651839120000,35766.60,35772.90,35712.00,35717.00,507.792,1651839179999,18146431.62582,4817,152.869,5463047.21880,0 +1651839180000,35717.00,35732.20,35679.90,35697.30,571.492,1651839239999,20404172.91170,4872,155.612,5557049.37580,0 +1651839240000,35697.30,35743.00,35685.60,35694.70,465.982,1651839299999,16640472.21480,4003,244.804,8743297.05850,0 +1651839300000,35694.60,35733.30,35690.20,35694.70,180.809,1651839359999,6457494.37530,2558,86.664,3095094.25580,0 +1651839360000,35694.70,35709.90,35680.00,35701.60,460.300,1651839419999,16431135.40930,3679,329.986,11780001.91750,0 +1651839420000,35701.60,35701.70,35671.30,35686.10,200.621,1651839479999,7158481.32510,2638,92.982,3317782.63770,0 +1651839480000,35686.00,35719.30,35665.90,35677.50,419.760,1651839539999,14983125.73960,3563,232.389,8297230.85950,0 +1651839540000,35677.60,35703.50,35674.00,35687.10,147.227,1651839599999,5254657.08860,2166,93.457,3335711.66850,0 +1651839600000,35687.20,35730.00,35687.10,35706.50,218.932,1651839659999,7819809.92440,2810,141.826,5065719.96900,0 +1651839660000,35706.40,35793.20,35706.40,35778.30,385.688,1651839719999,13794837.74490,3823,254.193,9091244.83960,0 +1651839720000,35778.30,35870.00,35778.20,35844.30,842.630,1651839779999,30198667.96260,6651,627.119,22474161.11240,0 +1651839780000,35844.30,35866.00,35827.70,35847.30,396.637,1651839839999,14218871.11340,3233,153.043,5486189.15570,0 +1651839840000,35847.30,35868.00,35834.70,35863.70,256.738,1651839899999,9205178.11570,2821,123.686,4434724.80790,0 +1651839900000,35863.60,35947.90,35845.00,35899.90,942.275,1651839959999,33836577.33959,7628,676.376,24288052.02839,0 +1651839960000,35899.90,35903.60,35824.60,35842.50,451.169,1651840019999,16182017.45070,4389,165.125,5924117.23240,0 +1651840020000,35842.50,35899.90,35820.00,35899.00,301.313,1651840079999,10803909.22140,3270,162.104,5812515.39340,0 +1651840080000,35899.00,36066.20,35891.20,35990.70,1887.676,1651840139999,67968068.72445,15463,1300.115,46813696.24085,0 +1651840140000,35990.80,36023.30,35929.20,35967.80,632.154,1651840199999,22744321.06271,6375,366.294,13180337.82710,0 +1651840200000,35967.90,36288.00,35967.90,36170.70,3908.047,1651840259999,141367719.68770,28457,2576.997,93213932.82510,0 +1651840260000,36170.80,36233.90,36029.00,36115.80,1857.556,1651840319999,67140198.79436,15674,878.095,31741631.70570,0 +1651840320000,36116.70,36238.70,36050.40,36197.70,1227.313,1651840379999,44348838.96503,11139,665.257,24043953.88443,0 +1651840380000,36197.70,36235.20,36140.30,36155.40,881.201,1651840439999,31886723.56980,8176,543.199,19658152.78680,0 +1651840440000,36159.20,36196.90,36136.50,36183.80,433.678,1651840499999,15685788.14790,4666,171.121,6189994.16900,0 +1651840500000,36183.70,36220.00,36158.00,36182.80,745.938,1651840559999,26988480.64720,5901,295.239,10683418.85840,0 +1651840560000,36182.70,36327.00,36182.70,36310.90,1638.654,1651840619999,59429120.16433,11893,1075.824,39021433.78863,0 +1651840620000,36311.00,36331.10,36230.50,36250.00,911.306,1651840679999,33058568.02740,8185,373.784,13560152.72750,0 +1651840680000,36250.10,36266.70,36235.00,36254.90,378.354,1651840739999,13715643.34720,4366,178.095,6455827.58220,0 +1651840740000,36255.00,36267.00,36185.60,36193.90,543.613,1651840799999,19691848.37560,5197,177.872,6444590.56470,0 +1651840800000,36193.90,36193.90,36106.90,36122.70,767.574,1651840859999,27749387.60618,7245,266.826,9646080.07590,0 +1651840860000,36122.70,36122.70,36050.00,36111.80,947.088,1651840919999,34171935.37553,8330,349.615,12616390.84980,0 +1651840920000,36111.80,36127.80,36044.50,36127.50,631.410,1651840979999,22782918.14390,6532,309.262,11160778.45220,0 +1651840980000,36126.30,36165.80,36069.60,36080.70,640.583,1651841039999,23135959.99674,5643,344.075,12428852.08924,0 +1651841040000,36080.60,36081.50,36052.90,36068.00,227.702,1651841099999,8212768.98349,2828,86.700,3127090.42520,0 +1651841100000,36068.00,36089.10,36050.00,36054.10,280.743,1651841159999,10124743.43150,3506,104.182,3757663.18070,0 +1651841160000,36054.00,36055.00,35895.70,35901.80,1474.260,1651841219999,53016917.96694,12196,410.981,14775942.38740,0 +1651841220000,35902.00,35960.50,35888.00,35894.20,719.385,1651841279999,25839221.84580,6812,399.628,14355564.00270,0 +1651841280000,35894.30,35979.00,35894.20,35941.60,739.164,1651841339999,26568640.72730,5761,496.571,17848982.07840,0 +1651841340000,35941.60,35959.40,35832.50,35863.30,1234.169,1651841399999,44283187.57183,8862,438.861,15747490.91390,0 +1651841400000,35863.40,35917.80,35850.00,35873.00,359.333,1651841459999,12894727.79660,4678,208.700,7489451.68140,0 +1651841460000,35873.10,35940.70,35873.00,35924.20,440.037,1651841519999,15801179.64750,3760,304.478,10932996.83090,0 +1651841520000,35924.20,35927.70,35875.00,35879.30,312.254,1651841579999,11207637.79860,3446,141.674,5084958.87470,0 +1651841580000,35879.30,35916.20,35753.40,35787.70,1122.215,1651841639999,40205894.58483,8506,220.156,7891547.42850,0 +1651841640000,35787.80,35866.70,35750.10,35845.40,796.147,1651841699999,28509309.99339,7684,529.583,18968461.14739,0 +1651841700000,35845.50,35877.00,35750.70,35792.30,474.798,1651841759999,17011144.73794,5247,213.507,7653264.14190,0 +1651841760000,35791.20,35835.40,35780.30,35799.20,264.754,1651841819999,9478589.67090,3563,135.783,4861381.07240,0 +1651841820000,35799.20,35864.00,35799.10,35852.70,373.053,1651841879999,13370123.14039,3388,278.356,9976404.37309,0 +1651841880000,35852.70,35920.40,35843.10,35878.70,536.379,1651841939999,19248174.36593,5282,342.087,12276405.76233,0 +1651841940000,35878.70,35890.10,35800.00,35810.20,566.321,1651841999999,20293993.24130,4807,138.651,4969579.16510,0 +1651842000000,35813.50,35898.20,35806.80,35851.50,583.359,1651842059999,20919910.44940,4751,375.800,13477073.13630,0 +1651842060000,35851.60,35856.00,35800.00,35823.70,349.364,1651842119999,12516566.55610,3660,106.235,3805722.52500,0 +1651842120000,35823.40,35824.70,35771.00,35777.10,734.745,1651842179999,26299775.28270,4692,428.162,15325849.76680,0 +1651842180000,35777.00,35809.50,35760.00,35795.90,536.947,1651842239999,19210459.08102,3853,152.481,5456157.81640,0 +1651842240000,35795.90,35800.00,35704.10,35707.20,657.386,1651842299999,23498964.24360,5898,168.893,6037853.73210,0 +1651842300000,35707.30,35820.00,35693.50,35813.10,820.477,1651842359999,29335418.70090,7560,488.720,17478190.74990,0 +1651842360000,35813.00,35823.30,35777.60,35823.30,236.368,1651842419999,8461663.92780,2881,147.318,5273895.59710,0 +1651842420000,35823.30,35863.00,35792.20,35809.30,422.122,1651842479999,15122099.18309,3752,216.474,7756226.60169,0 +1651842480000,35809.20,35809.80,35780.30,35787.00,169.197,1651842539999,6056449.07630,2320,56.019,2005196.23710,0 +1651842540000,35787.00,35795.30,35780.90,35795.30,94.516,1651842599999,3382712.01740,1520,60.372,2160680.35880,0 +1651842600000,35795.30,35870.50,35792.50,35844.20,401.137,1651842659999,14377324.22111,3703,308.365,11052167.65301,0 +1651842660000,35844.10,35857.60,35808.00,35841.10,194.758,1651842719999,6979136.09820,2359,110.274,3951450.96630,0 +1651842720000,35840.70,35958.70,35840.00,35939.60,934.564,1651842779999,33561607.36870,7721,715.350,25690050.04250,0 +1651842780000,35939.60,36000.00,35932.40,35936.70,642.389,1651842839999,23105467.88864,6770,400.813,14417336.54044,0 +1651842840000,35936.10,35966.60,35906.80,35913.30,284.339,1651842899999,10217767.04580,3412,141.683,5091832.93250,0 +1651842900000,35913.30,35946.10,35863.40,35889.90,347.392,1651842959999,12466647.43470,3828,132.318,4748923.68720,0 +1651842960000,35890.00,35921.70,35877.20,35921.60,208.493,1651843019999,7485213.15950,2097,141.479,5079415.08130,0 +1651843020000,35921.60,35938.00,35910.80,35927.30,148.148,1651843079999,5322538.98740,1770,55.612,1997896.57190,0 +1651843080000,35927.30,35927.40,35882.10,35917.10,162.672,1651843139999,5840730.66800,2146,61.866,2221114.04710,0 +1651843140000,35917.10,36023.80,35905.70,35987.90,602.978,1651843199999,21694599.26217,4595,360.309,12962508.46357,0 +1651843200000,35987.90,36008.50,35921.90,35946.70,222.310,1651843259999,7997027.98090,3069,85.432,3073342.48610,0 +1651843260000,35946.80,36016.40,35929.40,36007.70,264.984,1651843319999,9536567.67750,3018,171.991,6190177.02420,0 +1651843320000,36007.70,36020.60,35972.80,35977.40,283.614,1651843379999,10211143.32240,3255,138.452,4985266.17220,0 +1651843380000,35977.40,35984.90,35915.60,35960.80,273.201,1651843439999,9820110.15230,3055,78.394,2818689.61300,0 +1651843440000,35960.80,35966.70,35925.60,35946.30,283.371,1651843499999,10185787.54490,2322,91.192,3278146.84190,0 +1651843500000,35946.20,35978.40,35940.00,35952.40,208.425,1651843559999,7494781.48120,2340,151.021,5430333.98490,0 +1651843560000,35952.40,35987.90,35933.60,35980.10,149.145,1651843619999,5362770.73580,1652,92.964,3343061.56430,0 +1651843620000,35980.10,35984.60,35959.00,35973.00,117.565,1651843679999,4229169.94380,1717,60.697,2183449.36530,0 +1651843680000,35973.00,36009.30,35970.50,35994.70,304.054,1651843739999,10944022.28380,2883,242.378,8723778.14230,0 +1651843740000,35994.70,35999.20,35975.20,35982.30,207.780,1651843799999,7477788.62700,2343,67.880,2442989.52620,0 +1651843800000,35983.00,36054.40,35898.10,35903.30,1425.496,1651843859999,51299405.84620,10471,653.651,23529960.33917,0 +1651843860000,35901.20,35988.70,35846.80,35988.60,1360.956,1651843919999,48865874.69387,10857,615.690,22112979.85411,0 +1651843920000,35986.20,35986.30,35766.10,35774.00,1047.487,1651843979999,37568367.14441,9168,348.716,12513677.93310,0 +1651843980000,35774.00,35794.20,35642.70,35642.80,2166.672,1651844039999,77361989.95093,16354,835.015,29816847.44910,0 +1651844040000,35642.80,35728.00,35633.00,35650.70,1301.872,1651844099999,46446142.68124,12589,595.074,21232748.04930,0 +1651844100000,35650.70,35655.70,35455.00,35480.30,3674.586,1651844159999,130597669.40434,29543,1085.117,38577163.68320,0 +1651844160000,35481.90,35526.20,35243.90,35307.70,7105.874,1651844219999,251287073.38066,54078,2839.091,100426018.35157,0 +1651844220000,35307.70,35466.40,35200.00,35434.50,3772.999,1651844279999,133309348.49555,30590,1939.540,68568861.66645,0 +1651844280000,35433.00,35445.40,35319.90,35375.50,1402.968,1651844339999,49645611.65440,13121,740.486,26206086.11050,0 +1651844340000,35375.50,35410.00,35319.50,35396.60,1300.202,1651844399999,45973878.81230,10990,717.260,25361633.27460,0 +1651844400000,35396.60,35516.50,35378.30,35513.50,1593.788,1651844459999,56490437.85910,13974,1016.979,36048302.10820,0 +1651844460000,35513.60,35841.80,35513.60,35787.80,4367.423,1651844519999,155923624.05818,30917,2649.267,94563631.86488,0 +1651844520000,35787.90,35803.40,35659.90,35695.80,2121.387,1651844579999,75826548.62625,16713,1090.275,38978318.50440,0 +1651844580000,35695.70,35695.80,35530.00,35578.30,1881.774,1651844639999,66974066.80277,15140,773.499,27528374.68280,0 +1651844640000,35578.20,35586.80,35450.00,35487.40,1810.548,1651844699999,64261444.29880,14533,865.924,30735692.64300,0 +1651844700000,35482.70,35605.60,35418.60,35502.40,2197.218,1651844759999,78008138.48816,16123,1031.501,36639531.85103,0 +1651844760000,35502.40,35510.80,35385.00,35385.00,1196.516,1651844819999,42417865.08120,11050,572.552,20299933.34000,0 +1651844820000,35385.00,35465.90,35303.40,35366.80,1806.289,1651844879999,63914131.18223,16299,974.956,34504962.58570,0 +1651844880000,35366.80,35488.90,35354.60,35449.90,1233.361,1651844939999,43706377.97787,11023,604.860,21434587.67407,0 +1651844940000,35450.00,35649.70,35449.90,35584.40,1927.559,1651844999999,68532943.91304,15955,1295.116,46050363.84834,0 +1651845000000,35584.50,35712.70,35556.10,35582.50,1676.223,1651845059999,59719166.87360,14384,855.181,30475527.67497,0 +1651845060000,35582.10,35633.10,35508.00,35566.30,974.054,1651845119999,34643681.87230,9380,451.207,16049558.05300,0 +1651845120000,35567.10,35585.00,35475.30,35527.90,1115.189,1651845179999,39624478.88498,8918,454.632,16155548.26980,0 +1651845180000,35527.90,35610.40,35507.10,35576.00,1031.979,1651845239999,36688173.88230,7888,540.731,19224858.26190,0 +1651845240000,35576.00,35645.30,35561.10,35621.60,863.997,1651845299999,30764037.38953,8361,567.078,20192925.56983,0 +1651845300000,35621.90,35697.50,35586.70,35597.40,1071.396,1651845359999,38180885.91655,9074,505.346,18014642.90515,0 +1651845360000,35598.80,35741.20,35598.70,35623.90,1146.799,1651845419999,40922765.66270,9713,738.366,26352580.42870,0 +1651845420000,35623.80,35687.30,35615.40,35687.30,459.621,1651845479999,16386165.73790,5281,203.222,7246130.16000,0 +1651845480000,35687.90,35728.10,35654.50,35707.40,465.734,1651845539999,16618004.37440,5574,267.938,9561326.94240,0 +1651845540000,35708.30,35763.60,35688.40,35727.10,771.361,1651845599999,27555568.28186,7575,389.588,13917857.56636,0 +1651845600000,35728.80,35814.80,35714.90,35803.40,1099.456,1651845659999,39332408.09319,10224,777.928,27832959.05449,0 +1651845660000,35804.50,35955.00,35790.10,35835.50,1720.961,1651845719999,61738571.31705,16572,1047.523,37582471.37265,0 +1651845720000,35835.50,35835.50,35607.20,35616.90,1655.158,1651845779999,59101984.51710,15064,407.011,14536083.25730,0 +1651845780000,35616.90,35813.50,35606.70,35766.40,1949.970,1651845839999,69663668.92232,12036,998.729,35675510.76192,0 +1651845840000,35766.50,35830.00,35756.50,35812.60,660.508,1651845899999,23642648.13240,6598,391.456,14012926.53460,0 +1651845900000,35812.60,35950.00,35811.90,35924.50,1442.433,1651845959999,51789093.58795,12855,911.477,32722399.84235,0 +1651845960000,35924.60,35970.00,35863.50,35902.60,1023.808,1651846019999,36775474.97450,9074,605.911,21765510.51640,0 +1651846020000,35902.70,36077.10,35901.60,35952.90,1638.154,1651846079999,58959585.08280,14055,1088.227,39172688.83319,0 +1651846080000,35952.80,35958.00,35810.00,35830.50,1104.810,1651846139999,39639015.32659,10927,328.692,11793121.35140,0 +1651846140000,35831.50,35860.00,35791.20,35797.10,761.477,1651846199999,27281385.53173,8186,327.626,11739100.65430,0 +1651846200000,35797.20,35850.00,35704.10,35731.90,1385.808,1651846259999,49554587.85902,10612,478.897,17129774.66570,0 +1651846260000,35732.00,35862.00,35709.80,35834.00,841.818,1651846319999,30139565.29559,8422,538.635,19287212.53009,0 +1651846320000,35834.00,35924.40,35817.70,35882.70,879.439,1651846379999,31541573.77570,7748,478.499,17163953.38680,0 +1651846380000,35882.70,35967.60,35865.80,35952.10,1045.446,1651846439999,37548218.29761,9209,622.417,22357077.04271,0 +1651846440000,35952.10,35968.20,35861.10,35894.80,916.664,1651846499999,32932730.26150,8529,450.235,16175919.09610,0 +1651846500000,35894.80,35958.60,35873.30,35957.90,628.029,1651846559999,22560012.71720,5616,279.803,10051325.20460,0 +1651846560000,35958.00,35984.20,35911.50,35922.00,673.240,1651846619999,24202372.19210,5986,352.709,12680491.38430,0 +1651846620000,35922.10,36071.80,35912.50,36069.70,1304.012,1651846679999,46964817.59902,10498,1018.359,36677353.01572,0 +1651846680000,36069.70,36099.80,36001.60,36099.80,1022.014,1651846739999,36834143.96102,8805,515.988,18599331.29532,0 +1651846740000,36099.80,36182.00,36018.20,36028.90,1894.444,1651846799999,68426166.11921,17267,1011.063,36528745.15661,0 +1651846800000,36029.10,36054.70,35959.50,35971.30,909.851,1651846859999,32754752.72878,9581,327.528,11792124.14850,0 +1651846860000,35971.30,35983.60,35900.20,35940.10,859.485,1651846919999,30884613.13057,7829,283.492,10187793.25550,0 +1651846920000,35940.00,36071.80,35937.10,36035.00,809.867,1651846979999,29174108.11189,8306,491.369,17699801.46519,0 +1651846980000,36035.10,36035.10,35922.00,36016.10,754.779,1651847039999,27152319.21711,7899,295.530,10631426.21710,0 +1651847040000,36016.40,36043.70,35970.00,35994.00,564.461,1651847099999,20320750.36170,5774,282.125,10157909.80140,0 +1651847100000,35995.70,36048.00,35975.80,35986.20,732.900,1651847159999,26385442.51550,5533,325.218,11709118.88000,0 +1651847160000,35986.30,36063.10,35973.40,35994.30,572.071,1651847219999,20603045.41249,5468,268.952,9687823.38779,0 +1651847220000,35994.90,36010.70,35938.00,35938.10,446.282,1651847279999,16055733.64971,4968,173.613,6245996.92220,0 +1651847280000,35938.00,35974.90,35893.00,35893.00,489.911,1651847339999,17604385.69944,5828,201.246,7232960.83580,0 +1651847340000,35893.10,35924.20,35785.50,35800.00,1455.037,1651847399999,52181571.36434,11511,435.910,15639382.47460,0 +1651847400000,35802.40,35899.20,35773.70,35817.90,1178.823,1651847459999,42230717.16156,9737,490.568,17577741.82260,0 +1651847460000,35817.80,35934.10,35804.10,35892.90,701.082,1651847519999,25135145.94000,6545,471.651,16910655.46100,0 +1651847520000,35893.50,35944.50,35830.60,35831.20,609.972,1651847579999,21889457.91000,6130,288.257,10345807.88550,0 +1651847580000,35831.10,35854.50,35728.50,35754.70,883.502,1651847639999,31611810.04968,8438,274.219,9811213.69520,0 +1651847640000,35753.20,35797.90,35726.40,35794.80,1066.845,1651847699999,38152155.44560,7316,585.491,20939480.73640,0 +1651847700000,35794.70,35824.70,35739.50,35786.50,823.081,1651847759999,29448423.00300,7704,416.396,14899677.65940,0 +1651847760000,35787.50,35848.30,35768.10,35776.00,628.924,1651847819999,22524669.02200,6143,260.318,9323456.93080,0 +1651847820000,35775.90,35790.10,35736.30,35764.80,311.608,1651847879999,11144097.96340,4138,147.833,5287356.04270,0 +1651847880000,35764.90,35819.30,35737.50,35799.30,512.975,1651847939999,18353312.94140,4479,229.809,8222306.71770,0 +1651847940000,35798.30,35872.70,35798.20,35854.10,678.020,1651847999999,24299363.23029,5265,423.965,15194257.42119,0 +1651848000000,35849.90,35946.40,35817.30,35940.40,1009.693,1651848059999,36239684.63569,7811,684.673,24572137.89659,0 +1651848060000,35939.10,35972.40,35883.80,35919.30,800.093,1651848119999,28747340.54051,6641,496.036,17824759.96281,0 +1651848120000,35919.40,35919.40,35851.90,35895.50,319.588,1651848179999,11468040.41909,3836,124.679,4473679.74260,0 +1651848180000,35895.60,35960.00,35876.70,35940.80,254.566,1651848239999,9145057.32691,3738,146.982,5280898.88911,0 +1651848240000,35940.40,35972.40,35900.00,35902.50,431.869,1651848299999,15516367.17930,3818,198.957,7150199.95460,0 +1651848300000,35902.00,36070.20,35873.10,36032.60,1284.404,1651848359999,46224329.11282,10894,851.852,30663889.36512,0 +1651848360000,36032.50,36140.00,35990.20,36114.00,2071.367,1651848419999,74733764.43308,12784,1197.386,43199820.65258,0 +1651848420000,36114.10,36144.00,36060.50,36075.20,1417.053,1651848479999,51159982.74040,10166,790.211,28533889.07730,0 +1651848480000,36075.30,36107.60,36026.10,36059.90,734.044,1651848539999,26477929.92340,6651,262.643,9474022.26800,0 +1651848540000,36059.90,36110.00,36039.90,36103.20,440.897,1651848599999,15905823.96540,4784,224.288,8091659.41300,0 +1651848600000,36103.20,36162.80,36026.60,36070.50,854.538,1651848659999,30850975.26556,7873,494.980,17876372.31557,0 +1651848660000,36070.50,36077.90,36015.50,36044.40,569.266,1651848719999,20518955.49370,5140,243.223,8767106.34650,0 +1651848720000,36044.30,36070.80,35994.90,36009.00,481.821,1651848779999,17357487.36078,4866,170.266,6134426.96030,0 +1651848780000,36009.00,36076.30,36004.00,36055.00,389.485,1651848839999,14035170.93900,4229,250.430,9024431.35600,0 +1651848840000,36054.90,36117.20,36040.00,36102.90,451.484,1651848899999,16286543.16200,4559,273.484,9866289.37120,0 +1651848900000,36102.80,36103.00,36050.50,36072.40,308.579,1651848959999,11132561.71700,4166,142.936,5156464.25600,0 +1651848960000,36071.90,36105.50,36057.00,36068.40,447.458,1651849019999,16145418.63270,4292,188.921,6817495.23650,0 +1651849020000,36068.50,36133.00,36049.20,36122.30,478.304,1651849079999,17267562.76720,4491,255.487,9225523.00880,0 +1651849080000,36122.30,36158.50,36105.20,36150.70,473.630,1651849139999,17113502.83037,4716,310.589,11223029.13247,0 +1651849140000,36149.90,36241.80,36121.40,36125.80,1514.544,1651849199999,54808500.48970,12109,970.134,35112088.65730,0 +1651849200000,36125.80,36181.20,36099.60,36169.70,804.043,1651849259999,29047732.15180,6115,392.595,14185060.83130,0 +1651849260000,36168.40,36199.90,36131.00,36134.10,595.033,1651849319999,21520992.73740,5299,295.977,10706173.26130,0 +1651849320000,36134.20,36150.70,36094.40,36107.70,592.788,1651849379999,21410004.07050,5093,206.585,7462572.67660,0 +1651849380000,36107.60,36113.20,36050.70,36074.20,538.522,1651849439999,19429921.09949,5379,183.056,6605142.30160,0 +1651849440000,36074.20,36117.30,36072.40,36088.90,239.051,1651849499999,8628717.68760,3085,117.375,4236695.31150,0 +1651849500000,36088.80,36135.90,36069.30,36098.90,325.886,1651849559999,11764692.46750,3945,132.207,4772925.54390,0 +1651849560000,36098.80,36140.00,36079.50,36139.90,280.115,1651849619999,10113919.94890,2914,151.565,5472942.97970,0 +1651849620000,36140.00,36146.10,36070.90,36082.20,311.557,1651849679999,11249121.95570,3324,112.615,4066199.12830,0 +1651849680000,36084.20,36190.00,36083.90,36181.50,393.924,1651849739999,14232685.84644,3547,294.826,10652858.54034,0 +1651849740000,36181.40,36228.40,36172.00,36188.80,673.693,1651849799999,24385772.18218,5900,388.195,14052613.28608,0 +1651849800000,36188.70,36194.30,36090.10,36091.10,382.425,1651849859999,13817825.57510,4590,112.743,4074090.78920,0 +1651849860000,36093.80,36113.00,36085.00,36103.70,206.666,1651849919999,7460071.20850,2701,80.265,2897450.95060,0 +1651849920000,36103.60,36144.30,36080.00,36132.40,336.302,1651849979999,12145208.30310,3775,201.702,7284965.63380,0 +1651849980000,36132.40,36162.20,36114.80,36152.60,202.458,1651850039999,7318008.80900,2902,119.865,4332820.15080,0 +1651850040000,36152.60,36189.00,36144.00,36188.50,341.169,1651850099999,12339385.45980,3565,121.415,4391616.83070,0 +1651850100000,36188.60,36229.00,36150.00,36221.50,712.570,1651850159999,25794613.94870,5523,341.355,12358013.48890,0 +1651850160000,36221.40,36232.30,36148.90,36169.30,399.405,1651850219999,14453062.39820,4654,147.239,5329069.25550,0 +1651850220000,36169.30,36215.70,36152.00,36210.10,243.661,1651850279999,8817997.91500,3386,162.832,5892911.92150,0 +1651850280000,36210.00,36223.70,36166.00,36184.60,494.031,1651850339999,17887153.99270,4630,296.086,10721087.24880,0 +1651850340000,36184.60,36222.00,36166.00,36194.70,440.662,1651850399999,15948715.63550,3691,155.360,5624171.61180,0 +1651850400000,36195.70,36214.70,36153.90,36207.80,287.417,1651850459999,10399081.28580,3208,118.634,4292909.64030,0 +1651850460000,36208.40,36296.80,36200.80,36285.40,1271.793,1651850519999,46114706.82004,10522,797.986,28937125.76464,0 +1651850520000,36285.30,36341.90,36256.50,36289.40,1536.601,1651850579999,55777785.33392,12103,807.425,29314765.09812,0 +1651850580000,36289.40,36310.00,36258.30,36296.30,559.820,1651850639999,20314838.46190,5635,244.116,8859632.88920,0 +1651850640000,36299.40,36399.80,36289.10,36372.40,1505.838,1651850699999,54745232.85592,12251,915.495,33289049.68112,0 +1651850700000,36372.40,36426.40,36336.00,36397.90,1274.005,1651850759999,46343830.82408,9976,647.259,23549194.56258,0 +1651850760000,36398.00,36412.80,36277.90,36297.80,909.257,1651850819999,33041602.96100,8617,381.455,13864247.00200,0 +1651850820000,36297.70,36349.00,36285.30,36312.80,306.734,1651850879999,11139913.03850,4073,181.456,6590087.73540,0 +1651850880000,36312.70,36355.80,36286.00,36316.10,523.864,1651850939999,19024351.86620,4857,161.990,5883436.22940,0 +1651850940000,36316.10,36321.90,36256.00,36291.50,497.392,1651850999999,18047191.44550,4633,162.041,5879727.70370,0 +1651851000000,36291.60,36310.00,36246.20,36279.30,468.961,1651851059999,17009221.77865,4709,206.409,7487660.97470,0 +1651851060000,36281.40,36314.10,36229.40,36240.20,470.606,1651851119999,17069099.91600,5127,199.579,7240785.12030,0 +1651851120000,36240.20,36246.50,36166.00,36200.10,896.465,1651851179999,32448523.12553,7392,331.997,12017419.11280,0 +1651851180000,36200.10,36219.00,36130.80,36168.20,1029.988,1651851239999,37258346.41367,7147,481.405,17417981.14980,0 +1651851240000,36168.30,36175.30,36102.00,36117.30,711.833,1651851299999,25720576.50228,5719,192.445,6953728.52330,0 +1651851300000,36117.30,36167.50,36100.00,36123.00,810.342,1651851359999,29276674.24770,5796,521.214,18832009.04720,0 +1651851360000,36121.20,36165.40,36085.00,36131.60,440.536,1651851419999,15912728.19999,4532,178.406,6445847.65170,0 +1651851420000,36129.60,36150.00,36076.30,36076.30,393.586,1651851479999,14211185.33180,3328,141.906,5124770.87860,0 +1651851480000,36076.20,36108.00,35972.40,36005.40,1023.755,1651851539999,36893137.89044,9054,349.188,12583739.36370,0 +1651851540000,36005.50,36075.30,36003.50,36019.60,580.541,1651851599999,20923570.99260,5781,305.871,11025322.72220,0 +1651851600000,36019.50,36067.50,36006.70,36046.00,543.536,1651851659999,19585662.63820,4639,294.641,10617153.58130,0 +1651851660000,36046.30,36097.10,36040.20,36073.80,453.907,1651851719999,16374864.96760,3901,333.499,12030843.52900,0 +1651851720000,36072.50,36130.00,36072.40,36105.00,529.190,1651851779999,19107785.41030,4223,415.153,14990914.79940,0 +1651851780000,36105.10,36110.00,36060.00,36097.40,180.241,1651851839999,6504040.00610,2564,92.419,3335165.57760,0 +1651851840000,36097.50,36129.00,36070.00,36071.30,212.205,1651851899999,7660694.32430,2443,108.349,3912050.48810,0 +1651851900000,36071.30,36077.60,36019.20,36039.80,455.140,1651851959999,16403556.49430,4443,209.523,7551321.68190,0 +1651851960000,36040.00,36099.20,36030.00,36041.50,417.363,1651852019999,15051326.35710,4295,213.348,7695180.44130,0 +1651852020000,36041.60,36076.40,36040.00,36076.10,185.212,1651852079999,6676473.19590,2148,131.737,4748921.48530,0 +1651852080000,36076.10,36086.60,36050.30,36062.10,232.631,1651852139999,8391339.46310,2539,155.483,5608741.39740,0 +1651852140000,36062.00,36100.80,36055.70,36089.20,251.365,1651852199999,9070648.17390,2765,164.576,5939052.48010,0 +1651852200000,36088.70,36132.70,36060.00,36077.30,405.914,1651852259999,14652604.54880,3941,235.513,8502832.50800,0 +1651852260000,36077.10,36199.80,36071.60,36165.40,808.068,1651852319999,29213596.41790,6650,605.105,21874230.15800,0 +1651852320000,36165.40,36181.00,36084.60,36095.10,303.174,1651852379999,10955750.24100,3699,122.971,4444825.87760,0 +1651852380000,36095.00,36095.10,35927.90,35966.50,1234.867,1651852439999,44435238.54769,10311,282.525,10164383.02010,0 +1651852440000,35966.50,36014.70,35940.40,36009.60,372.531,1651852499999,13405748.09180,4475,218.644,7868619.18050,0 +1651852500000,36009.60,36040.40,36000.00,36015.70,224.266,1651852559999,8077892.35130,2923,120.673,4346442.97470,0 +1651852560000,36015.90,36047.00,36007.60,36014.90,202.334,1651852619999,7289745.03340,2448,123.043,4433005.89970,0 +1651852620000,36014.90,36047.70,35994.40,36045.70,245.270,1651852679999,8835182.59070,2482,153.000,5511785.85020,0 +1651852680000,36045.60,36045.60,35934.60,35939.90,377.187,1651852739999,13568698.86480,3948,98.304,3535965.68580,0 +1651852740000,35938.20,35990.00,35934.90,35989.10,245.719,1651852799999,8838662.47940,2847,132.772,4775955.11720,0 +1651852800000,35989.10,35997.00,35952.10,35979.00,317.133,1651852859999,11408421.99400,4264,162.162,5834461.92950,0 +1651852860000,35979.90,36059.50,35969.70,36026.50,542.230,1651852919999,19525952.63529,4124,408.477,14708160.15939,0 +1651852920000,36026.40,36097.60,35992.60,36064.50,863.476,1651852979999,31144791.61720,5170,566.112,20420219.12650,0 +1651852980000,36064.50,36096.60,36040.40,36073.30,463.607,1651853039999,16719764.31580,3599,236.899,8543956.78610,0 +1651853040000,36073.20,36097.30,36056.60,36090.00,171.353,1651853099999,6181944.39130,2163,79.287,2860321.37840,0 +1651853100000,36090.00,36134.70,36073.60,36108.00,320.869,1651853159999,11585403.07670,3595,195.035,7041738.45250,0 +1651853160000,36108.10,36179.60,36093.80,36166.10,431.527,1651853219999,15594119.46188,4712,244.881,8849875.76258,0 +1651853220000,36166.00,36192.00,36124.00,36144.40,536.161,1651853279999,19385639.93740,5104,238.966,8641185.75200,0 +1651853280000,36144.30,36152.20,36105.00,36118.30,264.188,1651853339999,9543486.27980,2764,80.446,2906125.52730,0 +1651853340000,36118.30,36118.30,36037.20,36051.40,443.717,1651853399999,16007635.09259,3310,104.923,3785592.45480,0 +1651853400000,36051.90,36130.00,36014.10,36116.60,710.894,1651853459999,25640430.82171,5402,446.431,16103598.24460,0 +1651853460000,36116.60,36116.60,36003.40,36010.60,578.330,1651853519999,20840678.75738,5028,165.807,5975559.99590,0 +1651853520000,36010.70,36031.90,35966.00,36007.60,506.685,1651853579999,18241948.64120,4366,175.989,6336262.14110,0 +1651853580000,36007.20,36007.20,35920.00,35949.50,829.357,1651853639999,29819265.01787,7494,315.873,11358025.38260,0 +1651853640000,35949.40,35971.40,35907.50,35964.10,539.472,1651853699999,19384762.65240,4833,238.916,8586972.77750,0 +1651853700000,35964.10,35968.30,35915.70,35939.90,414.126,1651853759999,14885380.76380,4296,226.401,8138187.99110,0 +1651853760000,35940.00,36012.80,35939.90,35975.00,271.175,1651853819999,9757767.20590,3289,177.824,6398700.23050,0 +1651853820000,35975.20,36021.60,35975.20,35998.70,163.913,1651853879999,5900963.90060,2115,108.826,3917730.73030,0 +1651853880000,35998.70,36040.00,35998.70,36022.50,189.667,1651853939999,6831406.56680,2233,127.761,4601744.91820,0 +1651853940000,36022.50,36111.30,35976.70,35984.20,616.179,1651853999999,22216348.92780,5430,405.561,14624647.83590,0 +1651854000000,35984.20,36080.00,35984.10,36064.10,252.233,1651854059999,9088026.60610,3022,155.880,5616001.78840,0 +1651854060000,36064.10,36100.00,36037.70,36062.50,252.772,1651854119999,9116051.26540,3061,125.764,4535838.94410,0 +1651854120000,36062.50,36130.30,36062.50,36125.00,580.677,1651854179999,20965653.34350,5047,347.323,12541150.08890,0 +1651854180000,36125.10,36160.00,36077.00,36094.00,427.426,1651854239999,15435934.22477,4403,250.278,9039309.65637,0 +1651854240000,36092.30,36122.10,36046.60,36063.60,317.033,1651854299999,11439835.80399,3238,103.673,3741553.02670,0 +1651854300000,36063.60,36153.90,36052.60,36109.10,410.560,1651854359999,14823146.92540,3518,256.217,9250023.59470,0 +1651854360000,36109.00,36122.80,36077.80,36108.20,173.968,1651854419999,6280659.48400,2062,66.175,2388972.52620,0 +1651854420000,36108.30,36108.30,36056.80,36075.50,196.256,1651854479999,7081377.87900,2210,68.784,2481850.58590,0 +1651854480000,36075.50,36103.10,36048.40,36091.20,178.029,1651854539999,6422198.08860,2088,94.317,3402860.12830,0 +1651854540000,36091.10,36129.30,36087.00,36087.10,157.240,1651854599999,5677507.27600,2263,74.532,2691039.37490,0 +1651854600000,36086.70,36105.50,36030.50,36067.10,432.975,1651854659999,15616998.90300,3553,212.372,7659803.20880,0 +1651854660000,36065.80,36132.00,36065.00,36115.10,228.722,1651854719999,8258408.68030,2987,151.723,5478240.22870,0 +1651854720000,36115.00,36133.30,36090.00,36099.90,240.746,1651854779999,8695738.88330,2689,142.870,5160715.32610,0 +1651854780000,36099.90,36129.30,36091.10,36107.20,118.682,1651854839999,4285740.70200,1461,64.102,2314870.90160,0 +1651854840000,36107.30,36171.60,36107.30,36163.60,365.829,1651854899999,13227135.96554,3705,211.829,7658588.31194,0 +1651854900000,36163.60,36180.00,36116.70,36153.60,311.737,1651854959999,11269233.31471,2659,102.964,3722927.94781,0 +1651854960000,36153.80,36181.90,36093.90,36096.70,278.696,1651855019999,10070807.55300,2815,108.974,3938623.66600,0 +1651855020000,36096.80,36098.00,36050.00,36075.10,279.354,1651855079999,10074934.65069,3199,105.842,3817043.83100,0 +1651855080000,36075.00,36111.00,36071.60,36110.60,160.677,1651855139999,5798985.70770,2071,86.080,3106668.24130,0 +1651855140000,36111.10,36169.20,36111.10,36134.40,293.038,1651855199999,10591202.32624,3047,178.532,6451979.75104,0 +1651855200000,36134.40,36144.30,36090.00,36139.40,233.736,1651855259999,8441107.99710,2720,108.654,3924371.46100,0 +1651855260000,36140.80,36155.80,36087.90,36106.30,190.147,1651855319999,6867549.68470,2061,87.944,3176404.52120,0 +1651855320000,36106.40,36120.00,36088.90,36112.60,135.662,1651855379999,4898169.47850,1545,57.361,2071010.35690,0 +1651855380000,36112.50,36129.90,36098.00,36122.40,162.093,1651855439999,5854340.09470,1690,75.229,2717040.86660,0 +1651855440000,36124.60,36131.10,36104.70,36124.00,82.921,1651855499999,2994906.85120,1133,40.697,1469768.78350,0 +1651855500000,36124.10,36149.20,36115.00,36119.60,173.370,1651855559999,6263825.56500,1985,91.996,3323661.44880,0 +1651855560000,36119.70,36127.90,36087.00,36094.00,107.568,1651855619999,3883136.80460,1475,33.355,1204084.33900,0 +1651855620000,36094.00,36104.90,36080.80,36088.80,98.926,1651855679999,3570238.77530,1476,54.118,1953190.98140,0 +1651855680000,36088.90,36126.10,36072.70,36124.30,160.142,1651855739999,5780531.87400,2017,85.690,3093434.73170,0 +1651855740000,36124.30,36130.00,36069.60,36069.60,111.564,1651855799999,4027977.34480,1397,36.523,1318729.59460,0 +1651855800000,36069.60,36078.30,36004.90,36069.30,553.186,1651855859999,19936277.98938,4509,216.414,7799868.61780,0 +1651855860000,36069.20,36081.70,36050.00,36073.10,109.900,1651855919999,3963784.86120,1510,44.970,1622020.79720,0 +1651855920000,36073.20,36166.10,36051.80,36138.00,301.339,1651855979999,10887313.87327,2927,224.063,8096187.66987,0 +1651855980000,36137.10,36234.60,36137.10,36175.50,985.146,1651856039999,35659914.64803,7955,692.333,25063170.00773,0 +1651856040000,36176.50,36195.50,36157.30,36165.70,161.103,1651856099999,5828021.53420,2265,80.178,2900615.46450,0 +1651856100000,36165.60,36175.00,36133.40,36163.40,164.298,1651856159999,5940174.15610,2097,64.979,2349213.41000,0 +1651856160000,36163.50,36222.00,36163.50,36180.20,231.982,1651856219999,8397028.38600,2962,151.123,5470150.50330,0 +1651856220000,36180.30,36200.00,36171.80,36188.60,217.187,1651856279999,7859360.19490,2482,88.651,3207882.48980,0 +1651856280000,36188.60,36215.00,36186.90,36196.20,159.851,1651856339999,5787444.12600,1873,91.394,3308877.22660,0 +1651856340000,36196.10,36222.50,36182.80,36200.80,254.594,1651856399999,9216836.65220,2468,140.992,5104312.38800,0 +1651856400000,36200.70,36211.40,36156.70,36165.50,209.892,1651856459999,7594157.42470,2347,64.589,2336651.04110,0 +1651856460000,36165.40,36185.00,36151.00,36153.20,118.411,1651856519999,4282764.99870,1522,50.535,1827904.16290,0 +1651856520000,36153.30,36182.30,36150.00,36150.00,83.562,1651856579999,3022238.00570,1256,38.172,1380642.28840,0 +1651856580000,36150.00,36172.00,36137.00,36164.80,140.294,1651856639999,5071635.07580,1751,60.948,2203480.82660,0 +1651856640000,36164.80,36225.00,36163.50,36196.10,247.878,1651856699999,8973956.36510,2726,183.751,6652348.82310,0 +1651856700000,36196.00,36196.60,36124.00,36129.20,185.021,1651856759999,6688512.08030,2234,65.359,2362693.64300,0 +1651856760000,36129.30,36137.70,36103.80,36123.30,285.215,1651856819999,10300990.98420,2496,87.424,3157433.78950,0 +1651856820000,36123.30,36140.70,36104.90,36134.80,131.672,1651856879999,4755545.35010,1597,70.819,2557806.20000,0 +1651856880000,36134.70,36174.00,36117.00,36151.50,81.465,1651856939999,2944468.26240,1293,49.046,1772739.03510,0 +1651856940000,36151.50,36178.10,36130.00,36145.10,136.092,1651856999999,4921013.73050,1636,92.317,3338451.99050,0 +1651857000000,36143.70,36151.20,36123.10,36136.40,89.166,1651857059999,3222147.91600,1354,47.450,1714757.20420,0 +1651857060000,36136.50,36151.50,36123.30,36151.10,92.001,1651857119999,3324644.87070,1082,47.152,1703925.31890,0 +1651857120000,36150.60,36165.80,36110.00,36113.10,115.554,1651857179999,4176064.10450,1549,51.545,1862894.67860,0 +1651857180000,36113.00,36115.70,36085.40,36110.70,177.538,1651857239999,6408799.54060,1937,43.580,1573282.91590,0 +1651857240000,36110.80,36110.80,36100.40,36102.30,113.499,1651857299999,4097927.16770,1040,73.733,2662119.69640,0 +1651857300000,36102.30,36127.10,36077.90,36077.90,176.786,1651857359999,6382409.21480,2208,77.457,2796779.34720,0 +1651857360000,36077.20,36094.90,36042.40,36092.70,510.463,1651857419999,18409759.06279,3806,120.874,4360166.77110,0 +1651857420000,36092.60,36107.80,36052.70,36068.30,148.026,1651857479999,5340531.26120,1725,53.761,1939638.14660,0 +1651857480000,36068.30,36068.30,36014.20,36032.90,274.778,1651857539999,9902490.98181,3268,114.983,4143977.86400,0 +1651857540000,36032.90,36062.40,36024.70,36056.60,217.185,1651857599999,7827576.73790,1994,141.527,5101064.34550,0 +1651857600000,36056.60,36056.60,35980.00,36041.40,496.972,1651857659999,17896412.90706,4768,183.017,6591484.33340,0 +1651857660000,36041.50,36092.00,36030.90,36072.90,121.206,1651857719999,4370252.01430,1887,81.354,2933431.72730,0 +1651857720000,36072.90,36072.90,36048.10,36058.00,75.127,1651857779999,2709122.11120,1281,42.438,1530346.16080,0 +1651857780000,36057.60,36154.50,36057.60,36086.20,317.056,1651857839999,11450057.85327,3542,212.895,7688562.04417,0 +1651857840000,36086.20,36113.20,36050.00,36050.10,184.567,1651857899999,6658303.50939,2124,83.133,2999363.51430,0 +1651857900000,36050.00,36082.50,36041.40,36057.30,116.331,1651857959999,4195311.22990,1550,50.002,1803179.96210,0 +1651857960000,36057.30,36057.30,36022.50,36040.60,161.041,1651858019999,5803876.64220,1699,69.359,2499752.04690,0 +1651858020000,36040.50,36091.00,36029.60,36091.00,106.420,1651858079999,3836659.01330,1346,70.047,2525268.23940,0 +1651858080000,36090.90,36121.00,36070.00,36077.70,171.393,1651858139999,6186868.77110,1881,82.286,2970386.76740,0 +1651858140000,36077.80,36083.10,36050.10,36078.40,103.065,1651858199999,3717341.96410,1348,52.989,1911131.71260,0 +1651858200000,36078.40,36099.60,36063.40,36099.50,323.307,1651858259999,11664956.74480,1578,248.062,8950015.55890,0 +1651858260000,36099.60,36109.60,36057.10,36069.60,127.458,1651858319999,4599490.91350,1747,55.977,2020246.50790,0 +1651858320000,36069.50,36069.60,36033.90,36041.40,141.845,1651858379999,5113316.27370,1559,72.701,2620664.66900,0 +1651858380000,36041.30,36053.20,36033.00,36050.60,116.570,1651858439999,4201791.98730,1384,58.423,2105830.80890,0 +1651858440000,36051.40,36063.70,36042.80,36051.90,100.716,1651858499999,3631186.08550,1293,33.568,1210338.92880,0 +1651858500000,36051.90,36086.80,36043.10,36084.60,80.811,1651858559999,2914992.87350,1192,45.958,1657821.98700,0 +1651858560000,36084.60,36106.80,36020.90,36046.00,283.015,1651858619999,10205575.07580,2348,112.221,4048135.25570,0 +1651858620000,36046.60,36050.50,35980.00,36000.10,366.379,1651858679999,13189271.61908,3638,94.179,3390145.14580,0 +1651858680000,36000.00,36021.80,35984.60,36004.40,160.639,1651858739999,5783156.32030,1763,82.851,2982872.85960,0 +1651858740000,36004.50,36022.00,36004.00,36008.20,102.458,1651858799999,3689638.87320,1212,60.575,2181387.15460,0 +1651858800000,36008.10,36083.20,36008.10,36044.50,345.389,1651858859999,12456636.46310,3353,251.173,9058766.68360,0 +1651858860000,36044.20,36063.90,35994.80,36004.10,216.805,1651858919999,7808604.78200,2251,68.408,2464434.88860,0 +1651858920000,36004.00,36022.70,35972.40,36007.20,348.328,1651858979999,12538836.57340,2907,113.679,4092400.59530,0 +1651858980000,36007.20,36049.90,36001.00,36003.00,176.080,1651859039999,6342798.62430,1943,109.627,3949055.46730,0 +1651859040000,36003.10,36018.70,35986.80,36004.70,129.984,1651859099999,4679232.35340,1561,69.887,2515898.46300,0 +1651859100000,36004.20,36035.80,36001.70,36009.40,139.197,1651859159999,5013187.82680,1620,79.917,2878193.56790,0 +1651859160000,36009.40,36017.00,35978.70,35987.50,211.143,1651859219999,7599719.69890,2418,87.910,3164214.75180,0 +1651859220000,35987.50,36020.90,35972.40,36001.00,143.586,1651859279999,5169291.19560,1691,82.533,2971487.41610,0 +1651859280000,36001.00,36023.90,35987.20,35988.40,107.791,1651859339999,3881328.46690,1599,55.934,2014122.42850,0 +1651859340000,35988.30,36014.10,35932.60,35959.90,985.273,1651859399999,35435537.88281,5263,217.130,7808174.68720,0 +1651859400000,35960.00,35968.20,35885.00,35914.90,599.110,1651859459999,21520550.74972,6147,181.649,6525945.15990,0 +1651859460000,35915.00,35945.80,35909.60,35923.20,339.478,1651859519999,12197104.86950,2837,205.981,7400891.27260,0 +1651859520000,35923.90,35933.90,35871.60,35907.70,459.968,1651859579999,16513547.77138,4191,150.074,5388704.85900,0 +1651859580000,35907.80,35907.80,35800.00,35872.30,1431.624,1651859639999,51329498.60515,9249,344.775,12359953.21740,0 +1651859640000,35872.30,35878.90,35820.80,35860.00,559.979,1651859699999,20075712.76670,3959,155.682,5582432.43020,0 +1651859700000,35860.00,35915.30,35846.10,35912.00,296.128,1651859759999,10623828.89780,3109,171.257,6144965.58090,0 +1651859760000,35912.00,35921.50,35868.50,35880.40,286.066,1651859819999,10265659.94850,2911,123.587,4435258.93540,0 +1651859820000,35880.30,35888.90,35863.90,35874.20,96.438,1651859879999,3459707.60200,1808,42.506,1524918.43760,0 +1651859880000,35874.20,35889.90,35870.40,35881.50,130.604,1651859939999,4686129.87130,1571,70.286,2521968.42500,0 +1651859940000,35881.90,35894.50,35850.00,35872.20,238.713,1651859999999,8562492.66630,2241,71.162,2553059.17440,0 +1651860000000,35872.20,35891.20,35845.30,35890.00,196.364,1651860059999,7043594.55120,2535,93.975,3371245.45340,0 +1651860060000,35890.10,35900.00,35878.90,35890.00,139.900,1651860119999,5021250.71120,1966,98.896,3549619.43530,0 +1651860120000,35889.90,35935.80,35886.00,35901.50,374.700,1651860179999,13456703.45670,3411,281.732,10118438.97790,0 +1651860180000,35901.50,35915.00,35870.00,35879.70,197.448,1651860239999,7086601.03330,2245,97.505,3499810.56170,0 +1651860240000,35879.80,35910.80,35850.90,35860.80,216.006,1651860299999,7752027.64690,2104,142.279,5106847.21820,0 +1651860300000,35860.70,35860.70,35822.20,35844.90,242.681,1651860359999,8697018.17130,2451,54.444,1951044.25110,0 +1651860360000,35844.80,35849.80,35827.10,35841.90,148.493,1651860419999,5321919.95500,1558,52.703,1888799.07140,0 +1651860420000,35841.90,35852.90,35825.60,35845.00,118.097,1651860479999,4232466.65400,1456,62.146,2227319.03340,0 +1651860480000,35845.10,35872.50,35845.00,35859.10,117.131,1651860539999,4200480.61280,1432,73.768,2645377.95870,0 +1651860540000,35859.10,35859.10,35831.00,35831.00,110.244,1651860599999,3951906.03780,1196,24.858,891122.98060,0 +1651860600000,35831.10,35870.60,35829.20,35867.20,106.094,1651860659999,3803321.44500,1500,63.857,2289244.94890,0 +1651860660000,35867.20,35912.10,35858.50,35901.60,371.360,1651860719999,13327158.35780,2496,287.073,10302285.17810,0 +1651860720000,35901.60,35923.70,35890.90,35897.50,260.398,1651860779999,9350297.43430,2355,184.306,6618224.13330,0 +1651860780000,35897.40,35913.60,35870.90,35870.90,322.586,1651860839999,11578639.16460,1202,129.622,4653561.65630,0 +1651860840000,35870.90,35891.30,35856.90,35888.80,202.446,1651860899999,7262411.28120,1360,54.855,1967947.26630,0 +1651860900000,35888.70,35960.10,35888.60,35950.20,485.728,1651860959999,17450915.17631,4054,371.960,13363672.21231,0 +1651860960000,35949.40,35949.40,35905.20,35907.50,122.287,1651861019999,4393578.93880,1600,62.752,2254598.44670,0 +1651861020000,35907.40,35970.60,35905.30,35936.40,148.084,1651861079999,5322111.26030,1947,109.566,3937969.01060,0 +1651861080000,35935.90,35963.60,35932.40,35950.70,151.631,1651861139999,5450332.52300,1778,97.319,3498181.00630,0 +1651861140000,35950.70,35965.50,35940.00,35947.20,127.424,1651861199999,4580815.98670,1409,69.096,2483890.12040,0 +1651861200000,35946.80,35946.80,35921.30,35930.20,104.612,1651861259999,3758911.93650,1427,62.194,2234684.83510,0 +1651861260000,35930.10,35937.40,35922.20,35922.30,69.223,1651861319999,2487137.66830,914,38.648,1388566.57600,0 +1651861320000,35922.30,35942.00,35917.40,35925.10,66.603,1651861379999,2392910.19050,1130,39.604,1422955.53570,0 +1651861380000,35925.10,35937.10,35898.20,35918.20,357.275,1651861439999,12830718.88140,2113,112.622,4044162.17030,0 +1651861440000,35918.20,35983.50,35911.30,35924.50,242.433,1651861499999,8716586.35980,2642,162.021,5825575.72990,0 +1651861500000,35924.60,35930.00,35880.70,35895.80,141.650,1651861559999,5086205.22330,1879,38.479,1381773.22090,0 +1651861560000,35895.80,35895.80,35866.70,35877.00,267.252,1651861619999,9588057.68490,1976,100.372,3600666.49300,0 +1651861620000,35877.00,35925.00,35875.30,35916.10,189.299,1651861679999,6796382.01130,2242,97.746,3509127.58970,0 +1651861680000,35916.50,35944.90,35899.30,35929.10,127.055,1651861739999,4564601.85230,1750,67.111,2411167.09670,0 +1651861740000,35929.10,35945.60,35907.80,35907.90,91.513,1651861799999,3288028.56960,1312,42.533,1528313.91330,0 +1651861800000,35907.80,35954.60,35894.90,35910.20,229.788,1651861859999,8253519.70460,2768,119.208,4281997.22830,0 +1651861860000,35910.90,35925.40,35889.50,35897.80,114.671,1651861919999,4117223.92520,1397,42.259,1517203.47720,0 +1651861920000,35897.70,35898.30,35841.40,35843.70,319.221,1651861979999,11447105.42529,2592,163.564,5864570.76800,0 +1651861980000,35843.80,35855.60,35801.10,35855.50,525.027,1651862039999,18808212.40070,3922,132.225,4737705.09030,0 +1651862040000,35855.50,35882.00,35846.90,35879.40,110.849,1651862099999,3975272.72190,1547,64.035,2296555.75550,0 +1651862100000,35879.40,35915.80,35863.20,35907.30,93.716,1651862159999,3363095.84970,1636,55.933,2007402.62300,0 +1651862160000,35907.20,35924.20,35887.80,35914.60,156.822,1651862219999,5631738.40350,1876,70.097,2516994.82070,0 +1651862220000,35914.50,35927.40,35903.90,35907.20,95.392,1651862279999,3426015.08150,1292,60.580,2175633.51390,0 +1651862280000,35907.20,35938.30,35906.10,35923.40,109.633,1651862339999,3938661.85440,1351,74.613,2680540.91770,0 +1651862340000,35923.30,35971.20,35911.60,35969.00,153.445,1651862399999,5514975.46481,1910,76.999,2767633.70161,0 +1651862400000,35967.50,35981.40,35951.10,35962.80,237.055,1651862459999,8526228.58680,2372,154.351,5551601.05590,0 +1651862460000,35962.70,35995.50,35957.10,35978.40,262.565,1651862519999,9446514.47520,2441,190.908,6868581.67740,0 +1651862520000,35978.50,35991.80,35961.40,35961.50,273.915,1651862579999,9854779.31850,1556,49.635,1785749.50540,0 +1651862580000,35961.40,35978.30,35953.00,35955.40,73.285,1651862639999,2635921.56130,1097,39.284,1412997.82450,0 +1651862640000,35955.40,35957.30,35935.60,35937.50,289.503,1651862699999,10407149.93960,1580,62.938,2262448.12470,0 +1651862700000,35937.40,35972.40,35933.60,35952.20,309.942,1651862759999,11144547.47560,1535,82.325,2960032.60160,0 +1651862760000,35952.30,35980.00,35943.50,35968.10,156.213,1651862819999,5616875.33530,1302,83.193,2991666.87030,0 +1651862820000,35968.00,35968.10,35921.20,35922.90,79.507,1651862879999,2857014.94270,1249,27.926,1003533.52440,0 +1651862880000,35922.30,35985.00,35920.00,35965.10,223.216,1651862939999,8024702.07220,1692,99.242,3568682.42100,0 +1651862940000,35965.10,36048.70,35965.10,36024.70,641.053,1651862999999,23093097.95985,5346,458.383,16512054.04945,0 +1651863000000,36023.50,36088.00,36017.00,36021.10,514.823,1651863059999,18564060.72936,4720,333.454,12024451.46716,0 +1651863060000,36021.00,36041.80,35983.30,35989.80,324.927,1651863119999,11699004.03880,2792,109.416,3939833.85370,0 +1651863120000,35989.80,36007.70,35971.80,35981.60,191.981,1651863179999,6909505.87180,1784,101.179,3641950.61580,0 +1651863180000,35982.40,36005.80,35975.00,36005.70,127.161,1651863239999,4576258.13000,1448,69.328,2495002.58190,0 +1651863240000,36005.70,36035.70,35998.50,36019.90,179.622,1651863299999,6469745.66070,1966,99.222,3573763.93420,0 +1651863300000,36020.20,36052.70,35980.50,35993.90,378.255,1651863359999,13624308.12350,2956,173.580,6255013.92320,0 +1651863360000,35993.90,36015.70,35975.00,35988.00,124.209,1651863419999,4470127.80930,1398,49.200,1770795.31950,0 +1651863420000,35988.00,36014.70,35979.90,35998.20,326.576,1651863479999,11753379.44540,2080,137.226,4938675.39600,0 +1651863480000,35998.20,36013.80,35981.90,35982.20,141.067,1651863539999,5078183.21600,1518,74.515,2682631.76480,0 +1651863540000,35982.30,35990.00,35913.60,35923.80,310.936,1651863599999,11176157.31127,2828,104.832,3767145.10970,0 +1651863600000,35923.90,35942.10,35883.40,35897.60,317.404,1651863659999,11396038.45273,3671,93.827,3369070.58460,0 +1651863660000,35897.70,35915.90,35877.80,35880.30,246.585,1651863719999,8850708.91850,2434,108.271,3886323.98300,0 +1651863720000,35880.30,35890.00,35856.80,35888.20,193.053,1651863779999,6925476.77610,2368,77.775,2790140.35470,0 +1651863780000,35888.10,35909.90,35888.10,35900.10,114.903,1651863839999,4124691.10000,1465,78.593,2821210.90070,0 +1651863840000,35900.10,35970.30,35900.10,35970.30,210.475,1651863899999,7565086.81611,2045,156.145,5612344.74911,0 +1651863900000,35970.20,36013.60,35934.80,35943.30,258.789,1651863959999,9311129.78068,2985,140.292,5048129.80308,0 +1651863960000,35943.20,35943.30,35883.20,35904.90,197.279,1651864019999,7084397.73470,2127,60.197,2161395.72050,0 +1651864020000,35904.90,35912.70,35897.80,35900.40,74.285,1651864079999,2667099.52100,975,39.523,1418962.09840,0 +1651864080000,35900.40,35909.90,35890.00,35906.00,107.607,1651864139999,3863413.43200,1344,55.717,2000384.08050,0 +1651864140000,35905.60,35912.70,35893.70,35903.80,224.316,1651864199999,8054225.64050,1267,43.684,1568358.35620,0 +1651864200000,35903.70,35956.40,35902.00,35916.70,245.356,1651864259999,8816300.46470,2261,185.001,6647554.48480,0 +1651864260000,35916.60,35943.60,35896.90,35929.20,99.110,1651864319999,3559803.82810,1392,51.676,1856263.48720,0 +1651864320000,35929.30,35971.60,35929.30,35960.20,100.780,1651864379999,3624046.76040,1242,54.868,1972973.65040,0 +1651864380000,35960.20,35977.40,35946.70,35969.30,118.901,1651864439999,4276325.32050,1314,69.497,2499517.82260,0 +1651864440000,35969.30,35974.40,35930.00,35931.80,117.588,1651864499999,4226548.86580,1224,33.027,1187182.58900,0 +1651864500000,35931.90,35945.80,35904.00,35908.10,73.418,1651864559999,2637681.63750,1119,36.466,1310070.80080,0 +1651864560000,35908.20,35917.60,35895.70,35904.10,182.813,1651864619999,6563597.14550,1211,76.964,2763100.61440,0 +1651864620000,35904.00,35923.60,35863.60,35875.00,333.730,1651864679999,11977461.16521,2347,64.017,2297910.96220,0 +1651864680000,35875.10,35915.50,35856.00,35902.50,260.397,1651864739999,9342698.17079,2287,112.660,4042396.63910,0 +1651864740000,35902.50,35963.50,35894.80,35926.00,191.195,1651864799999,6870192.91811,2215,131.149,4712745.96301,0 +1651864800000,35926.00,35928.20,35865.30,35865.50,159.000,1651864859999,5706784.37760,1927,66.210,2376420.97990,0 +1651864860000,35865.40,35882.80,35841.50,35882.70,312.565,1651864919999,11209128.85545,2577,190.860,6844813.16830,0 +1651864920000,35882.80,35899.30,35860.00,35867.30,94.047,1651864979999,3374007.55200,1378,44.771,1606200.50340,0 +1651864980000,35868.20,35875.20,35835.00,35845.80,350.777,1651865039999,12576616.50040,2105,77.052,2762566.95750,0 +1651865040000,35845.80,35858.00,35833.40,35855.00,144.740,1651865099999,5188475.38600,1409,77.826,2789990.60650,0 +1651865100000,35855.10,35869.00,35835.50,35840.70,150.852,1651865159999,5407735.63070,1679,90.461,3242724.88660,0 +1651865160000,35838.80,35883.00,35830.00,35879.10,142.539,1651865219999,5110265.33640,1421,93.098,3338134.44100,0 +1651865220000,35879.10,35942.80,35866.80,35935.60,208.322,1651865279999,7479271.71200,2029,171.961,6174325.44180,0 +1651865280000,35935.60,35972.10,35928.90,35961.20,324.535,1651865339999,11667211.59531,2879,219.545,7893063.90091,0 +1651865340000,35960.70,35969.30,35944.20,35951.60,119.334,1651865399999,4291052.73540,1548,56.619,2035912.86630,0 +1651865400000,35951.50,36007.10,35938.40,36007.00,424.525,1651865459999,15274934.82470,3641,307.251,11055970.01120,0 +1651865460000,36007.00,36025.00,36000.00,36004.70,220.357,1651865519999,7935589.64278,2708,103.719,3735307.35528,0 +1651865520000,36004.80,36020.00,35964.00,35982.00,220.087,1651865579999,7922516.45570,1903,50.254,1808813.45250,0 +1651865580000,35982.00,36015.00,35977.20,36003.00,137.913,1651865639999,4964880.63960,1476,84.501,3042114.62760,0 +1651865640000,36002.90,36026.90,36000.00,36022.40,203.843,1651865699999,7340980.74340,1792,131.226,4725817.72160,0 +1651865700000,36022.40,36067.00,36015.10,36060.20,340.127,1651865759999,12258992.22850,3794,221.393,7979323.89910,0 +1651865760000,36060.30,36069.10,36022.60,36030.50,142.176,1651865819999,5124740.26160,2025,64.973,2342206.31550,0 +1651865820000,36030.60,36069.00,36027.50,36050.90,157.877,1651865879999,5691295.75840,1579,97.014,3497341.02120,0 +1651865880000,36051.00,36134.10,36050.90,36100.00,511.402,1651865939999,18461010.78595,5174,378.581,13666520.70035,0 +1651865940000,36099.50,36116.00,35972.40,36043.90,1337.842,1651865999999,48219686.44380,8355,518.463,18688072.94620,0 +1651866000000,36043.90,36087.90,36034.80,36065.50,267.848,1651866059999,9659163.72720,3047,143.373,5170369.40120,0 +1651866060000,36064.50,36074.20,36038.00,36068.70,176.228,1651866119999,6353492.71610,1884,68.584,2472665.74670,0 +1651866120000,36070.00,36073.10,36050.00,36056.70,81.568,1651866179999,2941495.77210,1090,39.168,1412462.79220,0 +1651866180000,36056.80,36061.30,36029.00,36060.20,187.601,1651866239999,6761092.34830,1987,61.628,2220919.13940,0 +1651866240000,36060.20,36079.10,36034.70,36040.70,199.474,1651866299999,7192390.42540,1785,114.922,4144065.72570,0 +1651866300000,36040.80,36060.00,36016.00,36047.50,149.959,1651866359999,5403885.50910,1822,67.634,2437499.47370,0 +1651866360000,36047.50,36116.00,36047.40,36094.00,291.321,1651866419999,10513871.40300,2781,191.726,6919647.66270,0 +1651866420000,36096.00,36099.20,36070.00,36099.20,95.662,1651866479999,3452277.56300,1341,46.974,1695262.29920,0 +1651866480000,36099.20,36118.80,36093.30,36100.00,166.240,1651866539999,6002245.06400,1625,77.531,2799356.92000,0 +1651866540000,36100.10,36112.00,36072.30,36088.40,136.483,1651866599999,4926411.07140,1548,63.440,2289896.89140,0 +1651866600000,36088.30,36135.10,36088.30,36110.00,284.050,1651866659999,10258598.51160,2545,204.467,7384399.50180,0 +1651866660000,36110.10,36110.10,36070.30,36075.00,160.855,1651866719999,5805116.43300,1604,83.660,3018947.16430,0 +1651866720000,36075.00,36087.00,36059.10,36072.10,108.725,1651866779999,3921899.42370,1214,53.430,1927328.92750,0 +1651866780000,36072.20,36083.70,36063.00,36071.40,64.427,1651866839999,2324039.60180,947,20.896,753813.79720,0 +1651866840000,36071.40,36092.00,36063.00,36068.00,199.205,1651866899999,7186145.25360,1803,87.044,3139992.05490,0 +1651866900000,36068.00,36072.10,36018.30,36042.20,227.899,1651866959999,8213832.64650,2241,87.005,3135811.86730,0 +1651866960000,36042.10,36049.00,35919.10,35942.60,1531.381,1651867019999,55075069.35847,6990,689.529,24790691.96760,0 +1651867020000,35942.60,35969.90,35909.50,35969.90,266.522,1651867079999,9578963.79800,2525,135.162,4858833.82110,0 +1651867080000,35969.90,35993.10,35963.00,35974.40,123.956,1651867139999,4459490.48170,1539,49.062,1765133.51540,0 +1651867140000,35974.50,36006.10,35957.80,35980.30,297.137,1651867199999,10691195.42610,2636,170.583,6137756.36410,0 +1651867200000,35981.50,35989.00,35922.50,35922.50,348.671,1651867259999,12533117.54880,2737,97.791,3515081.29290,0 +1651867260000,35922.20,35955.80,35920.00,35947.60,122.656,1651867319999,4408160.37870,1448,76.942,2765314.43690,0 +1651867320000,35947.70,35950.10,35921.00,35937.00,113.331,1651867379999,4072715.38420,1200,69.828,2509454.68980,0 +1651867380000,35937.00,35940.30,35907.60,35919.90,115.385,1651867439999,4144243.12100,1409,43.431,1559895.89740,0 +1651867440000,35920.00,35920.00,35886.00,35889.10,266.430,1651867499999,9565048.28143,2056,71.573,2569537.70510,0 +1651867500000,35889.10,35924.90,35888.20,35909.40,118.052,1651867559999,4238899.95430,1316,91.792,3295868.86780,0 +1651867560000,35909.30,35913.70,35900.50,35911.30,68.023,1651867619999,2442315.35370,1016,35.342,1268901.66060,0 +1651867620000,35911.30,35937.20,35898.60,35936.70,128.044,1651867679999,4598577.36070,1260,70.072,2517065.87170,0 +1651867680000,35936.80,35952.30,35926.10,35928.00,197.123,1651867739999,7084963.56200,1715,127.503,4582885.31410,0 +1651867740000,35928.00,35939.80,35922.20,35933.30,75.755,1651867799999,2721890.35480,771,26.773,961972.39990,0 +1651867800000,35933.40,35934.60,35924.80,35928.20,73.488,1651867859999,2640421.93300,746,36.326,1305195.46810,0 +1651867860000,35928.20,35943.10,35928.00,35941.20,44.565,1651867919999,1601324.33390,553,30.480,1095228.13280,0 +1651867920000,35941.30,35954.10,35941.20,35945.40,88.678,1651867979999,3187668.47020,972,58.109,2088815.36270,0 +1651867980000,35945.40,35945.40,35922.50,35922.60,64.533,1651868039999,2318641.98780,667,13.168,473109.81840,0 +1651868040000,35922.60,35922.70,35877.60,35890.00,195.326,1651868099999,7010358.76210,1985,51.091,1833597.59820,0 +1651868100000,35889.90,35908.60,35886.00,35891.80,260.825,1651868159999,9361470.49210,1317,230.122,8259319.57370,0 +1651868160000,35891.80,35891.90,35861.10,35862.70,131.805,1651868219999,4728114.71413,1592,36.394,1305485.46020,0 +1651868220000,35862.60,35879.80,35852.00,35873.30,157.943,1651868279999,5664686.02965,1721,80.848,2899983.49680,0 +1651868280000,35873.30,35876.70,35854.30,35862.00,80.523,1651868339999,2887764.87550,1080,29.087,1043144.20460,0 +1651868340000,35862.10,35871.70,35851.00,35853.00,73.509,1651868399999,2636021.36060,1018,34.887,1251070.44370,0 +1651868400000,35853.10,35860.90,35848.20,35848.20,110.748,1651868459999,3970792.24332,1414,66.002,2366508.00290,0 +1651868460000,35848.20,35879.80,35845.70,35864.50,131.133,1651868519999,4702844.27260,1429,93.347,3347855.96330,0 +1651868520000,35864.60,35892.10,35864.60,35873.60,154.850,1651868579999,5556189.05750,1197,117.952,4232282.60440,0 +1651868580000,35873.60,35887.40,35867.00,35882.90,81.664,1651868639999,2929847.99970,838,51.201,1836934.87090,0 +1651868640000,35883.00,35887.50,35875.70,35875.70,39.394,1651868699999,1413472.82050,565,17.797,638569.94580,0 +1651868700000,35875.80,35882.40,35875.40,35881.80,53.182,1651868759999,1908124.15810,694,38.901,1395716.69080,0 +1651868760000,35881.90,35890.10,35881.80,35890.00,45.325,1651868819999,1626581.84900,698,30.568,1096988.42800,0 +1651868820000,35890.10,35907.70,35887.50,35887.60,104.693,1651868879999,3758252.39460,1174,62.048,2227345.80160,0 +1651868880000,35887.60,35888.80,35882.60,35882.70,20.922,1651868939999,750784.55830,393,7.953,285397.28900,0 +1651868940000,35882.70,35882.70,35881.90,35882.00,30.664,1651868999999,1100295.83650,360,21.466,770249.81900,0 +1651869000000,35882.00,35882.00,35860.00,35877.10,130.116,1651869059999,4667367.90530,1018,52.550,1885088.89450,0 +1651869060000,35877.10,35878.80,35865.20,35865.30,27.622,1651869119999,990833.28690,572,13.052,468202.07430,0 +1651869120000,35865.20,35875.30,35843.80,35874.60,137.068,1651869179999,4914714.68910,1316,51.910,1861594.38200,0 +1651869180000,35874.70,35889.40,35871.40,35889.40,90.806,1651869239999,3258292.90970,967,51.886,1861754.49380,0 +1651869240000,35889.40,35918.30,35885.30,35894.10,176.535,1651869299999,6338087.54220,1674,135.372,4860273.19100,0 +1651869300000,35894.00,35894.10,35877.50,35882.80,58.189,1651869359999,2088124.71760,728,18.109,649813.51110,0 +1651869360000,35882.70,35882.80,35858.50,35869.60,56.526,1651869419999,2027432.32240,691,16.081,576807.98560,0 +1651869420000,35869.70,35908.50,35869.60,35908.50,37.010,1651869479999,1328169.37570,818,24.078,864114.15960,0 +1651869480000,35908.40,35928.60,35904.40,35909.90,95.677,1651869539999,3436665.51400,1089,54.501,1957659.51300,0 +1651869540000,35910.00,35910.00,35904.00,35907.20,42.459,1651869599999,1524635.34270,580,25.448,913795.60380,0 +1651869600000,35907.10,35922.10,35901.00,35921.70,47.722,1651869659999,1713804.75040,691,24.643,885037.53660,0 +1651869660000,35921.70,35950.60,35920.80,35943.40,236.213,1651869719999,8489105.47410,1738,190.018,6828836.20900,0 +1651869720000,35943.40,35951.50,35930.80,35939.50,93.240,1651869779999,3351202.09160,944,60.411,2171349.81670,0 +1651869780000,35939.50,35954.80,35938.30,35954.70,67.797,1651869839999,2437101.21130,872,47.323,1701145.24550,0 +1651869840000,35954.80,35958.00,35945.70,35945.70,43.571,1651869899999,1566517.32710,692,21.095,758455.73430,0 +1651869900000,35945.70,35972.40,35937.50,35972.30,96.505,1651869959999,3469357.64991,1109,40.946,1472271.69471,0 +1651869960000,35972.40,36018.00,35972.30,36006.00,311.711,1651870019999,11221627.72598,2859,216.914,7808762.73848,0 +1651870020000,36005.90,36018.00,35992.90,36009.90,79.988,1651870079999,2879943.64880,1173,29.084,1047202.08530,0 +1651870080000,36010.00,36019.70,36009.90,36018.10,80.516,1651870139999,2899950.80410,1074,42.501,1530745.85860,0 +1651870140000,36018.10,36029.70,36009.20,36015.60,94.925,1651870199999,3418952.18310,1144,37.702,1357970.37580,0 +1651870200000,36015.60,36027.30,36002.70,36026.80,104.376,1651870259999,3758677.28210,1429,46.590,1677869.91290,0 +1651870260000,36026.70,36050.70,36020.20,36050.30,203.037,1651870319999,7317531.39541,1952,153.340,5526485.68591,0 +1651870320000,36050.40,36068.80,36050.30,36056.00,111.752,1651870379999,4029467.75379,1619,53.729,1937329.45119,0 +1651870380000,36056.10,36076.60,36043.40,36056.50,119.187,1651870439999,4297949.01540,1642,44.446,1602898.34500,0 +1651870440000,36056.50,36092.70,36056.50,36092.60,145.714,1651870499999,5256234.17761,1609,88.831,3204478.47291,0 +1651870500000,36092.60,36098.70,36045.70,36075.90,225.661,1651870559999,8140254.93898,2327,72.395,2611853.08558,0 +1651870560000,36075.90,36086.40,36068.10,36074.00,71.291,1651870619999,2572059.27290,1185,17.454,629727.34100,0 +1651870620000,36074.00,36087.10,36058.70,36068.40,92.057,1651870679999,3320682.71290,1145,29.471,1063018.20740,0 +1651870680000,36068.40,36069.10,36040.20,36041.90,87.697,1651870739999,3162022.08040,1166,28.451,1025799.13150,0 +1651870740000,36041.90,36060.00,36040.40,36059.70,98.363,1651870799999,3546055.93030,926,57.215,2062650.60740,0 +1651870800000,36059.70,36079.80,36059.70,36079.70,53.517,1651870859999,1930479.88760,734,22.051,795402.97020,0 +1651870860000,36079.70,36084.20,36051.70,36051.70,70.851,1651870919999,2555756.09310,1132,25.517,920431.69940,0 +1651870920000,36051.00,36060.00,36039.80,36039.90,105.271,1651870979999,3794845.17070,1289,33.914,1222531.95090,0 +1651870980000,36039.80,36050.00,36029.80,36049.90,103.073,1651871039999,3714713.99240,1049,40.158,1447374.95230,0 +1651871040000,36049.90,36067.20,36049.90,36061.10,62.725,1651871099999,2261876.97870,818,24.953,899775.36750,0 +1651871100000,36061.10,36063.90,35987.00,35998.00,521.501,1651871159999,18779858.68940,3193,110.762,3987898.43750,0 +1651871160000,35998.00,36000.10,35970.20,35997.10,140.949,1651871219999,5072019.34880,1489,50.097,1802776.25600,0 +1651871220000,35997.10,36013.50,35997.00,36005.20,68.048,1651871279999,2450072.89730,800,35.949,1294323.18660,0 +1651871280000,36005.20,36011.00,36005.10,36005.20,34.310,1651871339999,1235438.32030,519,17.830,642016.48280,0 +1651871340000,36005.20,36019.70,36000.90,36012.80,86.939,1651871399999,3130615.61440,1027,52.599,1894041.62180,0 +1651871400000,36012.80,36012.80,36003.60,36012.70,24.227,1651871459999,872409.38680,457,9.219,331969.78450,0 +1651871460000,36012.80,36012.90,36003.60,36003.70,24.583,1651871519999,885255.13650,457,4.295,154668.92920,0 +1651871520000,36003.60,36008.80,36001.00,36007.50,26.976,1651871579999,971290.48560,563,11.061,398257.95240,0 +1651871580000,36007.40,36007.50,35979.00,35988.00,107.897,1651871639999,3883353.54160,1050,13.451,484090.41350,0 +1651871640000,35987.90,35999.40,35981.80,35993.80,103.815,1651871699999,3736443.56270,1098,72.889,2623422.13880,0 +1651871700000,35993.90,35993.90,35976.10,35980.10,36.352,1651871759999,1308029.17960,826,12.448,447915.58730,0 +1651871760000,35980.00,35980.10,35959.20,35968.50,157.560,1651871819999,5667247.24220,1390,39.768,1430362.01590,0 +1651871820000,35968.50,35979.60,35968.40,35977.00,32.058,1651871879999,1153312.37900,613,25.622,921770.83700,0 +1651871880000,35977.00,35986.30,35975.30,35986.30,27.409,1651871939999,986177.37160,498,22.556,811566.85280,0 +1651871940000,35986.20,35993.20,35986.20,35990.20,35.922,1651871999999,1292832.73110,662,19.595,705221.35150,0 +1651872000000,35990.10,35990.10,35984.90,35989.90,23.631,1651872059999,850426.35140,456,9.394,338065.08860,0 +1651872060000,35990.00,35992.50,35984.90,35989.90,26.530,1651872119999,954812.99870,546,11.349,408455.00840,0 +1651872120000,35990.00,36012.80,35989.90,36009.30,85.713,1651872179999,3085993.11590,1121,54.966,1979009.98210,0 +1651872180000,36009.30,36024.90,36005.80,36024.90,57.930,1651872239999,2086551.79410,1011,43.839,1579056.77210,0 +1651872240000,36024.90,36034.40,36020.00,36025.10,50.858,1651872299999,1832363.10160,855,37.354,1345844.31040,0 +1651872300000,36025.00,36025.10,35999.90,36010.40,55.404,1651872359999,1994976.52950,752,21.908,788764.24100,0 +1651872360000,36010.40,36017.50,36010.40,36013.70,27.693,1651872419999,997319.99130,516,15.411,555010.03900,0 +1651872420000,36013.70,36016.00,36010.30,36011.20,26.406,1651872479999,950971.50150,532,10.876,391679.06130,0 +1651872480000,36011.10,36019.40,36005.00,36016.60,74.479,1651872539999,2681940.48850,900,15.789,568622.68440,0 +1651872540000,36016.70,36049.00,36016.60,36045.00,118.914,1651872599999,4285187.66710,1132,103.057,3713774.34530,0 +1651872600000,36044.90,36051.90,36037.10,36051.90,90.427,1651872659999,3259539.17390,1094,63.931,2304553.26460,0 +1651872660000,36051.90,36060.40,36030.70,36033.80,129.265,1651872719999,4659747.46360,1315,44.297,1597020.70760,0 +1651872720000,36033.80,36036.40,36024.60,36028.30,51.064,1651872779999,1839916.27420,762,18.213,656260.85150,0 +1651872780000,36028.20,36028.20,36020.90,36021.00,28.291,1651872839999,1019151.11890,543,6.639,239167.31890,0 +1651872840000,36020.90,36021.00,36005.00,36005.10,90.858,1651872899999,3271651.88090,670,14.820,533740.88440,0 +1651872900000,36005.10,36005.10,35956.20,35960.40,221.102,1651872959999,7955636.49131,2015,40.753,1466165.03030,0 +1651872960000,35960.40,35960.40,35946.20,35958.30,104.604,1651873019999,3760825.92080,1571,54.565,1961837.35460,0 +1651873020000,35958.20,35964.60,35951.30,35957.00,43.827,1651873079999,1575999.59860,853,32.462,1167333.76750,0 +1651873080000,35957.10,35957.10,35951.50,35953.10,18.269,1651873139999,656876.84880,500,8.261,297034.48320,0 +1651873140000,35953.00,35964.60,35953.00,35957.50,58.625,1651873199999,2108055.87280,951,32.107,1154525.24490,0 +1651873200000,35957.60,35960.00,35942.10,35950.30,89.649,1651873259999,3222732.91270,1039,18.181,653580.69460,0 +1651873260000,35949.10,35949.10,35915.50,35932.90,148.458,1651873319999,5334033.33396,1813,41.216,1480878.53290,0 +1651873320000,35932.90,35933.90,35913.00,35919.40,93.210,1651873379999,3348095.36590,1080,28.840,1035943.36060,0 +1651873380000,35919.40,35964.60,35916.00,35951.10,112.772,1651873439999,4053320.79460,1437,83.335,2995205.59540,0 +1651873440000,35951.10,35959.50,35906.60,35909.10,103.723,1651873499999,3726857.13960,1419,25.970,933157.76310,0 +1651873500000,35909.10,35949.60,35908.90,35939.60,98.331,1651873559999,3533511.97220,1190,79.684,2863401.80400,0 +1651873560000,35938.60,35938.60,35879.80,35894.60,187.020,1651873619999,6714053.59713,2122,43.690,1568366.96760,0 +1651873620000,35894.60,35911.80,35879.70,35900.00,68.128,1651873679999,2445487.96690,1209,34.135,1225418.05300,0 +1651873680000,35900.00,35916.40,35900.00,35902.60,68.741,1651873739999,2468363.51360,890,51.151,1836760.02910,0 +1651873740000,35904.40,35915.60,35904.40,35910.10,37.427,1651873799999,1344035.81670,716,21.666,778048.71570,0 +1651873800000,35910.10,35910.10,35900.00,35900.10,33.161,1651873859999,1190585.24880,470,14.393,516755.93650,0 +1651873860000,35900.00,35900.10,35900.00,35900.10,22.967,1651873919999,824516.35970,390,10.597,380433.35970,0 +1651873920000,35900.10,35949.60,35880.10,35949.60,104.336,1651873979999,3746357.66220,1465,69.944,2511858.27050,0 +1651873980000,35949.60,35956.00,35911.40,35911.40,87.822,1651874039999,3156424.16720,1207,43.550,1565475.88190,0 +1651874040000,35911.30,35932.80,35904.90,35932.80,54.527,1651874099999,1958481.36410,778,34.849,1251709.95240,0 +1651874100000,35932.80,35950.50,35915.70,35920.70,70.223,1651874159999,2523412.34900,840,36.260,1302870.89350,0 +1651874160000,35920.80,35934.70,35916.80,35934.70,46.798,1651874219999,1681347.78970,657,27.767,997609.63580,0 +1651874220000,35934.70,35949.00,35934.60,35949.00,42.195,1651874279999,1516441.03950,667,28.951,1040476.20800,0 +1651874280000,35949.00,35949.00,35943.30,35943.30,46.468,1651874339999,1670435.51030,365,17.720,636994.05130,0 +1651874340000,35943.40,35943.40,35934.00,35935.30,31.486,1651874399999,1131643.39730,399,14.944,537105.82900,0 +1651874400000,35935.40,35935.40,35930.00,35932.60,34.861,1651874459999,1252653.16920,536,13.234,475534.36420,0 +1651874460000,35932.60,35974.20,35929.10,35974.20,78.059,1651874519999,2807057.91140,918,59.950,2155952.18500,0 +1651874520000,35974.10,35974.10,35952.00,35952.60,55.555,1651874579999,1997975.41040,660,20.106,723125.09000,0 +1651874580000,35952.50,35963.80,35946.50,35953.10,51.673,1651874639999,1857905.49860,690,24.697,888014.09630,0 +1651874640000,35953.10,35965.00,35953.00,35955.10,35.694,1651874699999,1283579.07960,565,21.752,782214.14920,0 +1651874700000,35955.20,35981.10,35955.10,35981.10,47.009,1651874759999,1691060.16480,632,33.836,1217176.87260,0 +1651874760000,35981.10,35981.10,35956.00,35957.60,72.174,1651874819999,2596221.75640,712,20.319,730938.19920,0 +1651874820000,35957.60,35972.60,35957.50,35972.50,21.483,1651874879999,772680.64650,358,14.506,521728.71680,0 +1651874880000,35972.50,35972.50,35960.30,35971.10,19.600,1651874939999,704933.08310,460,8.731,314018.34780,0 +1651874940000,35971.20,35979.90,35963.60,35964.50,39.293,1651874999999,1413600.60810,558,19.768,711168.47660,0 +1651875000000,35964.60,35967.20,35882.10,35899.50,307.803,1651875059999,11055269.79910,2316,33.344,1197743.08070,0 +1651875060000,35899.50,35912.60,35877.00,35877.10,106.515,1651875119999,3823003.43410,1351,42.286,1517786.35960,0 +1651875120000,35877.10,35895.10,35870.60,35884.20,90.086,1651875179999,3232190.23430,1419,47.771,1714021.37810,0 +1651875180000,35884.10,35892.20,35859.30,35867.90,144.658,1651875239999,5189848.30860,1472,35.731,1282016.46010,0 +1651875240000,35867.90,35873.20,35851.00,35860.80,96.265,1651875299999,3452345.55656,1469,38.796,1391405.55220,0 +1651875300000,35860.70,35883.40,35860.00,35877.60,73.274,1651875359999,2628621.62710,860,59.504,2134633.10270,0 +1651875360000,35877.70,35942.80,35877.60,35918.60,143.112,1651875419999,5139606.26820,1674,99.039,3556493.61650,0 +1651875420000,35918.50,35918.60,35890.20,35890.20,36.433,1651875479999,1308122.51730,612,15.491,556193.62880,0 +1651875480000,35890.20,35897.30,35876.00,35886.50,49.357,1651875539999,1771242.33990,776,29.711,1066196.46590,0 +1651875540000,35886.50,35895.90,35886.50,35886.60,27.190,1651875599999,975905.83920,406,10.782,386979.22820,0 +1651875600000,35886.50,35916.40,35886.40,35916.30,36.046,1651875659999,1294094.86320,730,24.226,869734.50140,0 +1651875660000,35916.30,35939.80,35912.70,35922.50,49.363,1651875719999,1773317.34670,864,15.785,567072.82100,0 +1651875720000,35922.60,35930.00,35908.90,35929.90,42.187,1651875779999,1515316.12790,614,26.127,938476.04770,0 +1651875780000,35930.00,35949.90,35929.90,35937.60,70.686,1651875839999,2540575.11870,704,51.978,1868194.12580,0 +1651875840000,35938.60,35947.80,35925.10,35942.30,46.766,1651875899999,1680667.03110,938,15.955,573355.00340,0 +1651875900000,35942.30,35943.40,35920.80,35927.10,59.453,1651875959999,2136257.04700,698,14.743,529712.63630,0 +1651875960000,35927.10,35929.30,35911.00,35914.70,36.260,1651876019999,1302529.52060,514,20.499,736326.64270,0 +1651876020000,35914.60,35925.80,35893.30,35900.50,68.690,1651876079999,2466442.48800,735,26.853,964167.53630,0 +1651876080000,35900.60,35900.60,35871.30,35889.50,59.873,1651876139999,2148492.51270,781,25.504,915229.30910,0 +1651876140000,35889.50,35900.00,35880.00,35898.10,36.647,1651876199999,1315187.79530,549,16.004,574304.16750,0 +1651876200000,35898.00,35901.90,35884.10,35887.00,33.339,1651876259999,1196580.29730,565,16.442,590110.08210,0 +1651876260000,35885.40,35900.00,35885.40,35900.00,75.926,1651876319999,2725233.81110,608,63.058,2263363.24960,0 +1651876320000,35899.90,35946.30,35899.90,35935.00,212.869,1651876379999,7644330.85400,1466,184.814,6636267.20210,0 +1651876380000,35934.90,35937.00,35920.60,35924.10,58.888,1651876439999,2115926.42930,565,10.545,378925.58920,0 +1651876440000,35924.00,35943.60,35924.00,35938.30,52.149,1651876499999,1874154.20860,619,37.647,1352971.27620,0 +1651876500000,35938.40,35942.10,35921.30,35934.00,143.945,1651876559999,5172827.83200,869,62.190,2234753.56050,0 +1651876560000,35934.00,35934.10,35884.60,35917.20,85.442,1651876619999,3068163.92870,1190,34.295,1231414.08360,0 +1651876620000,35917.30,35920.70,35880.00,35880.10,28.565,1651876679999,1025407.54600,569,6.962,249941.45510,0 +1651876680000,35880.10,35917.30,35858.60,35907.00,184.827,1651876739999,6631794.91630,2045,88.189,3164384.50200,0 +1651876740000,35907.00,35949.10,35907.00,35935.60,102.577,1651876799999,3686256.38440,1012,42.555,1529196.04130,0 +1651876800000,35935.70,35940.00,35930.70,35932.70,29.000,1651876859999,1042164.59720,541,5.505,197835.19430,0 +1651876860000,35932.70,35951.50,35930.70,35948.80,91.139,1651876919999,3275929.76900,997,57.876,2080356.81090,0 +1651876920000,35948.90,35959.90,35938.30,35959.90,63.066,1651876979999,2267172.30651,608,47.010,1690045.83171,0 +1651876980000,35959.90,35961.60,35946.70,35948.30,128.385,1651877039999,4615827.45210,916,26.784,962959.03080,0 +1651877040000,35948.20,35965.00,35948.20,35959.90,37.183,1651877099999,1337059.31360,476,20.601,740753.31000,0 +1651877100000,35959.90,35973.00,35956.90,35973.00,71.584,1651877159999,2574539.35390,624,56.610,2035969.69160,0 +1651877160000,35973.00,35973.00,35944.30,35948.60,293.296,1651877219999,10546462.95760,1481,148.827,5351417.79040,0 +1651877220000,35948.70,35957.50,35945.00,35948.70,64.394,1651877279999,2315168.45620,589,16.133,580025.55220,0 +1651877280000,35948.70,35979.00,35948.60,35978.90,53.126,1651877339999,1910676.43390,689,36.712,1320386.48190,0 +1651877340000,35979.00,36050.00,35973.10,36046.60,867.121,1651877399999,31234497.43239,3953,587.335,21153461.57369,0 +1651877400000,36045.90,36046.60,36007.50,36015.70,173.422,1651877459999,6247671.95090,1996,82.872,2985507.45560,0 +1651877460000,36015.80,36031.80,36013.20,36028.70,112.871,1651877519999,4065783.71870,1015,72.312,2604837.12930,0 +1651877520000,36028.10,36033.90,36012.50,36019.90,42.502,1651877579999,1530969.14190,794,13.078,471104.21050,0 +1651877580000,36020.00,36029.00,35983.00,35990.60,308.336,1651877639999,11100853.47610,1710,56.692,2040974.91500,0 +1651877640000,35990.60,36025.60,35984.90,36020.50,60.059,1651877699999,2162659.16780,707,32.843,1182537.10160,0 +1651877700000,36020.50,36020.50,36006.00,36014.90,58.352,1651877759999,2101387.61950,654,28.911,1041130.35790,0 +1651877760000,36015.00,36022.50,36014.90,36015.00,34.210,1651877819999,1232213.40990,479,21.898,788739.29470,0 +1651877820000,36015.00,36020.00,36006.90,36020.00,88.336,1651877879999,3181421.25650,669,64.833,2335041.13560,0 +1651877880000,36019.90,36020.00,35986.60,36006.70,192.941,1651877939999,6946308.79270,1384,26.406,950785.60370,0 +1651877940000,36006.70,36009.90,35961.30,35974.50,216.528,1651877999999,7790682.53510,1442,31.285,1125770.65040,0 +1651878000000,35974.40,35986.30,35971.50,35986.20,51.686,1651878059999,1859551.51550,779,31.708,1140798.30610,0 +1651878060000,35986.20,36008.20,35986.20,36005.60,62.489,1651878119999,2249586.62750,882,32.332,1163972.59640,0 +1651878120000,36005.60,36010.00,35998.20,35998.30,51.923,1651878179999,1869574.30530,592,27.438,987976.68240,0 +1651878180000,35998.20,35999.80,35993.20,35999.80,30.042,1651878239999,1081421.05080,361,19.912,716768.97070,0 +1651878240000,35999.70,36017.50,35999.70,36008.40,130.896,1651878299999,4713553.54600,667,111.793,4025626.60650,0 +1651878300000,36008.40,36012.00,36003.90,36011.60,25.443,1651878359999,916166.01890,461,9.095,327494.90540,0 +1651878360000,36011.60,36036.90,36011.50,36029.10,77.496,1651878419999,2791954.59010,786,53.812,1938605.43780,0 +1651878420000,36029.10,36029.10,35988.00,35988.00,63.918,1651878479999,2301050.18580,965,12.994,467788.70110,0 +1651878480000,35988.00,36001.60,35982.50,35992.70,47.502,1651878539999,1709673.87230,613,25.012,900170.57010,0 +1651878540000,35992.70,36032.60,35992.70,36029.90,144.595,1651878599999,5208372.65470,956,127.073,4577348.13240,0 +1651878600000,36029.80,36029.80,36003.80,36005.50,67.923,1651878659999,2446363.93380,730,16.425,591558.21860,0 +1651878660000,36005.60,36020.60,36005.50,36020.50,30.520,1651878719999,1099190.53040,431,16.470,593170.91960,0 +1651878720000,36020.60,36037.80,36020.50,36035.00,70.161,1651878779999,2528007.96070,852,52.668,1897772.11330,0 +1651878780000,36035.20,36044.20,36014.30,36024.60,97.952,1651878839999,3529490.78340,1117,54.079,1948635.69450,0 +1651878840000,36024.60,36072.60,36024.50,36041.60,738.761,1651878899999,26631110.96429,2762,362.384,13062557.99049,0 +1651878900000,36041.60,36092.80,36034.00,36092.80,216.960,1651878959999,7822603.47171,1890,101.143,3647156.94841,0 +1651878960000,36089.90,36099.00,36044.40,36047.50,85.213,1651879019999,3073868.68490,1483,40.723,1469033.91170,0 +1651879020000,36047.50,36064.50,36047.50,36062.70,78.711,1651879079999,2838202.25100,840,43.755,1577703.49390,0 +1651879080000,36062.70,36065.20,36051.70,36057.00,31.234,1651879139999,1126217.56010,508,9.712,350185.02240,0 +1651879140000,36057.00,36059.60,36051.30,36058.20,36.424,1651879199999,1313365.22390,471,15.579,561751.67990,0 +1651879200000,36058.20,36073.80,36049.00,36073.30,79.773,1651879259999,2876475.88120,810,22.455,809737.24870,0 +1651879260000,36073.20,36088.90,36062.00,36064.80,66.598,1651879319999,2402578.99000,814,36.401,1313221.98850,0 +1651879320000,36064.90,36080.00,36064.80,36071.40,47.448,1651879379999,1711621.56120,683,15.122,545489.80700,0 +1651879380000,36071.30,36079.20,36061.50,36079.20,75.507,1651879439999,2723300.94560,805,29.967,1080844.95490,0 +1651879440000,36079.20,36079.20,36061.50,36072.00,34.538,1651879499999,1245797.98360,625,16.432,592691.48800,0 +1651879500000,36072.00,36078.00,36062.20,36065.60,136.986,1651879559999,4941159.43720,788,22.349,806113.09110,0 +1651879560000,36065.60,36096.40,36065.60,36079.60,186.435,1651879619999,6727365.76100,1141,141.146,5093262.01290,0 +1651879620000,36079.60,36080.00,36068.60,36068.70,24.674,1651879679999,890110.92260,490,9.707,350178.92300,0 +1651879680000,36068.60,36068.70,36065.50,36068.40,30.218,1651879739999,1089884.05390,413,7.089,255675.83070,0 +1651879740000,36068.30,36072.40,36067.80,36068.70,21.274,1651879799999,767344.42830,384,8.867,319831.97120,0 +1651879800000,36068.70,36069.90,36054.30,36057.30,134.721,1651879859999,4858654.24160,801,10.532,379801.26980,0 +1651879860000,36057.30,36074.40,36057.30,36068.90,43.854,1651879919999,1581758.19160,746,21.050,759227.12010,0 +1651879920000,36069.00,36069.00,36043.90,36044.00,182.845,1651879979999,6591579.12610,1098,39.550,1425659.41390,0 +1651879980000,36043.90,36044.00,36031.00,36038.10,103.143,1651880039999,3716904.83180,1282,51.551,1857683.37140,0 +1651880040000,36038.70,36040.20,36032.70,36032.70,130.875,1651880099999,4716082.09670,750,43.974,1584656.68010,0 +1651880100000,36032.70,36039.70,36012.60,36039.70,156.672,1651880159999,5644301.74770,1171,50.658,1824992.21120,0 +1651880160000,36039.70,36045.30,36024.80,36039.90,48.925,1651880219999,1763191.20710,689,23.532,848052.66940,0 +1651880220000,36040.00,36047.50,36039.90,36041.80,45.978,1651880279999,1657250.00050,492,22.666,816959.85470,0 +1651880280000,36041.80,36042.90,36041.00,36042.90,24.023,1651880339999,865829.85350,316,13.722,494565.63370,0 +1651880340000,36042.90,36048.00,36042.80,36047.90,19.601,1651880399999,706541.68440,328,13.062,470837.25400,0 +1651880400000,36048.00,36048.20,36028.10,36037.90,52.340,1651880459999,1886237.30550,687,10.001,360400.44770,0 +1651880460000,36037.80,36045.70,36037.80,36043.30,37.458,1651880519999,1350033.25030,405,14.573,525230.56550,0 +1651880520000,36043.40,36049.40,36041.50,36049.10,30.642,1651880579999,1104509.65810,585,17.432,628353.22170,0 +1651880580000,36049.00,36069.90,36048.50,36067.30,62.526,1651880639999,2254658.84740,671,51.352,1851822.25060,0 +1651880640000,36067.40,36067.40,36050.50,36059.60,59.918,1651880699999,2160600.85320,717,27.937,1007437.32790,0 +1651880700000,36059.70,36066.70,36012.00,36020.30,97.637,1651880759999,3517418.72250,1258,31.209,1124271.46540,0 +1651880760000,36020.30,36020.30,36000.00,36010.40,98.352,1651880819999,3541530.25550,1122,31.161,1122089.66820,0 +1651880820000,36010.30,36015.30,36002.60,36012.70,39.599,1651880879999,1425970.42100,602,15.757,567417.54950,0 +1651880880000,36012.70,36018.40,36012.60,36016.50,20.176,1651880939999,726648.43480,378,12.009,432510.99440,0 +1651880940000,36016.50,36030.00,36013.10,36030.00,57.968,1651880999999,2088094.86360,675,24.319,876005.39220,0 +1651881000000,36030.00,36068.20,36030.00,36059.50,73.738,1651881059999,2658937.20210,855,38.396,1384455.58570,0 +1651881060000,36059.60,36061.90,36042.80,36042.80,30.964,1651881119999,1116367.58010,538,9.407,339169.88670,0 +1651881120000,36042.80,36042.80,36018.70,36018.70,24.380,1651881179999,878499.50560,461,10.575,381077.12550,0 +1651881180000,36018.50,36036.10,36005.40,36021.60,44.015,1651881239999,1585485.41360,831,28.178,1015059.34270,0 +1651881240000,36021.50,36027.90,36014.50,36027.90,37.758,1651881299999,1360131.71340,516,16.367,589556.07570,0 +1651881300000,36027.80,36031.90,36000.00,36000.20,78.189,1651881359999,2815960.76460,1096,39.854,1435393.94750,0 +1651881360000,36000.20,36000.20,35989.60,35993.90,111.951,1651881419999,4029720.45080,904,21.683,780481.00910,0 +1651881420000,35993.90,36012.40,35993.80,35996.80,73.877,1651881479999,2659704.79180,741,33.468,1204999.50350,0 +1651881480000,35996.80,36012.00,35993.00,36004.80,286.586,1651881539999,10318452.44230,838,271.151,9762761.43980,0 +1651881540000,36004.80,36009.70,35991.00,35995.30,35.970,1651881599999,1294815.33930,625,16.443,591885.46580,0 diff --git a/pkg/indicator/v2/volume/volume_profile.go b/pkg/indicator/v2/volume/volume_profile.go new file mode 100644 index 0000000000..e4ac56226b --- /dev/null +++ b/pkg/indicator/v2/volume/volume_profile.go @@ -0,0 +1,195 @@ +package volume + +import ( + "math" + + "golang.org/x/exp/slices" + "gonum.org/v1/gonum/floats" + "gonum.org/v1/gonum/stat" + + bbgofloats "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// DefaultValueAreaPercentage is the percentage of the total volume used to calculate the value area. +const DefaultValueAreaPercentage = 0.68 + +type VolumeProfileStream struct { + *types.Float64Series + VP VolumeProfile + window int +} + +// VolumeProfile is a histogram of market price and volume. +// Intent is to show the price points with most volume during a period. +// The profile gives key features such as: +// +// Point of control (POC) +// +// Value area high (VAH) +// +// Value area low (VAL) +// +// Session High/Low +type VolumeProfile struct { + + // Bins is the histogram bins. + Bins []float64 + + // Hist is the histogram values. + Hist []float64 + + // POC is the point of control. + POC float64 + + // VAH is the value area high. + VAH float64 + + // VAL is the value area low. + VAL float64 + + // High is the highest price in the profile. + High float64 + + // Low is the lowest price in the profile. + Low float64 +} + +// VolumeLevel is a price and volume pair used to build a volume profile. +type VolumeLevel struct { + + // Price is the market price, typically the high/low average of the kline. + Price float64 + + // Volume is the total buy and sell volume at the price. + Volume float64 +} + +func NewVolumeProfile(source v2.KLineSubscription, window int) *VolumeProfileStream { + prices := v2.HLC3(source) + volumes := v2.Volumes(source) + + s := &VolumeProfileStream{ + Float64Series: types.NewFloat64Series(), + window: window, + } + + source.AddSubscriber(func(v types.KLine) { + if source.Length() < window { + s.PushAndEmit(0) + return + } + var nBins = 10 + // nBins = int(math.Floor((prices.Slice.Max()-prices.Slice.Min())/binWidth)) + 1 + s.VP.High = prices.Slice.Max() + s.VP.Low = prices.Slice.Min() + sortedPrices, sortedVolumes := buildVolumeLevel(prices.Slice, volumes.Slice) + s.VP.Bins = make([]float64, nBins) + s.VP.Bins = floats.Span(s.VP.Bins, s.VP.Low, s.VP.High+1) + s.VP.Hist = stat.Histogram(nil, s.VP.Bins, sortedPrices, sortedVolumes) + + pocIdx := floats.MaxIdx(s.VP.Hist) + s.VP.POC = midBin(s.VP.Bins, pocIdx) + + // TODO the results are of by small difference whereas it is expected they work the same + // vaTotalVol := volumes.Sum() * DefaultValueAreaPercentage + // Calculate Value Area with POC as the centre point\ + vaTotalVol := floats.Sum(volumes.Slice) * DefaultValueAreaPercentage + + vaCumVol := s.VP.Hist[pocIdx] + var vahVol, valVol float64 + vahIdx, valIdx := pocIdx+1, pocIdx-1 + stepVAH, stepVAL := true, true + + for (vaCumVol <= vaTotalVol) && + (vahIdx <= len(s.VP.Hist)-1 && valIdx >= 0) { + + if stepVAH { + vahVol = 0 + for vahVol == 0 && vahIdx+1 < len(s.VP.Hist)-1 { + vahVol = s.VP.Hist[vahIdx] + s.VP.Hist[vahIdx+1] + vahIdx += 2 + } + stepVAH = false + } + + if stepVAL { + valVol = 0 + for valVol == 0 && valIdx-1 >= 0 { + valVol = s.VP.Hist[valIdx] + s.VP.Hist[valIdx-1] + valIdx -= 2 + } + stepVAL = false + } + + switch { + case vahVol > valVol: + vaCumVol += vahVol + stepVAH, stepVAL = true, false + case vahVol < valVol: + vaCumVol += valVol + stepVAH, stepVAL = false, true + case vahVol == valVol: + vaCumVol += valVol + vahVol + stepVAH, stepVAL = true, true + } + + if vahIdx >= len(s.VP.Hist)-1 { + stepVAH = false + } + + if valIdx <= 0 { + stepVAL = false + } + } + + s.VP.VAH = midBin(s.VP.Bins, vahIdx) + s.VP.VAL = midBin(s.VP.Bins, valIdx) + + }) + + return s +} + +func (s *VolumeProfileStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} + +func buildVolumeLevel(p, v bbgofloats.Slice) (sortedp, sortedv bbgofloats.Slice) { + var levels []VolumeLevel + for i := range p { + levels = append(levels, VolumeLevel{ + Price: p[i], + Volume: v[i], + }) + } + + slices.SortStableFunc(levels, func(i, j VolumeLevel) bool { + return i.Price < j.Price + }) + + for _, v := range levels { + sortedp.Append(v.Price) + sortedv.Append(v.Volume) + } + + return +} + +func midBin(bins []float64, idx int) float64 { + + if len(bins) == 0 { + return math.NaN() + } + + if idx >= len(bins)-1 { + return bins[len(bins)-1] + } + + if idx < 0 { + return bins[0] + } + + return stat.Mean([]float64{bins[idx], bins[idx+1]}, nil) +} diff --git a/pkg/indicator/v2/volume/volume_profile_test.go b/pkg/indicator/v2/volume/volume_profile_test.go new file mode 100644 index 0000000000..16a0f67236 --- /dev/null +++ b/pkg/indicator/v2/volume/volume_profile_test.go @@ -0,0 +1,41 @@ +package volume + +import ( + "encoding/csv" + "os" + "path" + "testing" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/datasource/csvsource" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestVolumeProfile(t *testing.T) { + file, _ := os.Open(path.Join("testdata", "BTCUSDT-1m-2022-05-06.csv")) + defer func() { + assert.NoError(t, file.Close()) + }() + + candles, err := csvsource.NewCSVKlineReader(csv.NewReader(file)).ReadAll(time.Minute) + assert.NoError(t, err) + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := NewVolumeProfile(kLines, 10) + + for _, candle := range candles { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + + assert.InDelta(t, 35359.26666666667, ind.VP.Low, 0.01, "VP.LOW") + assert.InDelta(t, 35569.12777777779, ind.VP.VAL, 0.01, "VP.VAL") + assert.InDelta(t, 35988.850000000006, ind.VP.POC, 0.01, "VP.POC") + assert.InDelta(t, 36408.572222222225, ind.VP.VAH, 0.01, "VP.VAH") + assert.InDelta(t, 36617.433333333334, ind.VP.High, 0.01, "VP.HIGH") +} From 0bd8ef1f6187ce567f592987f0636e663a2081a3 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Fri, 27 Oct 2023 02:07:43 +0200 Subject: [PATCH 04/17] add kdj v2 indicators --- pkg/datatype/floats/slice.go | 7 --- pkg/indicator/v2/momentum/chaikin_osc.go | 2 - pkg/indicator/v2/pattern/README.md | 24 ------- pkg/indicator/v2/pattern/dark_cloud.go | 6 ++ pkg/indicator/v2/pattern/doji.go | 5 +- pkg/indicator/v2/pattern/doji_gravestone.go | 4 ++ pkg/indicator/v2/pattern/doji_long_legged.go | 5 ++ pkg/indicator/v2/pattern/harami.go | 4 ++ pkg/indicator/v2/pattern/harami_cross.go | 11 ++++ .../v2/pattern/morning_evening_star.go | 5 ++ pkg/indicator/v2/pattern/spinning_top.go | 5 ++ pkg/indicator/v2/pattern/three_crows.go | 12 ++-- pkg/indicator/v2/trend/alma_test.go | 3 - pkg/indicator/v2/trend/dema.go | 24 +++++-- pkg/indicator/v2/trend/kdj.go | 63 +++++++++++++++++++ pkg/indicator/v2/trend/kdj_test.go | 40 ++++++++++++ pkg/types/series_float64.go | 16 ----- 17 files changed, 171 insertions(+), 65 deletions(-) delete mode 100644 pkg/indicator/v2/pattern/README.md create mode 100644 pkg/indicator/v2/trend/kdj.go create mode 100644 pkg/indicator/v2/trend/kdj_test.go diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go index 3a6aea5ce5..5a01a982ad 100644 --- a/pkg/datatype/floats/slice.go +++ b/pkg/datatype/floats/slice.go @@ -2,7 +2,6 @@ package floats import ( "math" - "sort" "gonum.org/v1/gonum/floats" ) @@ -53,12 +52,6 @@ func (s Slice) Min() float64 { return floats.Min(s) } -func (s Slice) Sort() (b Slice) { - b = s - sort.Float64s(b) - return b -} - func (s Slice) Sub(b Slice) (c Slice) { if len(s) != len(b) { return c diff --git a/pkg/indicator/v2/momentum/chaikin_osc.go b/pkg/indicator/v2/momentum/chaikin_osc.go index a9d0cddd74..ef833dd47f 100644 --- a/pkg/indicator/v2/momentum/chaikin_osc.go +++ b/pkg/indicator/v2/momentum/chaikin_osc.go @@ -10,8 +10,6 @@ import ( // The DefaultChaikinOscillator function calculates Chaikin // Oscillator with the most frequently used fast and short // periods, 3 and 10. -// -// Returns co, ad. func NewChaikinOscillatorDefault(source v2.KLineSubscription) *ChaikinOscillatorStream { return ChaikinOscillator(source, 3, 10) } diff --git a/pkg/indicator/v2/pattern/README.md b/pkg/indicator/v2/pattern/README.md deleted file mode 100644 index 26885f3df5..0000000000 --- a/pkg/indicator/v2/pattern/README.md +++ /dev/null @@ -1,24 +0,0 @@ -[explanations](https://analyzingalpha.com/candlestick-patterns#The_Best_Crypto_Candlestick_Patterns) - -## Use - -Pass a dataframe containing OHLC data and get a bullish or bearish pattern identified: - -- 1: BULL -- -1: BEAR -- 0: NULL - -## Todo - -Check repos for more indicators -https://github.com/markcheno/go-talib/ -https://github.com/gobacktest/gobacktest/blob/main/strategy/ma-cross.go -https://github.com/iamjinlei/go-tart -https://pkg.go.dev/github.com/uvite/u8/tart - - -montecarlo black and scholes -https://ggcarvalho.dev/posts/montecarlo/ -https://medium.com/@matt.a.french/predicting-stock-prices-using-monte-carlo-simulations-in-go-26060ab2836 - -https://github.com/c9s/bbgo/blob/main/pkg/strategy/skeleton/strategy.go \ No newline at end of file diff --git a/pkg/indicator/v2/pattern/dark_cloud.go b/pkg/indicator/v2/pattern/dark_cloud.go index 52f06acb54..4f018bf88d 100644 --- a/pkg/indicator/v2/pattern/dark_cloud.go +++ b/pkg/indicator/v2/pattern/dark_cloud.go @@ -11,6 +11,12 @@ type DarkCloudStream struct { window int } +// Dark Cloud Cover is a candlestick pattern that shows a shift in momentum to the downside +// following a price rise. +// The pattern is composed of a bearish candle that opens above but then closes below the midpoint of +// the prior bullish candle. +// Both candles should be relatively large, showing strong participation by traders and investors. +// When the pattern occurs with small candles it is typically less significant. func DarkCloud(source v2.KLineSubscription) *DarkCloudStream { s := &DarkCloudStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/doji.go b/pkg/indicator/v2/pattern/doji.go index 358d0f45f8..e60c379639 100644 --- a/pkg/indicator/v2/pattern/doji.go +++ b/pkg/indicator/v2/pattern/doji.go @@ -10,7 +10,10 @@ type DojiStream struct { *types.Float64Series } -// maxDiff is the maximum deviation between a and b to consider them approximately equal +// Is a doji bullish or bearish? +// A doji formation generally can be interpreted as a sign of indecision, meaning neither bulls nor bears +// can successfully take over. Of its variations, the dragonfly doji is seen as a bullish reversal pattern +// that occurs at the bottom of downtrends. The gravestone doji is read as a bearish reversal at the peak of uptrends. func Doji(source v2.KLineSubscription, maxDiff float64) *DojiStream { s := &DojiStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/doji_gravestone.go b/pkg/indicator/v2/pattern/doji_gravestone.go index 04d035ed24..32781763e0 100644 --- a/pkg/indicator/v2/pattern/doji_gravestone.go +++ b/pkg/indicator/v2/pattern/doji_gravestone.go @@ -10,6 +10,10 @@ type DojiGraveStoneStream struct { *types.Float64Series } +// A gravestone doji candle is a pattern that technical stock traders use as a signal that a stock price +// may soon undergo a bearish reversal. This pattern forms when the open, low, and closing prices of an asset +// are close to each other and have a long upper shadow. The shadow in a candlestick chart is the thin part +// showing the price action for the day as it differs from high to low prices. func DojiGraveStone(source v2.KLineSubscription, maxDiff float64) *DojiGraveStoneStream { s := &DojiGraveStoneStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/doji_long_legged.go b/pkg/indicator/v2/pattern/doji_long_legged.go index 65c7c9955e..f2e19f1ef0 100644 --- a/pkg/indicator/v2/pattern/doji_long_legged.go +++ b/pkg/indicator/v2/pattern/doji_long_legged.go @@ -12,6 +12,11 @@ type DojiLongLeggedStream struct { window int } +// The long-legged doji is a type of candlestick pattern that signals to traders a point of indecision +// about the future direction of price. This doji has long upper and lower shadows and roughly +// the same opening and closing prices. In addition to signaling indecision, the long-legged doji can also +// indicate the beginning of a consolidation period where price action may soon break out to form a new trend. +// These doji can be a sign that sentiment is changing and that a trend reversal is on the horizon. func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { s := &DojiLongLeggedStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/harami.go b/pkg/indicator/v2/pattern/harami.go index cde9183df4..1a3a294e72 100644 --- a/pkg/indicator/v2/pattern/harami.go +++ b/pkg/indicator/v2/pattern/harami.go @@ -11,6 +11,10 @@ type HaramiStream struct { window int } +// The bullish harami indicator is charted as a long candlestick followed by a smaller body, +// referred to as a doji, that is completely contained within the vertical range of the previous body. +// To some, a line drawn around this pattern resembles a pregnant woman. The word harami comes from an +// old Japanese word meaning pregnant. func Harami(source v2.KLineSubscription) *HaramiStream { s := &HaramiStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/harami_cross.go b/pkg/indicator/v2/pattern/harami_cross.go index 8fc1f078ea..6300f3c5e1 100644 --- a/pkg/indicator/v2/pattern/harami_cross.go +++ b/pkg/indicator/v2/pattern/harami_cross.go @@ -12,6 +12,17 @@ type HaramiCrossStream struct { window int } +// A bullish harami cross pattern forms after a downtrend. +// The doji shows that some indecision has entered the minds of sellers. +// Typically, traders don't act on the pattern unless the price follows through to the upside within the next +// couple of candles. This is called confirmation. Sometimes the price may pause for a few candles after the doji, +// and then rise or fall. A rise above the open of the first candle helps confirm that the price may be heading higher. +// A bearish harami cross forms after an uptrend. +// The first candlestick is a long up candle (typically colored white or green) which shows buyers are in control. +// This is followed by a doji, which shows indecision on the part of the buyers. Once again, the doji +// must be contained within the real body of the prior candle. +// If the price drops following the pattern, this confirms the pattern. +// If the price continues to rise following the doji, the bearish pattern is invalidated. func HaramiCross(source v2.KLineSubscription, direction Direction, maxDiff float64) *HaramiCrossStream { s := &HaramiCrossStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/morning_evening_star.go b/pkg/indicator/v2/pattern/morning_evening_star.go index df5e5fe2e6..97b239b23f 100644 --- a/pkg/indicator/v2/pattern/morning_evening_star.go +++ b/pkg/indicator/v2/pattern/morning_evening_star.go @@ -12,6 +12,11 @@ type MorningOrEveningStarStream struct { window int } +// An evening star is a candlestick pattern that's used by technical analysts to predict future price reversals +// to the downside. +// The evening star pattern is rare but it's considered by traders to be a reliable technical indicator. +// The evening star is the opposite of the morning star. +// The candlestick pattern is bearish whereas the morning star pattern is bullish. func MorningOrEveningStar(source v2.KLineSubscription, direction Direction) *MorningOrEveningStarStream { s := &MorningOrEveningStarStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/spinning_top.go b/pkg/indicator/v2/pattern/spinning_top.go index 24b949e4ef..70408deeef 100644 --- a/pkg/indicator/v2/pattern/spinning_top.go +++ b/pkg/indicator/v2/pattern/spinning_top.go @@ -10,6 +10,11 @@ type SpinningTopStream struct { *types.Float64Series } +// A spinning top is a candlestick pattern that has a short real body that's vertically centered +// between long upper and lower shadows. +// The real body should be small, showing little difference between the open and close prices. +// Since buyers and sellers both pushed the price, but couldn't maintain it, the pattern shows +// indecision. More sideways movement could follow. func SpinningTop(source v2.KLineSubscription, direction Direction) *SpinningTopStream { s := &SpinningTopStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/pattern/three_crows.go b/pkg/indicator/v2/pattern/three_crows.go index 0e4840afc4..0c41d378af 100644 --- a/pkg/indicator/v2/pattern/three_crows.go +++ b/pkg/indicator/v2/pattern/three_crows.go @@ -5,18 +5,18 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -// https://www.candlescanner.com/candlestick-patterns/two-crows/ -// The Two Crows is a three-line bearish reversal candlestick pattern. -// The pattern requires confirmation, that is, the following candles should break -// a trendline or the nearest support area which may be formed by the first candle’s line. -// If the pattern is not confirmed it may act only as a temporary pause within an uptrend. -// Although the pattern name suggest that two lines form it, in fact, it contains three lines type ThreeCrowsStream struct { *types.Float64Series window int } +// https://www.candlescanner.com/candlestick-patterns/two-crows/ +// The Two Crows is a three-line bearish reversal candlestick pattern. +// The pattern requires confirmation, that is, the following candles should break +// a trendline or the nearest support area which may be formed by the first candle’s line. +// If the pattern is not confirmed it may act only as a temporary pause within an uptrend. +// Although the pattern name suggest that two lines form it, in fact, it contains three lines func ThreeCrows(source v2.KLineSubscription) *ThreeCrowsStream { s := &ThreeCrowsStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/trend/alma_test.go b/pkg/indicator/v2/trend/alma_test.go index b0a3def7c3..0988ef7626 100644 --- a/pkg/indicator/v2/trend/alma_test.go +++ b/pkg/indicator/v2/trend/alma_test.go @@ -1,6 +1,3 @@ -// Copyright 2022 The Coln Group Ltd -// SPDX-License-Identifier: MIT - package trend import ( diff --git a/pkg/indicator/v2/trend/dema.go b/pkg/indicator/v2/trend/dema.go index d3f5517561..04233c7b9a 100644 --- a/pkg/indicator/v2/trend/dema.go +++ b/pkg/indicator/v2/trend/dema.go @@ -30,14 +30,26 @@ type DEMAStream struct { } func DEMA(source types.Float64Source, window int) *DEMAStream { - ema1 := EWMA2(source, window) - ema2 := EWMA2(source, window) - return &DEMAStream{ema1: ema1, ema2: ema2} + var ( + ema1 = EWMA2(source, window) + ema2 = EWMA2(ema1, window) + ) + + s := &DEMAStream{ + Float64Series: types.NewFloat64Series(), + ema1: ema1, + ema2: ema2, + } + s.Bind(source, s) + return s } func (s *DEMAStream) Calculate(v float64) float64 { - e1 := s.ema1.Last(0) - e2 := s.ema2.Last(0) - dema := e1*2 - e2 + var ( + e1 = s.ema1.Last(0) + e2 = s.ema2.Last(0) + dema = e1*2 - e2 + ) + return dema } diff --git a/pkg/indicator/v2/trend/kdj.go b/pkg/indicator/v2/trend/kdj.go new file mode 100644 index 0000000000..69c9f0e137 --- /dev/null +++ b/pkg/indicator/v2/trend/kdj.go @@ -0,0 +1,63 @@ +package trend + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type KDJStream struct { + *types.Float64Series + K *SMAStream + D *SMAStream + min *v2.MinValueStream + max *v2.MaxValueStream + window int +} + +// The Kdj function calculates the KDJ indicator, also known as +// the Random Index. KDJ is calculated similar to the Stochastic +// Oscillator with the difference of having the J line. It is +// used to analyze the trend and entry points. +// +// The K and D lines show if the asset is overbought when they +// crosses above 80%, and oversold when they crosses below +// 20%. The J line represents the divergence. +// +// RSV = ((Closing - Min(Low, rPeriod)) +// +// / (Max(High, rPeriod) - Min(Low, rPeriod))) * 100 +// +// K = Sma(RSV, kPeriod) +// D = Sma(K, dPeriod) +// J = (3 * K) - (2 * D) +func KDJ(source v2.KLineSubscription, window, kWindow, dWindow int) *KDJStream { + + s := &KDJStream{ + Float64Series: types.NewFloat64Series(), + min: v2.MinValue(v2.LowPrices(source), window), + max: v2.MaxValue(v2.HighPrices(source), window), + K: SMA(nil, kWindow), + D: SMA(nil, dWindow), + window: window, + } + source.AddSubscriber(func(v types.KLine) { + var ( + closing = v.Close.Float64() + highest = s.max.Last(0) + lowest = s.min.Last(0) + rsv = (closing - lowest) / (highest - lowest) * 100 + k = s.K.Calculate(rsv) + d = s.D.Calculate(k) + j = (3 * k) - (2 * d) + ) + s.PushAndEmit(j) + }) + + return s +} + +// The DefaultKdj function calculates KDJ based on default periods +// consisting of window of 9, kPeriod of 3, and dPeriod of 3. +func KDJDefault(source v2.KLineSubscription) *KDJStream { + return KDJ(source, 9, 3, 3) +} diff --git a/pkg/indicator/v2/trend/kdj_test.go b/pkg/indicator/v2/trend/kdj_test.go new file mode 100644 index 0000000000..6f52615903 --- /dev/null +++ b/pkg/indicator/v2/trend/kdj_test.go @@ -0,0 +1,40 @@ +package trend + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestKdj(t *testing.T) { + ts := []types.KLine{ + {Low: n(1), High: n(10), Close: n(5)}, + {Low: n(2), High: n(20), Close: n(10)}, + {Low: n(3), High: n(30), Close: n(15)}, + {Low: n(4), High: n(40), Close: n(20)}, + {Low: n(5), High: n(50), Close: n(25)}, + {Low: n(6), High: n(60), Close: n(30)}, + {Low: n(7), High: n(70), Close: n(35)}, + {Low: n(8), High: n(80), Close: n(40)}, + {Low: n(9), High: n(90), Close: n(45)}, + {Low: n(10), High: n(100), Close: n(50)}, + } + // expectedK := []float64{44.44, 45.91, 46.70, 48.12, 48.66, 48.95, 49.14, 49.26, 49.36, 49.26} + // expectedD := []float64{44.44, 45.18, 45.68, 46.91, 47.82, 48.58, 48.91, 49.12, 49.25, 49.30} + expectedJ := []float64{44.44, 47.37, 48.72, 50.55, 50.32, 49.70, 49.58, 49.56, 49.57, 49.19} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := KDJDefault(kLines) + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range expectedJ { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected KDJ.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/types/series_float64.go b/pkg/types/series_float64.go index 0baee1ef30..f12e05d584 100644 --- a/pkg/types/series_float64.go +++ b/pkg/types/series_float64.go @@ -29,22 +29,6 @@ func (f *Float64Series) Length() int { return len(f.Slice) } -// CrossOver returns true if the latest series values cross above x -func (f *Float64Series) CrossOver(curr, x float64) bool { - if f.Last(1) < x && curr > x { - return true - } - return false -} - -// CrossDown returns true if the latest series values cross below x -func (f *Float64Series) CrossUnder(x float64) bool { - if f.Last(1) > x && f.Last(0) < x { - return true - } - return false -} - func (f *Float64Series) Push(x float64) { f.Slice.Push(x) } From ca5c4a63b071c583d2c4f1ec033a38e6add807e9 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Fri, 27 Oct 2023 22:08:38 +0200 Subject: [PATCH 05/17] add trima, vortex, vwma, vwap v2 indicators --- pkg/datatype/floats/slice.go | 11 ++++ pkg/indicator/v2/momentum/rsi.go | 2 +- pkg/indicator/v2/pattern/engulfing.go | 1 + pkg/indicator/v2/price.go | 8 +++ pkg/indicator/v2/trend/dema.go | 4 ++ pkg/indicator/v2/trend/trima.go | 45 ++++++++++++++ pkg/indicator/v2/trend/vortex.go | 90 +++++++++++++++++++++++++++ pkg/indicator/v2/trend/vortex_test.go | 38 +++++++++++ pkg/indicator/v2/trend/vwma.go | 41 ++++++++++++ pkg/indicator/v2/trend/vwma_test.go | 56 +++++++++++++++++ pkg/indicator/v2/volume/vwap.go | 34 ++++++++++ pkg/indicator/v2/volume/vwap_test.go | 33 ++++++++++ pkg/types/kline.go | 8 +++ 13 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 pkg/indicator/v2/trend/trima.go create mode 100644 pkg/indicator/v2/trend/vortex.go create mode 100644 pkg/indicator/v2/trend/vortex_test.go create mode 100644 pkg/indicator/v2/trend/vwma.go create mode 100644 pkg/indicator/v2/trend/vwma_test.go create mode 100644 pkg/indicator/v2/volume/vwap.go create mode 100644 pkg/indicator/v2/volume/vwap_test.go diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go index 5a01a982ad..6a7785114b 100644 --- a/pkg/datatype/floats/slice.go +++ b/pkg/datatype/floats/slice.go @@ -99,6 +99,17 @@ func (s Slice) Mean() (mean float64) { return s.Sum() / float64(length) } +/* Calculates the variance across the dataset of float64s */ +func (s Slice) Variance() float64 { + var variance = .0 + + for _, diff := range s { + variance += math.Pow(diff-s.Mean(), 2) + } + + return variance / float64(len(s)) +} + func (s Slice) Tail(size int) Slice { length := len(s) if length <= size { diff --git a/pkg/indicator/v2/momentum/rsi.go b/pkg/indicator/v2/momentum/rsi.go index fc96c8138c..30fb7ac10e 100644 --- a/pkg/indicator/v2/momentum/rsi.go +++ b/pkg/indicator/v2/momentum/rsi.go @@ -17,8 +17,8 @@ type RSIStream struct { func RSI2(source types.Float64Source, window int) *RSIStream { s := &RSIStream{ - source: source, Float64Series: types.NewFloat64Series(), + source: source, window: window, } s.Bind(source, s) diff --git a/pkg/indicator/v2/pattern/engulfing.go b/pkg/indicator/v2/pattern/engulfing.go index f5b6f06922..fc043f1699 100644 --- a/pkg/indicator/v2/pattern/engulfing.go +++ b/pkg/indicator/v2/pattern/engulfing.go @@ -11,6 +11,7 @@ type EngulfingStream struct { window int } +// Bullish engulfing patterns are more likely to signal reversals when they are preceded by four or more black candlesticks. func Engulfing(source v2.KLineSubscription) *EngulfingStream { s := &EngulfingStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/price.go b/pkg/indicator/v2/price.go index 34a9502387..cd109df73c 100644 --- a/pkg/indicator/v2/price.go +++ b/pkg/indicator/v2/price.go @@ -72,10 +72,18 @@ func HLC3(source KLineSubscription) *PriceStream { return Price(source, types.KLineHLC3Mapper) } +func HLC3MulVolume(source KLineSubscription) *PriceStream { + return Price(source, types.KLineHLC3xVMapper) +} + func HL2(source KLineSubscription) *PriceStream { return Price(source, types.KLineHL2Mapper) } +func CloseMulVolume(source KLineSubscription) *PriceStream { + return Price(source, types.KLineCxVMapper) +} + func LogClose(source KLineSubscription) *PriceStream { s := &PriceStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/trend/dema.go b/pkg/indicator/v2/trend/dema.go index 04233c7b9a..84bea5c030 100644 --- a/pkg/indicator/v2/trend/dema.go +++ b/pkg/indicator/v2/trend/dema.go @@ -53,3 +53,7 @@ func (s *DEMAStream) Calculate(v float64) float64 { return dema } + +func (s *DEMAStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) +} diff --git a/pkg/indicator/v2/trend/trima.go b/pkg/indicator/v2/trend/trima.go new file mode 100644 index 0000000000..e7fe72e812 --- /dev/null +++ b/pkg/indicator/v2/trend/trima.go @@ -0,0 +1,45 @@ +package trend + +import "github.com/c9s/bbgo/pkg/types" + +type TrimaStream struct { + // embedded struct + *types.Float64Series + + trima *SMAStream +} + +// Trima function calculates the Triangular Moving Average (TRIMA). +// +// If period is even: +// +// TRIMA = SMA(period / 2, SMA((period / 2) + 1, values)) +// +// If period is odd: +// +// TRIMA = SMA((period + 1) / 2, SMA((period + 1) / 2, values)) +// +// Returns trima. +func Trima(source types.Float64Source, window int) *TrimaStream { + var n1, n2 int + + if window%2 == 0 { + n1 = window / 2 + n2 = n1 + 1 + } else { + n1 = (window + 1) / 2 + n2 = n1 + } + + var s = &TrimaStream{ + Float64Series: types.NewFloat64Series(), + trima: SMA(SMA(source, n2), n1), + } + + s.Bind(source, s) + return s +} + +func (s *TrimaStream) Calculate(_ float64) float64 { + return s.trima.Last(0) +} diff --git a/pkg/indicator/v2/trend/vortex.go b/pkg/indicator/v2/trend/vortex.go new file mode 100644 index 0000000000..6e96368959 --- /dev/null +++ b/pkg/indicator/v2/trend/vortex.go @@ -0,0 +1,90 @@ +package trend + +import ( + "math" + + "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +// Vortex Indicator. It provides two oscillators that capture positive and +// negative trend movement. A bullish signal triggers when the positive +// trend indicator crosses above the negative trend indicator or a key +// level. A bearish signal triggers when the negative trend indicator +// crosses above the positive trend indicator or a key level. +// +// +VM = Abs(Current High - Prior Low) +// -VM = Abd(Current Low - Prior High) +// +// +VM14 = 14-Period Sum of +VM +// -VM14 = 14-Period Sum of -VM +// +// TR = Max((High[i]-Low[i]), Abs(High[i]-Closing[i-1]), Abs(Low[i]-Closing[i-1])) +// TR14 = 14-Period Sum of TR +// +// +VI14 = +VM14 / TR14 +// -VI14 = -VM14 / TR14 +// +// Based on https://school.stockcharts.com/doku.php?id=technical_indicators:vortex_indicator +type VortexStream struct { + plusVm, minusVm, tr floats.Slice + PlusVi, MinusVi *types.Float64Series + plusVmSum, minusVmSum, trSum float64 + window int +} + +func Vortex(source v2.KLineSubscription) *VortexStream { + var ( + low = v2.LowPrices(source) + high = v2.HighPrices(source) + closing = v2.ClosePrices(source) + window = 14 + s = &VortexStream{ + PlusVi: types.NewFloat64Series(), + MinusVi: types.NewFloat64Series(), + plusVm: make([]float64, window), + minusVm: make([]float64, window), + tr: make([]float64, window), + window: window, + } + ) + + source.AddSubscriber(func(v types.KLine) { + var ( + i = source.Length() + j = i % s.window + ) + if i == 1 { + s.PlusVi.PushAndEmit(0) + s.MinusVi.PushAndEmit(0) + return + } + s.plusVmSum -= s.plusVm[j] + s.plusVm[j] = math.Abs(high.Last(0) - low.Last(1)) + s.plusVmSum += s.plusVm[j] + + s.minusVmSum -= s.minusVm[j] + s.minusVm[j] = math.Abs(low.Last(0) - high.Last(1)) + s.minusVmSum += s.minusVm[j] + + var ( + highLow = high.Last(0) - low.Last(0) + highPrevClosing = math.Abs(high.Last(0) - closing.Last(1)) + lowPrevClosing = math.Abs(low.Last(0) - closing.Last(1)) + ) + + s.trSum -= s.tr[j] + s.tr[j] = math.Max(highLow, math.Max(highPrevClosing, lowPrevClosing)) + s.trSum += s.tr[j] + + s.PlusVi.PushAndEmit(s.plusVmSum / s.trSum) + s.MinusVi.PushAndEmit(s.minusVmSum / s.trSum) + }) + return s +} + +func (s *VortexStream) Truncate() { + s.PlusVi.Slice = s.PlusVi.Slice.Truncate(MaxNumOfMA) + s.MinusVi.Slice = s.MinusVi.Slice.Truncate(MaxNumOfMA) +} diff --git a/pkg/indicator/v2/trend/vortex_test.go b/pkg/indicator/v2/trend/vortex_test.go new file mode 100644 index 0000000000..df28518d31 --- /dev/null +++ b/pkg/indicator/v2/trend/vortex_test.go @@ -0,0 +1,38 @@ +package trend + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestVortex(t *testing.T) { + high := []float64{1404.14, 1405.95, 1405.98, 1405.87, 1410.03} + low := []float64{1396.13, 1398.80, 1395.62, 1397.32, 1400.60} + closing := []float64{1402.22, 1402.80, 1405.87, 1404.11, 1403.93} + expectedPlusVi := []float64{0.00000, 1.37343, 0.97087, 1.04566, 1.12595} + expectedMinusVi := []float64{0.00000, 0.74685, 0.89492, 0.93361, 0.83404} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Vortex(kLines) + var ts []types.KLine + for i := range closing { + kline := types.KLine{Low: n(low[i]), High: n(high[i]), Close: n(closing[i])} + ts = append(ts, kline) + } + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range expectedPlusVi { + assert.InDelta(t, v, ind.PlusVi.Slice[i], 0.01, "Expected Vortex.slice[%d] to be %v, but got %v", i, v, ind.PlusVi.Slice[i]) + } + for i, v := range expectedMinusVi { + assert.InDelta(t, v, ind.MinusVi.Slice[i], 0.01, "Expected Vortex.slice[%d] to be %v, but got %v", i, v, ind.MinusVi.Slice[i]) + } +} diff --git a/pkg/indicator/v2/trend/vwma.go b/pkg/indicator/v2/trend/vwma.go new file mode 100644 index 0000000000..11a8ff50b7 --- /dev/null +++ b/pkg/indicator/v2/trend/vwma.go @@ -0,0 +1,41 @@ +package trend + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type VwmaStream struct { + *types.Float64Series + sma1 *SMAStream + sma2 *SMAStream + window int +} + +// The Vwma function calculates the Volume Weighted Moving Average (VWMA) +// averaging the price data with an emphasis on volume, meaning areas +// with higher volume will have a greater weight. +// +// VWMA = Sum(Price * Volume) / Sum(Volume) for a given Period. +func Vwma(source v2.KLineSubscription, window int) *VwmaStream { + s := &VwmaStream{ + Float64Series: types.NewFloat64Series(), + sma1: SMA(v2.CloseMulVolume(source), window), + sma2: SMA(v2.Volumes(source), window), + window: window, + } + source.AddSubscriber(func(v types.KLine) { + var vwma = s.sma1.Last(0) / s.sma2.Last(0) + s.PushAndEmit(vwma) + }) + return s +} + +// The DefaultVwma function calculates VWMA with a period of 20. +func VwmaDefault(source v2.KLineSubscription) *VwmaStream { + return Vwma(source, 20) +} + +func (s *VwmaStream) Calculate(_ float64) float64 { + return s.Slice.Last(0) +} diff --git a/pkg/indicator/v2/trend/vwma_test.go b/pkg/indicator/v2/trend/vwma_test.go new file mode 100644 index 0000000000..5168ef3d8d --- /dev/null +++ b/pkg/indicator/v2/trend/vwma_test.go @@ -0,0 +1,56 @@ +package trend + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestVwma(t *testing.T) { + + tests := []struct { + name string + closing []float64 + volume []float64 + window int + want []float64 + }{ + { + name: "Valid sample", + closing: []float64{20, 21, 21, 19, 16}, + volume: []float64{100, 50, 40, 50, 100}, + window: 3, + want: []float64{20, 20.33, 20.47, 20.29, 17.84}, + }, + { + name: "Default window", + closing: []float64{20, 21, 21, 19, 16}, + volume: []float64{100, 50, 40, 50, 100}, + window: 20, + want: []float64{20, 20.33, 20.47, 20.17, 18.94}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Vwma(kLines, tt.window) + var ts []types.KLine + for i := range tt.closing { + kline := types.KLine{Volume: n(tt.volume[i]), Close: n(tt.closing[i])} + ts = append(ts, kline) + } + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range tt.want { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected TEMA.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } + }) + } +} diff --git a/pkg/indicator/v2/volume/vwap.go b/pkg/indicator/v2/volume/vwap.go new file mode 100644 index 0000000000..214037e5d4 --- /dev/null +++ b/pkg/indicator/v2/volume/vwap.go @@ -0,0 +1,34 @@ +package volume + +import ( + "gonum.org/v1/gonum/floats" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type VWAPStream struct { + *types.Float64Series + window int +} + +// The Volume Weighted Average Price (VWAP) provides the average price +// the asset has traded weighted by volume. +// +// VWAP = Sum(Closing * Volume) / Sum(Volume) +func VWAP(source v2.KLineSubscription, window int) *VWAPStream { + var ( + hlc3v = v2.CloseMulVolume(source) + volume = v2.Volumes(source) + s = &VWAPStream{ + Float64Series: types.NewFloat64Series(), + window: window, + } + ) + source.AddSubscriber(func(v types.KLine) { + // var vwap = hlc3v.Sum(window) / volume.Sum(s.window) // todo behaviour not the same?! + var vwap = floats.Sum(hlc3v.Slice.Tail(s.window)) / floats.Sum(volume.Slice.Tail(s.window)) + s.PushAndEmit(vwap) + }) + return s +} diff --git a/pkg/indicator/v2/volume/vwap_test.go b/pkg/indicator/v2/volume/vwap_test.go new file mode 100644 index 0000000000..bfc51516aa --- /dev/null +++ b/pkg/indicator/v2/volume/vwap_test.go @@ -0,0 +1,33 @@ +package volume + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestVolumeWeightedAveragePrice(t *testing.T) { + ts := []types.KLine{ + {Volume: n(100), Close: n(9)}, + {Volume: n(110), Close: n(11)}, + {Volume: n(80), Close: n(7)}, + {Volume: n(120), Close: n(10)}, + {Volume: n(90), Close: n(8)}, + } + expected := []float64{9, 10.05, 9.32, 8.8, 9.14} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := VWAP(kLines, 2) + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected VWAP.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/types/kline.go b/pkg/types/kline.go index cadb529176..f4a2335571 100644 --- a/pkg/types/kline.go +++ b/pkg/types/kline.go @@ -673,10 +673,18 @@ func KLineHLC3Mapper(k KLine) float64 { return k.High.Add(k.Low).Add(k.Close).Div(Three).Float64() } +func KLineHLC3xVMapper(k KLine) float64 { + return k.High.Add(k.Low).Add(k.Close).Div(Three).Mul(k.Volume).Float64() +} + func KLineHL2Mapper(k KLine) float64 { return k.High.Add(k.Low).Div(Two).Float64() } +func KLineCxVMapper(k KLine) float64 { + return k.Close.Mul(k.Volume).Float64() +} + func MapKLinePrice(kLines []KLine, f KLineValueMapper) (prices []float64) { for _, k := range kLines { prices = append(prices, f(k)) From 8426d3b37e917b35209910ee7b42a72d7171529d Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Sat, 28 Oct 2023 01:31:48 +0200 Subject: [PATCH 06/17] chaikin money flow, trend line v2 indicators --- pkg/indicator/util.go | 2 +- pkg/indicator/v2/momentum/rsi.go | 10 +-- pkg/indicator/v2/trend/kdj.go | 4 + pkg/indicator/v2/trend/rma.go | 4 +- pkg/indicator/v2/trend/trend_line.go | 69 +++++++++++++++ pkg/indicator/v2/trend/trend_line_test.go | 83 +++++++++++++++++++ pkg/indicator/v2/volume/chaikin_money_flow.go | 58 +++++++++++++ .../v2/volume/chaikin_money_flow_test.go | 33 ++++++++ pkg/indicator/v2/volume/vwap.go | 14 +++- 9 files changed, 262 insertions(+), 15 deletions(-) create mode 100644 pkg/indicator/v2/trend/trend_line.go create mode 100644 pkg/indicator/v2/trend/trend_line_test.go create mode 100644 pkg/indicator/v2/volume/chaikin_money_flow.go create mode 100644 pkg/indicator/v2/volume/chaikin_money_flow_test.go diff --git a/pkg/indicator/util.go b/pkg/indicator/util.go index ce5c209b2d..27314df772 100644 --- a/pkg/indicator/util.go +++ b/pkg/indicator/util.go @@ -1,6 +1,6 @@ package indicator -func max(x, y int) int { +func Max(x, y int) int { if x > y { return x } diff --git a/pkg/indicator/v2/momentum/rsi.go b/pkg/indicator/v2/momentum/rsi.go index 30fb7ac10e..d896f371bc 100644 --- a/pkg/indicator/v2/momentum/rsi.go +++ b/pkg/indicator/v2/momentum/rsi.go @@ -1,6 +1,7 @@ package momentum import ( + "github.com/c9s/bbgo/pkg/indicator" "github.com/c9s/bbgo/pkg/types" ) @@ -28,7 +29,7 @@ func RSI2(source types.Float64Source, window int) *RSIStream { func (s *RSIStream) Calculate(_ float64) float64 { var gainSum, lossSum float64 var sourceLen = s.source.Length() - var limit = min(s.window, sourceLen) + var limit = indicator.Min(s.window, sourceLen) for i := 0; i < limit; i++ { value := s.source.Last(i) prev := s.source.Last(i + 1) @@ -46,10 +47,3 @@ func (s *RSIStream) Calculate(_ float64) float64 { rsi := 100.0 - (100.0 / (1.0 + rs)) return rsi } - -func min(x, y int) int { - if x < y { - return x - } - return y -} diff --git a/pkg/indicator/v2/trend/kdj.go b/pkg/indicator/v2/trend/kdj.go index 69c9f0e137..339c022f80 100644 --- a/pkg/indicator/v2/trend/kdj.go +++ b/pkg/indicator/v2/trend/kdj.go @@ -61,3 +61,7 @@ func KDJ(source v2.KLineSubscription, window, kWindow, dWindow int) *KDJStream { func KDJDefault(source v2.KLineSubscription) *KDJStream { return KDJ(source, 9, 3, 3) } + +func (s *KDJStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) +} diff --git a/pkg/indicator/v2/trend/rma.go b/pkg/indicator/v2/trend/rma.go index 6e3d7289fc..ecd7a91565 100644 --- a/pkg/indicator/v2/trend/rma.go +++ b/pkg/indicator/v2/trend/rma.go @@ -59,9 +59,7 @@ func (s *RMAStream) Calculate(x float64) float64 { } func (s *RMAStream) Truncate() { - if len(s.Slice) > MaxNumOfRMA { - s.Slice = s.Slice[MaxNumOfRMATruncateSize-1:] - } + s.Slice = s.Slice.Truncate(MaxNumOfMA) } func checkWindow(window int) { diff --git a/pkg/indicator/v2/trend/trend_line.go b/pkg/indicator/v2/trend/trend_line.go new file mode 100644 index 0000000000..0403d56bc1 --- /dev/null +++ b/pkg/indicator/v2/trend/trend_line.go @@ -0,0 +1,69 @@ +package trend + +import ( + "math" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type TrendLineStream struct { + *types.Float64Series +} + +// NewTrendlineIndicator returns an indicator whose output is the slope of the trend +// line given by the values in the window. +func TrendLine(source v2.KLineSubscription, window int) *TrendLineStream { + var ( + closing = v2.ClosePrices(source) + s = &TrendLineStream{ + Float64Series: types.NewFloat64Series(), + } + ) + source.AddSubscriber(func(v types.KLine) { + var index = source.Length() + if index < window { + s.PushAndEmit(0.0) + } + var ( + values = closing.Slice.Tail(window) + ab = sumXy(values)*float64(window) - sumX(values)*sumY(values) + cd = sumX2(values)*float64(window) - math.Pow(sumX(values), 2) + trend = ab / cd + ) + s.PushAndEmit(trend) + }) + return s +} + +func (s *TrendLineStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) +} + +func sumX(s []float64) (sum float64) { + for i := range s { + sum += float64(i) + } + return +} + +func sumY(s []float64) (sum float64) { + for _, d := range s { + sum += d + } + return +} + +func sumXy(s []float64) (sum float64) { + for i, d := range s { + sum += d * float64(i) + } + return +} + +func sumX2(s []float64) (sum float64) { + for i := range s { + sum += math.Pow(float64(i), 2) + } + return +} diff --git a/pkg/indicator/v2/trend/trend_line_test.go b/pkg/indicator/v2/trend/trend_line_test.go new file mode 100644 index 0000000000..d5f8f75ec7 --- /dev/null +++ b/pkg/indicator/v2/trend/trend_line_test.go @@ -0,0 +1,83 @@ +package trend + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestTrendIndicator(t *testing.T) { + t.Run("returns the correct slope of the trend", func(t *testing.T) { + tests := []struct { + closing []float64 + expectedResult float64 + }{ + { + closing: []float64{0, 1, 2, 3}, + expectedResult: 1, + }, + { + closing: []float64{0, 2, 4, 6}, + expectedResult: 2, + }, + { + closing: []float64{5, 4, 3, 2}, + expectedResult: -1, + }, + } + + for _, tt := range tests { + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := TrendLine(kLines, 3) + buildKLines := func(closing []float64) (kLines []types.KLine) { + for i := range closing { + kLines = append(kLines, types.KLine{Close: n(closing[i])}) + } + return kLines + } + ts := buildKLines(tt.closing) + for _, d := range ts { + stream.EmitKLineClosed(d) + } + + spew.Dump(ind) + assert.InDelta(t, tt.expectedResult, ind.Last(0), 0.001, "Expected Trend.Last(0) to be %v, but got %v", tt.expectedResult, ind.Last(0)) + + } + }) + + // t.Run("respects the window", func(t *testing.T) { + // indicator := NewTrendLine(4) + // indicator.Update(dec.Slice(-100, 1000, 0, 1, 2, 3)...) + // source := types.NewFloat64Series() + // sma := SMA(source, 9) + + // data := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9} + // for _, d := range data { + // source.PushAndEmit(d) + // } + + // assert.InDelta(t, 5, sma.Last(0), 0.001) + // assert.EqualValues(t, 1, indicator.Value().Float64()) + // }) + + // t.Run("does not allow an index out of bounds on the low end", func(t *testing.T) { + // indicator := NewTrendLine(2) + // indicator.Update(dec.Slice(0, 0, 1)...) + // source := types.NewFloat64Series() + // sma := SMA(source, 9) + + // data := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9} + // for _, d := range data { + // source.PushAndEmit(d) + // } + + // assert.InDelta(t, 5, sma.Last(0), 0.001) + // assert.EqualValues(t, 1, indicator.Value().Float64()) + // }) +} diff --git a/pkg/indicator/v2/volume/chaikin_money_flow.go b/pkg/indicator/v2/volume/chaikin_money_flow.go new file mode 100644 index 0000000000..e8f28f41de --- /dev/null +++ b/pkg/indicator/v2/volume/chaikin_money_flow.go @@ -0,0 +1,58 @@ +package volume + +import ( + "gonum.org/v1/gonum/floats" + + bbfloat "github.com/c9s/bbgo/pkg/datatype/floats" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type ChaikinMoneyFlowStream struct { + *types.Float64Series + moneyFlowVolume bbfloat.Slice + window int +} + +// The Chaikin Money Flow (CMF) measures the amount of money flow volume +// over a given period. +// +// Money Flow Multiplier = ((Closing - Low) - (High - Closing)) / (High - Low) +// Money Flow Volume = Money Flow Multiplier * Volume +// Chaikin Money Flow = Sum(20, Money Flow Volume) / Sum(20, Volume) +func ChaikinMoneyFlow(source v2.KLineSubscription, window int) *ChaikinMoneyFlowStream { + var ( + closing = v2.ClosePrices(source) + low = v2.LowPrices(source) + high = v2.HighPrices(source) + volume = v2.Volumes(source) + cl = v2.Subtract(closing, low) + hc = v2.Subtract(high, closing) + flow = v2.Subtract(cl, hc) + hl = v2.Subtract(high, low) + s = &ChaikinMoneyFlowStream{ + Float64Series: types.NewFloat64Series(), + window: window, + } + ) + source.AddSubscriber(func(v types.KLine) { + var moneyFlowMultiplier = flow.Last(0) / hl.Last(0) + s.moneyFlowVolume.Push(moneyFlowMultiplier * volume.Last(0)) + var ( + sumFlowVol = floats.Sum(s.moneyFlowVolume.Tail(s.window)) + sumVol = floats.Sum(volume.Slice.Tail(s.window)) + cmf = sumFlowVol / sumVol + ) + + s.PushAndEmit(cmf) + }) + return s +} + +func (s *ChaikinMoneyFlowStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} + +func ChaikinMoneyFlowDefault(source v2.KLineSubscription) *ChaikinMoneyFlowStream { + return ChaikinMoneyFlow(source, 20) +} diff --git a/pkg/indicator/v2/volume/chaikin_money_flow_test.go b/pkg/indicator/v2/volume/chaikin_money_flow_test.go new file mode 100644 index 0000000000..350e08e33d --- /dev/null +++ b/pkg/indicator/v2/volume/chaikin_money_flow_test.go @@ -0,0 +1,33 @@ +package volume + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestChaikinMoneyFlow(t *testing.T) { + ts := []types.KLine{ + {Volume: n(100), Low: n(6), High: n(10), Close: n(9)}, + {Volume: n(110), Low: n(7), High: n(9), Close: n(11)}, + {Volume: n(80), Low: n(9), High: n(12), Close: n(7)}, + {Volume: n(120), Low: n(12), High: n(14), Close: n(10)}, + {Volume: n(90), Low: n(10), High: n(12), Close: n(8)}, + } + expected := []float64{0.5, 1.81, 0.67, -0.41, -0.87} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := ChaikinMoneyFlowDefault(kLines) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.5, "Expected AccumulationDistribution.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/indicator/v2/volume/vwap.go b/pkg/indicator/v2/volume/vwap.go index 214037e5d4..5d7a254242 100644 --- a/pkg/indicator/v2/volume/vwap.go +++ b/pkg/indicator/v2/volume/vwap.go @@ -18,7 +18,7 @@ type VWAPStream struct { // VWAP = Sum(Closing * Volume) / Sum(Volume) func VWAP(source v2.KLineSubscription, window int) *VWAPStream { var ( - hlc3v = v2.CloseMulVolume(source) + pv = v2.CloseMulVolume(source) volume = v2.Volumes(source) s = &VWAPStream{ Float64Series: types.NewFloat64Series(), @@ -26,9 +26,17 @@ func VWAP(source v2.KLineSubscription, window int) *VWAPStream { } ) source.AddSubscriber(func(v types.KLine) { - // var vwap = hlc3v.Sum(window) / volume.Sum(s.window) // todo behaviour not the same?! - var vwap = floats.Sum(hlc3v.Slice.Tail(s.window)) / floats.Sum(volume.Slice.Tail(s.window)) + // var vwap = pv.Sum(window) / volume.Sum(s.window) // todo behaviour not the same?! + var vwap = floats.Sum(pv.Slice.Tail(s.window)) / floats.Sum(volume.Slice.Tail(s.window)) s.PushAndEmit(vwap) }) return s } + +func VwapDefault(source v2.KLineSubscription) *VWAPStream { + return VWAP(source, 14) +} + +func (s *VWAPStream) Truncate() { + s.Slice = s.Slice.Truncate(5000) +} From f63a40601f42249e9159c073441f428ae28117fa Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Sun, 29 Oct 2023 21:59:49 +0100 Subject: [PATCH 07/17] address comments --- pkg/bbgo/indicator_set.go | 4 +- .../csvsource/bybit_tick_to_kline.go | 8 +- pkg/datasource/csvsource/csv_kline_decoder.go | 30 ++-- pkg/datasource/csvsource/csv_kline_reader.go | 34 ++--- .../csvsource/csv_kline_reader_test.go | 18 +-- pkg/datasource/csvsource/read_klines.go | 16 +-- pkg/datasource/csvsource/read_klines_test.go | 13 +- pkg/datatype/floats/slice.go | 2 +- pkg/indicator/v2/momentum/rsi.go | 4 +- pkg/indicator/v2/price.go | 6 +- pkg/indicator/v2/trend/{ewma.go => ema.go} | 0 pkg/indicator/v2/trend/ema_test.go | 33 +++++ pkg/indicator/v2/trend/qstick.go | 28 ++++ pkg/indicator/v2/trend/qstick_test.go | 34 +++++ pkg/indicator/v2/util.go | 15 ++ .../volatility/{boll.go => bollinger_band.go} | 17 ++- .../v2/volatility/bollinger_band_test.go | 135 ++++++++++++++++++ .../v2/volatility/donchian_channel.go | 49 +++++++ .../v2/volatility/donchian_channel_test.go | 33 +++++ pkg/strategy/bollmaker/dynamic_spread.go | 6 +- pkg/strategy/bollmaker/strategy.go | 4 +- pkg/strategy/bollmaker/trend.go | 2 +- pkg/strategy/scmaker/strategy.go | 4 +- pkg/types/kline.go | 4 + 24 files changed, 424 insertions(+), 75 deletions(-) rename pkg/indicator/v2/trend/{ewma.go => ema.go} (100%) create mode 100644 pkg/indicator/v2/trend/ema_test.go create mode 100644 pkg/indicator/v2/trend/qstick.go create mode 100644 pkg/indicator/v2/trend/qstick_test.go create mode 100644 pkg/indicator/v2/util.go rename pkg/indicator/v2/volatility/{boll.go => bollinger_band.go} (74%) create mode 100644 pkg/indicator/v2/volatility/bollinger_band_test.go create mode 100644 pkg/indicator/v2/volatility/donchian_channel.go create mode 100644 pkg/indicator/v2/volatility/donchian_channel_test.go diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index cb3d4bef50..7173b097c3 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -92,8 +92,8 @@ func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *momentum.Sto return momentum.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) } -func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *volatility.BOLLStream { - return volatility.BOLL(i.CLOSE(iw.Interval), iw.Window, k) +func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *volatility.BollingerStream { + return volatility.BollingerBand(i.CLOSE(iw.Interval), iw.Window, k) } func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *trend.MACDStream { diff --git a/pkg/datasource/csvsource/bybit_tick_to_kline.go b/pkg/datasource/csvsource/bybit_tick_to_kline.go index 1daca70494..800a0240cb 100644 --- a/pkg/datasource/csvsource/bybit_tick_to_kline.go +++ b/pkg/datasource/csvsource/bybit_tick_to_kline.go @@ -28,7 +28,7 @@ type BybitCsvTick struct { ForeignNotional fixedpoint.Value `json:"foreignNotional"` } -func ConvertTicksToKlines(symbol string, interval time.Duration) error { +func ConvertTicksToKLines(symbol string, interval time.Duration) error { err := filepath.Walk( fmt.Sprintf("pkg/datasource/csv/testdata/bybit/%s/", symbol), func(path string, info os.FileInfo, err error) error { @@ -93,11 +93,11 @@ func ConvertTicksToKlines(symbol string, interval time.Duration) error { return err } - return WriteKlines(fmt.Sprintf("pkg/datasource/csv/testdata/%s_%s.csv", symbol, interval.String()), klines) + return WriteKLines(fmt.Sprintf("pkg/datasource/csv/testdata/%s_%s.csv", symbol, interval.String()), klines) } -// WriteKlines write csv to path. -func WriteKlines(path string, prices []types.KLine) (err error) { +// WriteKLines write csv to path. +func WriteKLines(path string, prices []types.KLine) (err error) { file, err := os.Create(path) if err != nil { return errors.Wrap(err, "failed to open file") diff --git a/pkg/datasource/csvsource/csv_kline_decoder.go b/pkg/datasource/csvsource/csv_kline_decoder.go index 904dc06018..38be70c13f 100644 --- a/pkg/datasource/csvsource/csv_kline_decoder.go +++ b/pkg/datasource/csvsource/csv_kline_decoder.go @@ -28,19 +28,19 @@ var ( ErrInvalidVolumeFormat = errors.New("volume must be in valid float format") ) -// CSVKlineDecoder is an extension point for CSVKlineReader to support custom file formats. -type CSVKlineDecoder func(record []string, interval time.Duration) (types.KLine, error) +// CSVKLineDecoder is an extension point for CSVKLineReader to support custom file formats. +type CSVKLineDecoder func(record []string, interval time.Duration) (types.KLine, error) -// NewBinanceCSVKlineReader creates a new CSVKlineReader for Binance CSV files. -func NewBinanceCSVKlineReader(csv *csv.Reader) *CSVKlineReader { - return &CSVKlineReader{ +// NewBinanceCSVKLineReader creates a new CSVKLineReader for Binance CSV files. +func NewBinanceCSVKLineReader(csv *csv.Reader) *CSVKLineReader { + return &CSVKLineReader{ csv: csv, - decoder: BinanceCSVKlineDecoder, + decoder: BinanceCSVKLineDecoder, } } -// BinanceCSVKlineDecoder decodes a CSV record from Binance or Bybit into a Kline. -func BinanceCSVKlineDecoder(record []string, interval time.Duration) (types.KLine, error) { +// BinanceCSVKLineDecoder decodes a CSV record from Binance or Bybit into a KLine. +func BinanceCSVKLineDecoder(record []string, interval time.Duration) (types.KLine, error) { var ( k, empty types.KLine err error @@ -55,6 +55,8 @@ func BinanceCSVKlineDecoder(record []string, interval time.Duration) (types.KLin return empty, ErrInvalidTimeFormat } k.StartTime = types.NewTimeFromUnix(time.UnixMilli(msec).Unix(), 0) + k.EndTime = types.NewTimeFromUnix(k.StartTime.Time().Add(interval).Unix(), 0) + open, err := strconv.ParseFloat(record[1], 64) if err != nil { return empty, ErrInvalidPriceFormat @@ -90,17 +92,17 @@ func BinanceCSVKlineDecoder(record []string, interval time.Duration) (types.KLin return k, nil } -// NewMetaTraderCSVKlineReader creates a new CSVKlineReader for MetaTrader CSV files. -func NewMetaTraderCSVKlineReader(csv *csv.Reader) *CSVKlineReader { +// NewMetaTraderCSVKLineReader creates a new CSVKLineReader for MetaTrader CSV files. +func NewMetaTraderCSVKLineReader(csv *csv.Reader) *CSVKLineReader { csv.Comma = ';' - return &CSVKlineReader{ + return &CSVKLineReader{ csv: csv, - decoder: MetaTraderCSVKlineDecoder, + decoder: MetaTraderCSVKLineDecoder, } } -// MetaTraderCSVKlineDecoder decodes a CSV record from MetaTrader into a Kline. -func MetaTraderCSVKlineDecoder(record []string, interval time.Duration) (types.KLine, error) { +// MetaTraderCSVKLineDecoder decodes a CSV record from MetaTrader into a KLine. +func MetaTraderCSVKLineDecoder(record []string, interval time.Duration) (types.KLine, error) { var ( k, empty types.KLine err error diff --git a/pkg/datasource/csvsource/csv_kline_reader.go b/pkg/datasource/csvsource/csv_kline_reader.go index ca8c7a891b..a5d252b5c6 100644 --- a/pkg/datasource/csvsource/csv_kline_reader.go +++ b/pkg/datasource/csvsource/csv_kline_reader.go @@ -8,35 +8,35 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -var _ KlineReader = (*CSVKlineReader)(nil) +var _ KLineReader = (*CSVKLineReader)(nil) -// CSVKlineReader is a KlineReader that reads from a CSV file. -type CSVKlineReader struct { +// CSVKLineReader is a KLineReader that reads from a CSV file. +type CSVKLineReader struct { csv *csv.Reader - decoder CSVKlineDecoder + decoder CSVKLineDecoder } -// MakeCSVKlineReader is a factory method type that creates a new CSVKlineReader. -type MakeCSVKlineReader func(csv *csv.Reader) *CSVKlineReader +// MakeCSVKLineReader is a factory method type that creates a new CSVKLineReader. +type MakeCSVKLineReader func(csv *csv.Reader) *CSVKLineReader -// NewCSVKlineReader creates a new CSVKlineReader with the default Binance decoder. -func NewCSVKlineReader(csv *csv.Reader) *CSVKlineReader { - return &CSVKlineReader{ +// NewCSVKLineReader creates a new CSVKLineReader with the default Binance decoder. +func NewCSVKLineReader(csv *csv.Reader) *CSVKLineReader { + return &CSVKLineReader{ csv: csv, - decoder: BinanceCSVKlineDecoder, + decoder: BinanceCSVKLineDecoder, } } -// NewCSVKlineReaderWithDecoder creates a new CSVKlineReader with the given decoder. -func NewCSVKlineReaderWithDecoder(csv *csv.Reader, decoder CSVKlineDecoder) *CSVKlineReader { - return &CSVKlineReader{ +// NewCSVKLineReaderWithDecoder creates a new CSVKLineReader with the given decoder. +func NewCSVKLineReaderWithDecoder(csv *csv.Reader, decoder CSVKLineDecoder) *CSVKLineReader { + return &CSVKLineReader{ csv: csv, decoder: decoder, } } -// Read reads the next Kline from the underlying CSV data. -func (r *CSVKlineReader) Read(interval time.Duration) (types.KLine, error) { +// Read reads the next KLine from the underlying CSV data. +func (r *CSVKLineReader) Read(interval time.Duration) (types.KLine, error) { var k types.KLine rec, err := r.csv.Read() @@ -47,8 +47,8 @@ func (r *CSVKlineReader) Read(interval time.Duration) (types.KLine, error) { return r.decoder(rec, interval) } -// ReadAll reads all the Klines from the underlying CSV data. -func (r *CSVKlineReader) ReadAll(interval time.Duration) ([]types.KLine, error) { +// ReadAll reads all the KLines from the underlying CSV data. +func (r *CSVKLineReader) ReadAll(interval time.Duration) ([]types.KLine, error) { var ks []types.KLine for { k, err := r.Read(interval) diff --git a/pkg/datasource/csvsource/csv_kline_reader_test.go b/pkg/datasource/csvsource/csv_kline_reader_test.go index 076a93cb7f..20bb68970b 100644 --- a/pkg/datasource/csvsource/csv_kline_reader_test.go +++ b/pkg/datasource/csvsource/csv_kline_reader_test.go @@ -12,7 +12,7 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -var assertKlineEq = func(t *testing.T, exp, act types.KLine) { +var assertKLineEq = func(t *testing.T, exp, act types.KLine) { assert.Equal(t, exp.StartTime, act.StartTime) assert.True(t, exp.Open == act.Open) assert.True(t, exp.High == act.High) @@ -21,7 +21,7 @@ var assertKlineEq = func(t *testing.T, exp, act types.KLine) { assert.Equal(t, exp.Volume, act.Volume) } -func TestCSVKlineReader_ReadWithBinanceDecoder(t *testing.T) { +func TestCSVKLineReader_ReadWithBinanceDecoder(t *testing.T) { tests := []struct { name string give string @@ -80,26 +80,26 @@ func TestCSVKlineReader_ReadWithBinanceDecoder(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - reader := NewBinanceCSVKlineReader(csv.NewReader(strings.NewReader(tt.give))) + reader := NewBinanceCSVKLineReader(csv.NewReader(strings.NewReader(tt.give))) kline, err := reader.Read(time.Hour) assert.Equal(t, tt.err, err) - assertKlineEq(t, tt.want, kline) + assertKLineEq(t, tt.want, kline) }) } } -func TestCSVKlineReader_ReadAllWithDefaultDecoder(t *testing.T) { +func TestCSVKLineReader_ReadAllWithDefaultDecoder(t *testing.T) { records := []string{ "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", "1609459300000,28928.63000000,30031.34000000,22690.17000000,28495.13000000,3000.00", } - reader := NewCSVKlineReader(csv.NewReader(strings.NewReader(strings.Join(records, "\n")))) + reader := NewCSVKLineReader(csv.NewReader(strings.NewReader(strings.Join(records, "\n")))) klines, err := reader.ReadAll(time.Hour) assert.NoError(t, err) assert.Len(t, klines, 2) } -func TestCSVKlineReader_ReadWithMetaTraderDecoder(t *testing.T) { +func TestCSVKLineReader_ReadWithMetaTraderDecoder(t *testing.T) { tests := []struct { name string @@ -146,10 +146,10 @@ func TestCSVKlineReader_ReadWithMetaTraderDecoder(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - reader := NewMetaTraderCSVKlineReader(csv.NewReader(strings.NewReader(tt.give))) + reader := NewMetaTraderCSVKLineReader(csv.NewReader(strings.NewReader(tt.give))) kline, err := reader.Read(time.Hour) assert.Equal(t, tt.err, err) - assertKlineEq(t, tt.want, kline) + assertKLineEq(t, tt.want, kline) }) } } diff --git a/pkg/datasource/csvsource/read_klines.go b/pkg/datasource/csvsource/read_klines.go index bee351ab77..b3ae962ea4 100644 --- a/pkg/datasource/csvsource/read_klines.go +++ b/pkg/datasource/csvsource/read_klines.go @@ -10,21 +10,21 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -// KlineReader is an interface for reading candlesticks. -type KlineReader interface { +// KLineReader is an interface for reading candlesticks. +type KLineReader interface { Read(interval time.Duration) (types.KLine, error) ReadAll(interval time.Duration) ([]types.KLine, error) } -// ReadKlinesFromCSV reads all the .csv files in a given directory or a single file into a slice of Klines. -// Wraps a default CSVKlineReader with Binance decoder for convenience. +// ReadKLinesFromCSV reads all the .csv files in a given directory or a single file into a slice of KLines. +// Wraps a default CSVKLineReader with Binance decoder for convenience. // For finer grained memory management use the base kline reader. -func ReadKlinesFromCSV(path string, interval time.Duration) ([]types.KLine, error) { - return ReadKlinesFromCSVWithDecoder(path, interval, MakeCSVKlineReader(NewBinanceCSVKlineReader)) +func ReadKLinesFromCSV(path string, interval time.Duration) ([]types.KLine, error) { + return ReadKLinesFromCSVWithDecoder(path, interval, MakeCSVKLineReader(NewBinanceCSVKLineReader)) } -// ReadKlinesFromCSVWithDecoder permits using a custom CSVKlineReader. -func ReadKlinesFromCSVWithDecoder(path string, interval time.Duration, maker MakeCSVKlineReader) ([]types.KLine, error) { +// ReadKLinesFromCSVWithDecoder permits using a custom CSVKLineReader. +func ReadKLinesFromCSVWithDecoder(path string, interval time.Duration, maker MakeCSVKLineReader) ([]types.KLine, error) { var prices []types.KLine err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { diff --git a/pkg/datasource/csvsource/read_klines_test.go b/pkg/datasource/csvsource/read_klines_test.go index 109828dc5e..24a055dd57 100644 --- a/pkg/datasource/csvsource/read_klines_test.go +++ b/pkg/datasource/csvsource/read_klines_test.go @@ -7,8 +7,17 @@ import ( "github.com/stretchr/testify/assert" ) -func TestReadKlinesFromCSV(t *testing.T) { - prices, err := ReadKlinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) +func TestReadKLinesFromCSV(t *testing.T) { + expectedEndTime := time.Unix(1609459200, 0).Add(time.Hour) + + prices, err := ReadKLinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) assert.NoError(t, err) assert.Len(t, prices, 2158) + assert.Equal(t, int64(1609459200), prices[0].StartTime.Unix(), "StartTime") + assert.Equal(t, expectedEndTime.Unix(), prices[0].EndTime.Unix(), "EndTime") + assert.Equal(t, 28923.63, prices[0].Open.Float64(), "Open") + assert.Equal(t, 29031.34, prices[0].High.Float64(), "High") + assert.Equal(t, 28690.17, prices[0].Low.Float64(), "Low") + assert.Equal(t, 28995.13, prices[0].Close.Float64(), "Close") + assert.Equal(t, 2311.81144499, prices[0].Volume.Float64(), "Volume") } diff --git a/pkg/datatype/floats/slice.go b/pkg/datatype/floats/slice.go index 6a7785114b..bace6adbf0 100644 --- a/pkg/datatype/floats/slice.go +++ b/pkg/datatype/floats/slice.go @@ -36,7 +36,7 @@ func (s Slice) Max() float64 { return floats.Max(s) } -func (s Slice) MaxIndex() int { +func (s Slice) IndexOfMaxValue() int { maxIdx := 0 maxVal := s[0] for i, val := range s { diff --git a/pkg/indicator/v2/momentum/rsi.go b/pkg/indicator/v2/momentum/rsi.go index d896f371bc..34f34135b3 100644 --- a/pkg/indicator/v2/momentum/rsi.go +++ b/pkg/indicator/v2/momentum/rsi.go @@ -1,7 +1,7 @@ package momentum import ( - "github.com/c9s/bbgo/pkg/indicator" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -29,7 +29,7 @@ func RSI2(source types.Float64Source, window int) *RSIStream { func (s *RSIStream) Calculate(_ float64) float64 { var gainSum, lossSum float64 var sourceLen = s.source.Length() - var limit = indicator.Min(s.window, sourceLen) + var limit = indicatorv2.Min(s.window, sourceLen) for i := 0; i < limit; i++ { value := s.source.Last(i) prev := s.source.Last(i + 1) diff --git a/pkg/indicator/v2/price.go b/pkg/indicator/v2/price.go index cd109df73c..c30a32a3d3 100644 --- a/pkg/indicator/v2/price.go +++ b/pkg/indicator/v2/price.go @@ -84,7 +84,11 @@ func CloseMulVolume(source KLineSubscription) *PriceStream { return Price(source, types.KLineCxVMapper) } -func LogClose(source KLineSubscription) *PriceStream { +func CloseSubOpen(source KLineSubscription) *PriceStream { + return Price(source, types.KLineCOMapper) +} + +func DiffClose(source KLineSubscription) *PriceStream { s := &PriceStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/trend/ewma.go b/pkg/indicator/v2/trend/ema.go similarity index 100% rename from pkg/indicator/v2/trend/ewma.go rename to pkg/indicator/v2/trend/ema.go diff --git a/pkg/indicator/v2/trend/ema_test.go b/pkg/indicator/v2/trend/ema_test.go new file mode 100644 index 0000000000..bc3012dde0 --- /dev/null +++ b/pkg/indicator/v2/trend/ema_test.go @@ -0,0 +1,33 @@ +package trend + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" +) + +func TestExponentialMovingAverage(t *testing.T) { + closing := []float64{ + 64.75, 63.79, 63.73, + 63.73, 63.55, 63.19, + 63.91, 63.85, 62.95, + 63.37, 61.33, 61.51} + expected := []float64{ + 64.75, 64.37, 64.11, + 63.96, 63.8, 63.55, + 63.7, 63.76, 63.43, + 63.41, 62.58, 62.15, + } + prices := v2.ClosePrices(nil) + ind := EWMA2(prices, 4) + + for _, price := range closing { + prices.PushAndEmit(price) + } + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected EWMA.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } + +} diff --git a/pkg/indicator/v2/trend/qstick.go b/pkg/indicator/v2/trend/qstick.go new file mode 100644 index 0000000000..c533541060 --- /dev/null +++ b/pkg/indicator/v2/trend/qstick.go @@ -0,0 +1,28 @@ +package trend + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type QstickStream struct { + *types.Float64Series + sma *SMAStream +} + +// The Qstick function calculates the ratio of recent up and down bars. +// +// QS = Sma(Closing - Opening) +func Qstick(source v2.KLineSubscription, window int) *QstickStream { + var ( + s = &QstickStream{ + Float64Series: types.NewFloat64Series(), + sma: SMA(v2.CloseSubOpen(source), window), + } + ) + source.AddSubscriber(func(v types.KLine) { + s.PushAndEmit(s.sma.Last(0)) + }) + + return s +} diff --git a/pkg/indicator/v2/trend/qstick_test.go b/pkg/indicator/v2/trend/qstick_test.go new file mode 100644 index 0000000000..e06d3361aa --- /dev/null +++ b/pkg/indicator/v2/trend/qstick_test.go @@ -0,0 +1,34 @@ +package trend + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestQstick(t *testing.T) { + ts := []types.KLine{ + {Open: n(10), Close: n(20)}, + {Open: n(20), Close: n(15)}, + {Open: n(15), Close: n(50)}, + {Open: n(50), Close: n(55)}, + {Open: n(40), Close: n(42)}, + {Open: n(41), Close: n(30)}, + {Open: n(43), Close: n(31)}, + {Open: n(80), Close: n(70)}, + } + expected := []float64{10, 2.5, 13.33, 11.25, 9.4, 5.2, 3.8, -5.2} + + stream := &types.StandardStream{} + kLines := v2.KLines(stream, "", "") + ind := Qstick(kLines, 5) + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected QStick.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} diff --git a/pkg/indicator/v2/util.go b/pkg/indicator/v2/util.go new file mode 100644 index 0000000000..293326fe42 --- /dev/null +++ b/pkg/indicator/v2/util.go @@ -0,0 +1,15 @@ +package indicatorv2 + +func Max(x, y int) int { + if x > y { + return x + } + return y +} + +func Min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/pkg/indicator/v2/volatility/boll.go b/pkg/indicator/v2/volatility/bollinger_band.go similarity index 74% rename from pkg/indicator/v2/volatility/boll.go rename to pkg/indicator/v2/volatility/bollinger_band.go index 4f7a861e03..f414c56d3e 100644 --- a/pkg/indicator/v2/volatility/boll.go +++ b/pkg/indicator/v2/volatility/bollinger_band.go @@ -6,14 +6,13 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -type BOLLStream struct { +type BollingerStream struct { // the band series *types.Float64Series UpBand, DownBand *types.Float64Series - window int - k float64 + k float64 SMA *trend.SMAStream StdDev *v2.StdDevStream @@ -26,16 +25,15 @@ type BOLLStream struct { // // -> calculate SMA // -> calculate stdDev -> calculate bandWidth -> get latest SMA -> upBand, downBand -func BOLL(source types.Float64Source, window int, k float64) *BOLLStream { +func BollingerBand(source types.Float64Source, window int, k float64) *BollingerStream { // bind these indicators before our main calculator sma := trend.SMA(source, window) stdDev := v2.StdDev(source, window) - s := &BOLLStream{ + s := &BollingerStream{ Float64Series: types.NewFloat64Series(), UpBand: types.NewFloat64Series(), DownBand: types.NewFloat64Series(), - window: window, k: k, SMA: sma, StdDev: stdDev, @@ -51,8 +49,13 @@ func BOLL(source types.Float64Source, window int, k float64) *BOLLStream { return s } -func (s *BOLLStream) Calculate(v float64) float64 { +func (s *BollingerStream) Calculate(v float64) float64 { stdDev := s.StdDev.Last(0) band := stdDev * s.k return band } + +func (s *BollingerStream) Truncate() { + s.UpBand.Slice = s.UpBand.Slice.Truncate(5000) + s.DownBand.Slice = s.DownBand.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volatility/bollinger_band_test.go b/pkg/indicator/v2/volatility/bollinger_band_test.go new file mode 100644 index 0000000000..a431179ddb --- /dev/null +++ b/pkg/indicator/v2/volatility/bollinger_band_test.go @@ -0,0 +1,135 @@ +package volatility + +import ( + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +// number data from https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands +func TestBollingerBand(t *testing.T) { + ts := []float64{ + 86.16, + 89.09, + 88.78, + 90.32, + 89.07, + 91.15, + 89.44, + 89.18, + 86.93, + 87.68, + 86.96, + 89.43, + 89.32, + 88.72, + 87.45, + 87.26, + 89.50, + 87.90, + 89.13, + 90.70, + 92.90, + 92.98, + 91.80, + 92.66, + 92.68, + 92.30, + 92.77, + 92.54, + 92.95, + 93.20, + 91.07, + 89.83, + 89.74, + 90.40, + 90.74, + 88.02, + 88.09, + 88.84, + 90.78, + 90.54, + 91.39, + 90.65, + } + + expectedLines := strings.Split(` +88.71 1.29 91.29 86.12 5.17 +89.05 1.45 91.95 86.14 5.81 +89.24 1.69 92.61 85.87 6.75 +89.39 1.77 92.93 85.85 7.09 +89.51 1.90 93.31 85.70 7.61 +89.69 2.02 93.73 85.65 8.08 +89.75 2.08 93.90 85.59 8.31 +89.91 2.18 94.27 85.56 8.71 +90.08 2.24 94.57 85.60 8.97 +90.38 2.20 94.79 85.98 8.81 +90.66 2.19 95.04 86.27 8.77 +90.86 2.02 94.91 86.82 8.09 +90.88 2.01 94.90 86.87 8.04 +90.91 2.00 94.90 86.91 7.98 +90.99 1.94 94.86 87.12 7.74 +91.15 1.76 94.67 87.63 7.04 +91.19 1.68 94.56 87.83 6.73 +91.12 1.78 94.68 87.56 7.12 +91.17 1.70 94.58 87.76 6.82 +91.25 1.64 94.53 87.97 6.57 +91.24 1.65 94.53 87.95 6.58 +91.17 1.60 94.37 87.96 6.41 +91.05 1.55 94.15 87.95 6.20`, "\n") + + // SMAs := []float64{} + // STDEVs := []float64{} + BBUPs := []float64{} + BBLOs := []float64{} + // BBWs := []float64{} + for _, line := range expectedLines { + tokens := strings.Split(line, "\t") + if len(tokens) == 5 { + // f1, _ := strconv.ParseFloat(tokens[0], 64) + // SMAs = append(SMAs, f1) + // f2, _ := strconv.ParseFloat(tokens[1], 64) + // STDEVs = append(STDEVs, f2) + f3, _ := strconv.ParseFloat(tokens[2], 64) + BBUPs = append(BBUPs, f3) + f4, _ := strconv.ParseFloat(tokens[3], 64) + BBLOs = append(BBLOs, f4) + // f5, _ := strconv.ParseFloat(tokens[4], 64) + // BBWs = append(BBWs, f5) + } + } + // assert.Equal(t, len(SMAs), 23) + + window := 20 + sigma := 2.0 + // ts := dec.Slice(src...) + // isma := trend.NewSimpleMovingAverage(window) + // isma.Update(ts...) + // smaHistory := isma.Series() + // iwstd := NewWindowedStandardDeviation(window) + // iwstd.Update(ts...) + // wstdHistory := iwstd.Series() + + source := types.NewFloat64Series() + ind := BollingerBand(source, window, sigma) + + for _, d := range ts { + source.PushAndEmit(d) + } + for i := window - 1; i < len(ts); i++ { + j := i - (window - 1) + // decimalAlmostEquals(t, smaHistory[i], SMAs[j], 0.01) + // decimalAlmostEquals(t, wstdHistory[i], STDEVs[j], 0.01) + decimalAlmostEquals(t, ind.UpBand.Slice[i], BBUPs[j], 0.01) + decimalAlmostEquals(t, ind.DownBand.Slice[i], BBLOs[j], 0.01) + // decimalAlmostEquals(t, bbUPHistory[i].Sub(bbLOHistory[i]), BBWs[j], 0.01) + } +} + +func decimalAlmostEquals(t *testing.T, actual float64, expected, epsilon float64) { + assert.InEpsilon(t, expected, actual, epsilon) +} diff --git a/pkg/indicator/v2/volatility/donchian_channel.go b/pkg/indicator/v2/volatility/donchian_channel.go new file mode 100644 index 0000000000..7040c7c58e --- /dev/null +++ b/pkg/indicator/v2/volatility/donchian_channel.go @@ -0,0 +1,49 @@ +package volatility + +import ( + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +type DonchianChannelStream struct { + UpBand, DownBand, MiddleBand *types.Float64Series +} + +// The Donchian Channel (DC) calculates three lines generated by moving average +// calculations that comprise an indicator formed by upper and lower bands +// around a midrange or median band. The upper band marks the highest +// price of an asset while the lower band marks the lowest price of +// an asset, and the area between the upper and lower bands +// represents the Donchian Channel. +// +// Upper Channel = Mmax(period, closings) +// Lower Channel = Mmin(period, closings) +// Middle Channel = (Upper Channel + Lower Channel) / 2 +func DonchianChannel(source v2.KLineSubscription, window int) *DonchianChannelStream { + var ( + closing = v2.ClosePrices(source) + s = &DonchianChannelStream{ + UpBand: types.NewFloat64Series(), + DownBand: types.NewFloat64Series(), + MiddleBand: types.NewFloat64Series(), + } + ) + + source.AddSubscriber(func(v types.KLine) { + var ( + sample = closing.Slice.Tail(window) + upperChannel = sample.Max() + lowerChannel = sample.Min() + ) + s.UpBand.Push(upperChannel) + s.DownBand.Push(lowerChannel) + s.MiddleBand.Push((upperChannel + lowerChannel) / 2) + }) + return s +} + +func (s *DonchianChannelStream) Truncate() { + s.UpBand.Slice = s.UpBand.Slice.Truncate(5000) + s.DownBand.Slice = s.DownBand.Slice.Truncate(5000) + s.MiddleBand.Slice = s.MiddleBand.Slice.Truncate(5000) +} diff --git a/pkg/indicator/v2/volatility/donchian_channel_test.go b/pkg/indicator/v2/volatility/donchian_channel_test.go new file mode 100644 index 0000000000..6f15200488 --- /dev/null +++ b/pkg/indicator/v2/volatility/donchian_channel_test.go @@ -0,0 +1,33 @@ +package volatility + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" +) + +func TestDonchianChannel(t *testing.T) { + closing := []float64{9, 11, 7, 10, 8} + expectedUpper := []float64{9, 11, 11, 11, 11} + expectedMiddle := []float64{9, 10, 9, 9, 9} + expectedLower := []float64{9, 9, 7, 7, 7} + + stream := &types.StandardStream{} + ind := DonchianChannel(v2.KLines(stream, "", ""), 4) + for i := range closing { + stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(closing[i])}) + } + for i, v := range expectedLower { + assert.InDelta(t, v, ind.DownBand.Slice[i], 0.01, "Expected DonchianDownBand.slice[%d] to be %v, but got %v", i, v, ind.DownBand.Slice[i]) + } + for i, v := range expectedMiddle { + assert.InDelta(t, v, ind.MiddleBand.Slice[i], 0.01, "Expected DonchianUpBand.slice[%d] to be %v, but got %v", i, v, ind.UpBand.Slice[i]) + } + for i, v := range expectedUpper { + assert.InDelta(t, v, ind.UpBand.Slice[i], 0.01, "Expected DonchianUpBand.slice[%d] to be %v, but got %v", i, v, ind.UpBand.Slice[i]) + } +} diff --git a/pkg/strategy/bollmaker/dynamic_spread.go b/pkg/strategy/bollmaker/dynamic_spread.go index 880f8b0e40..6ae08607c6 100644 --- a/pkg/strategy/bollmaker/dynamic_spread.go +++ b/pkg/strategy/bollmaker/dynamic_spread.go @@ -29,7 +29,7 @@ type DynamicSpreadSettings struct { } // Initialize dynamic spreads and preload SMAs -func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *volatility.BOLLStream) { +func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *volatility.BollingerStream) { switch { case ds.AmpSpreadSettings != nil: ds.AmpSpreadSettings.initialize(symbol, session) @@ -165,10 +165,10 @@ type DynamicSpreadBollWidthRatioSettings struct { // A positive number. The greater factor, the sharper weighting function. Default set to 1.0 . Sensitivity float64 `json:"sensitivity"` - defaultBoll, neutralBoll *volatility.BOLLStream + defaultBoll, neutralBoll *volatility.BollingerStream } -func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *volatility.BOLLStream) { +func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *volatility.BollingerStream) { ds.neutralBoll = neutralBoll ds.defaultBoll = defaultBoll if ds.Sensitivity <= 0. { diff --git a/pkg/strategy/bollmaker/strategy.go b/pkg/strategy/bollmaker/strategy.go index 131eef9349..23c9d48d47 100644 --- a/pkg/strategy/bollmaker/strategy.go +++ b/pkg/strategy/bollmaker/strategy.go @@ -157,10 +157,10 @@ type Strategy struct { groupID uint32 // defaultBoll is the BOLLINGER indicator we used for predicting the price. - defaultBoll *volatility.BOLLStream + defaultBoll *volatility.BollingerStream // neutralBoll is the neutral price section - neutralBoll *volatility.BOLLStream + neutralBoll *volatility.BollingerStream // StrategyController bbgo.StrategyController diff --git a/pkg/strategy/bollmaker/trend.go b/pkg/strategy/bollmaker/trend.go index 61a4fb2613..3ea9dd89a1 100644 --- a/pkg/strategy/bollmaker/trend.go +++ b/pkg/strategy/bollmaker/trend.go @@ -11,7 +11,7 @@ const ( UnknownTrend PriceTrend = "unknown" ) -func detectPriceTrend(inc *volatility.BOLLStream, price float64) PriceTrend { +func detectPriceTrend(inc *volatility.BollingerStream, price float64) PriceTrend { if inBetween(price, inc.DownBand.Last(0), inc.UpBand.Last(0)) { return NeutralTrend } diff --git a/pkg/strategy/scmaker/strategy.go b/pkg/strategy/scmaker/strategy.go index e214651243..153012bcf5 100644 --- a/pkg/strategy/scmaker/strategy.go +++ b/pkg/strategy/scmaker/strategy.go @@ -77,7 +77,7 @@ type Strategy struct { // indicators ewma *trend.EWMAStream - boll *volatility.BOLLStream + boll *volatility.BollingerStream intensity *IntensityStream positionRiskControl *riskcontrol.PositionRiskControl @@ -203,7 +203,7 @@ func (s *Strategy) initializeIntensityIndicator(session *bbgo.ExchangeSession) { func (s *Strategy) initializePriceRangeBollinger(session *bbgo.ExchangeSession) { kLines := KLines(session.MarketDataStream, s.Symbol, s.PriceRangeBollinger.Interval) closePrices := ClosePrices(kLines) - s.boll = volatility.BOLL(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) + s.boll = volatility.BollingerBand(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) s.preloadKLines(kLines, session, s.Symbol, s.PriceRangeBollinger.Interval) } diff --git a/pkg/types/kline.go b/pkg/types/kline.go index f4a2335571..7d0c67d267 100644 --- a/pkg/types/kline.go +++ b/pkg/types/kline.go @@ -685,6 +685,10 @@ func KLineCxVMapper(k KLine) float64 { return k.Close.Mul(k.Volume).Float64() } +func KLineCOMapper(k KLine) float64 { + return k.Close.Sub(k.Open).Float64() +} + func MapKLinePrice(kLines []KLine, f KLineValueMapper) (prices []float64) { for _, k := range kLines { prices = append(prices, f(k)) From ad5f9930c9323553a95af38f3c6f6ce761496439 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 30 Oct 2023 02:55:53 +0100 Subject: [PATCH 08/17] address comments --- README.md | 2 +- pkg/bbgo/indicator_set.go | 33 +++++++++---------- pkg/exchange/bybit/types.go | 2 +- pkg/indicator/atrp.go | 2 +- .../v2/{pattern => }/abondoned_baby.go | 6 ++-- .../v2/{pattern => }/abondoned_baby_test.go | 5 ++- .../accumulation_distiribution.go | 6 ++-- .../accumulation_distiribution_test.go | 5 ++- pkg/indicator/v2/{trend => }/alma.go | 5 ++- pkg/indicator/v2/{trend => }/alma_test.go | 2 +- pkg/indicator/v2/atr.go | 12 +++++++ pkg/indicator/v2/{volatility => }/atr_test.go | 5 ++- pkg/indicator/v2/{volatility => }/atrp.go | 8 ++--- .../v2/{momentum => }/awesome_osc_test.go | 9 +++-- .../v2/{momentum => }/awseome_osc.go | 19 +++++------ pkg/indicator/v2/{pattern => }/belthold.go | 5 ++- .../v2/{pattern => }/belthold_test.go | 5 ++- .../v2/{volatility => }/bollinger_band.go | 7 ++-- .../{volatility => }/bollinger_band_test.go | 2 +- pkg/indicator/v2/{pattern => }/breakaway.go | 5 ++- .../v2/{pattern => }/breakaway_test.go | 5 ++- pkg/indicator/v2/{trend => }/cci.go | 2 +- pkg/indicator/v2/{trend => }/cci_test.go | 6 ++-- .../v2/{volume => }/chaikin_money_flow.go | 24 +++++++------- .../{volume => }/chaikin_money_flow_test.go | 5 ++- .../v2/{momentum => }/chaikin_osc.go | 13 +++----- .../v2/{momentum => }/chaikin_osc_test.go | 10 ++---- .../v2/{volatility => }/chandelier_exit.go | 15 ++++----- pkg/indicator/v2/{trend => }/cma.go | 2 +- pkg/indicator/v2/{pattern => }/dark_cloud.go | 5 ++- .../v2/{pattern => }/dark_cloud_test.go | 5 ++- pkg/indicator/v2/{trend => }/dema.go | 2 +- pkg/indicator/v2/{pattern => }/doji.go | 6 ++-- .../v2/{pattern => }/doji_dragon_fly.go | 6 ++-- .../v2/{pattern => }/doji_dragon_fly_test.go | 5 ++- .../v2/{pattern => }/doji_gravestone.go | 6 ++-- .../v2/{pattern => }/doji_gravestone_test.go | 5 ++- .../v2/{pattern => }/doji_long_legged.go | 6 ++-- .../v2/{pattern => }/doji_long_legged_test.go | 5 ++- pkg/indicator/v2/{pattern => }/doji_star.go | 6 ++-- .../v2/{pattern => }/doji_star_test.go | 7 ++-- pkg/indicator/v2/{pattern => }/doji_test.go | 5 ++- .../v2/{volatility => }/donchian_channel.go | 7 ++-- .../{volatility => }/donchian_channel_test.go | 7 ++-- .../v2/{pattern => }/downside_tazuki_gap.go | 5 ++- .../{pattern => }/downside_tazuki_gap_test.go | 5 ++- pkg/indicator/v2/{trend => }/ema.go | 2 +- pkg/indicator/v2/{trend => }/ema_test.go | 6 ++-- pkg/indicator/v2/{pattern => }/engulfing.go | 5 ++- .../v2/{pattern => }/engulfing_test.go | 5 ++- pkg/indicator/v2/{pattern => }/harami.go | 5 ++- .../v2/{pattern => }/harami_cross.go | 6 ++-- .../v2/{pattern => }/harami_cross_test.go | 5 ++- pkg/indicator/v2/{pattern => }/harami_test.go | 5 ++- .../v2/{pattern => }/head_shoulders.go | 17 +++++----- .../v2/{pattern => }/head_shoulders_test.go | 5 ++- pkg/indicator/v2/{trend => }/kdj.go | 15 ++++----- pkg/indicator/v2/{trend => }/kdj_test.go | 5 ++- pkg/indicator/v2/{pattern => }/kicking.go | 6 ++-- .../v2/{pattern => }/kicking_test.go | 5 ++- pkg/indicator/v2/{trend => }/macd.go | 11 +++---- pkg/indicator/v2/{trend => }/macd_test.go | 6 ++-- pkg/indicator/v2/{pattern => }/marubozu.go | 6 ++-- .../v2/{pattern => }/marubozu_test.go | 5 ++- pkg/indicator/v2/maxval.go | 2 +- .../v2/{pattern => }/meeting_lines.go | 6 ++-- .../v2/{pattern => }/meeting_lines_test.go | 5 ++- pkg/indicator/v2/minval.go | 2 +- .../v2/{pattern => }/morning_evening_star.go | 6 ++-- .../morning_evening_star_test.go | 7 ++-- .../v2/{volume => }/negative_volume_index.go | 6 ++-- .../negative_volume_index_test.go | 10 ++---- pkg/indicator/v2/{volume => }/obv.go | 5 ++- pkg/indicator/v2/{volume => }/obv_test.go | 6 ++-- pkg/indicator/v2/{trend => }/parabolic_sar.go | 11 +++---- .../v2/{trend => }/parabolic_sar_test.go | 10 ++---- pkg/indicator/v2/{pattern => }/pattern.go | 2 +- .../v2/{pattern => }/piercing_line.go | 5 ++- .../v2/{pattern => }/piercing_line_test.go | 5 ++- pkg/indicator/v2/{trend => }/qstick.go | 7 ++-- pkg/indicator/v2/{trend => }/qstick_test.go | 5 ++- pkg/indicator/v2/{trend => }/rma.go | 2 +- pkg/indicator/v2/{momentum => }/rsi.go | 5 ++- pkg/indicator/v2/{momentum => }/rsi_test.go | 5 ++- .../v2/{pattern => }/separating_lines.go | 6 ++-- .../v2/{pattern => }/separating_lines_test.go | 5 ++- .../{pattern => }/side_by_side_whitelines.go | 6 ++-- .../side_by_side_whitelines_test.go | 5 ++- pkg/indicator/v2/{trend => }/sma.go | 2 +- pkg/indicator/v2/{trend => }/sma_test.go | 2 +- .../v2/{pattern => }/spinning_top.go | 6 ++-- .../v2/{pattern => }/spinning_top_test.go | 5 ++- pkg/indicator/v2/{momentum => }/stoch.go | 12 +++---- pkg/indicator/v2/{momentum => }/stoch_test.go | 6 ++-- .../{momentum => }/stochstream_callbacks.go | 2 +- .../testdata/BTCUSDT-1m-2022-05-06.csv | 0 pkg/indicator/v2/{pattern => }/three_crows.go | 5 ++- .../v2/{pattern => }/three_crows_test.go | 5 ++- .../v2/{pattern => }/three_line_strike.go | 5 ++- .../{pattern => }/three_line_strike_test.go | 5 ++- .../v2/{pattern => }/three_white_soldiers.go | 5 ++- .../three_white_soldiers_test.go | 5 ++- pkg/indicator/v2/{volatility => }/tr.go | 5 ++- pkg/indicator/v2/{volatility => }/tr_test.go | 8 ++--- pkg/indicator/v2/{trend => }/trend_line.go | 7 ++-- .../v2/{trend => }/trend_line_test.go | 5 ++- pkg/indicator/v2/{trend => }/trima.go | 2 +- .../v2/{volatility => }/ulcer_index.go | 8 ++--- .../v2/{volatility => }/ulcer_index_test.go | 2 +- pkg/indicator/v2/volatility/atr.go | 17 ---------- .../v2/{volume => }/volume_profile.go | 10 +++--- .../v2/{volume => }/volume_profile_test.go | 8 ++--- pkg/indicator/v2/{trend => }/vortex.go | 12 +++---- pkg/indicator/v2/{trend => }/vortex_test.go | 5 ++- pkg/indicator/v2/{volume => }/vwap.go | 11 +++---- pkg/indicator/v2/{volume => }/vwap_test.go | 5 ++- pkg/indicator/v2/{trend => }/vwma.go | 11 +++---- pkg/indicator/v2/{trend => }/vwma_test.go | 5 ++- pkg/indicator/v2/{momentum => }/williams_r.go | 13 ++++---- .../v2/{momentum => }/williams_r_test.go | 6 ++-- pkg/report/profit_report.go | 6 ++-- pkg/risk/riskcontrol/circuit_break.go | 6 ++-- pkg/risk/riskcontrol/circuit_break_test.go | 4 +-- pkg/strategy/bollmaker/dynamic_spread.go | 8 ++--- pkg/strategy/bollmaker/strategy.go | 6 ++-- pkg/strategy/bollmaker/trend.go | 4 +-- pkg/strategy/scmaker/intensity.go | 7 ++-- pkg/strategy/scmaker/strategy.go | 22 ++++++------- pkg/strategy/trendtrader/strategy.go | 2 +- pkg/strategy/trendtrader/trend.go | 2 +- pkg/strategy/xfixedmaker/order_price_risk.go | 6 ++-- .../xfixedmaker/order_price_risk_test.go | 4 +-- pkg/{indicator/v2 => types}/bst/bst.go | 0 pkg/{indicator/v2 => types}/bst/bst_test.go | 0 pkg/{indicator/v2 => types}/bst/compare.go | 0 135 files changed, 376 insertions(+), 480 deletions(-) rename pkg/indicator/v2/{pattern => }/abondoned_baby.go (89%) rename pkg/indicator/v2/{pattern => }/abondoned_baby_test.go (86%) rename pkg/indicator/v2/{volume => }/accumulation_distiribution.go (86%) rename pkg/indicator/v2/{volume => }/accumulation_distiribution_test.go (96%) rename pkg/indicator/v2/{trend => }/alma.go (93%) rename pkg/indicator/v2/{trend => }/alma_test.go (97%) create mode 100644 pkg/indicator/v2/atr.go rename pkg/indicator/v2/{volatility => }/atr_test.go (96%) rename pkg/indicator/v2/{volatility => }/atrp.go (61%) rename pkg/indicator/v2/{momentum => }/awesome_osc_test.go (87%) rename pkg/indicator/v2/{momentum => }/awseome_osc.go (78%) rename pkg/indicator/v2/{pattern => }/belthold.go (87%) rename pkg/indicator/v2/{pattern => }/belthold_test.go (90%) rename pkg/indicator/v2/{volatility => }/bollinger_band.go (91%) rename pkg/indicator/v2/{volatility => }/bollinger_band_test.go (99%) rename pkg/indicator/v2/{pattern => }/breakaway.go (90%) rename pkg/indicator/v2/{pattern => }/breakaway_test.go (92%) rename pkg/indicator/v2/{trend => }/cci.go (99%) rename pkg/indicator/v2/{trend => }/cci_test.go (91%) rename pkg/indicator/v2/{volume => }/chaikin_money_flow.go (69%) rename pkg/indicator/v2/{volume => }/chaikin_money_flow_test.go (89%) rename pkg/indicator/v2/{momentum => }/chaikin_osc.go (55%) rename pkg/indicator/v2/{momentum => }/chaikin_osc_test.go (82%) rename pkg/indicator/v2/{volatility => }/chandelier_exit.go (72%) rename pkg/indicator/v2/{trend => }/cma.go (96%) rename pkg/indicator/v2/{pattern => }/dark_cloud.go (91%) rename pkg/indicator/v2/{pattern => }/dark_cloud_test.go (84%) rename pkg/indicator/v2/{trend => }/dema.go (98%) rename pkg/indicator/v2/{pattern => }/doji.go (89%) rename pkg/indicator/v2/{pattern => }/doji_dragon_fly.go (83%) rename pkg/indicator/v2/{pattern => }/doji_dragon_fly_test.go (89%) rename pkg/indicator/v2/{pattern => }/doji_gravestone.go (88%) rename pkg/indicator/v2/{pattern => }/doji_gravestone_test.go (89%) rename pkg/indicator/v2/{pattern => }/doji_long_legged.go (93%) rename pkg/indicator/v2/{pattern => }/doji_long_legged_test.go (92%) rename pkg/indicator/v2/{pattern => }/doji_star.go (91%) rename pkg/indicator/v2/{pattern => }/doji_star_test.go (89%) rename pkg/indicator/v2/{pattern => }/doji_test.go (89%) rename pkg/indicator/v2/{volatility => }/donchian_channel.go (87%) rename pkg/indicator/v2/{volatility => }/donchian_channel_test.go (89%) rename pkg/indicator/v2/{pattern => }/downside_tazuki_gap.go (89%) rename pkg/indicator/v2/{pattern => }/downside_tazuki_gap_test.go (86%) rename pkg/indicator/v2/{trend => }/ema.go (96%) rename pkg/indicator/v2/{trend => }/ema_test.go (86%) rename pkg/indicator/v2/{pattern => }/engulfing.go (88%) rename pkg/indicator/v2/{pattern => }/engulfing_test.go (90%) rename pkg/indicator/v2/{pattern => }/harami.go (91%) rename pkg/indicator/v2/{pattern => }/harami_cross.go (93%) rename pkg/indicator/v2/{pattern => }/harami_cross_test.go (91%) rename pkg/indicator/v2/{pattern => }/harami_test.go (90%) rename pkg/indicator/v2/{pattern => }/head_shoulders.go (73%) rename pkg/indicator/v2/{pattern => }/head_shoulders_test.go (94%) rename pkg/indicator/v2/{trend => }/kdj.go (79%) rename pkg/indicator/v2/{trend => }/kdj_test.go (92%) rename pkg/indicator/v2/{pattern => }/kicking.go (91%) rename pkg/indicator/v2/{pattern => }/kicking_test.go (90%) rename pkg/indicator/v2/{trend => }/macd.go (76%) rename pkg/indicator/v2/{trend => }/macd_test.go (94%) rename pkg/indicator/v2/{pattern => }/marubozu.go (86%) rename pkg/indicator/v2/{pattern => }/marubozu_test.go (89%) rename pkg/indicator/v2/{pattern => }/meeting_lines.go (89%) rename pkg/indicator/v2/{pattern => }/meeting_lines_test.go (91%) rename pkg/indicator/v2/{pattern => }/morning_evening_star.go (92%) rename pkg/indicator/v2/{pattern => }/morning_evening_star_test.go (89%) rename pkg/indicator/v2/{volume => }/negative_volume_index.go (90%) rename pkg/indicator/v2/{volume => }/negative_volume_index_test.go (77%) rename pkg/indicator/v2/{volume => }/obv.go (86%) rename pkg/indicator/v2/{volume => }/obv_test.go (92%) rename pkg/indicator/v2/{trend => }/parabolic_sar.go (91%) rename pkg/indicator/v2/{trend => }/parabolic_sar_test.go (88%) rename pkg/indicator/v2/{pattern => }/pattern.go (95%) rename pkg/indicator/v2/{pattern => }/piercing_line.go (87%) rename pkg/indicator/v2/{pattern => }/piercing_line_test.go (85%) rename pkg/indicator/v2/{trend => }/qstick.go (68%) rename pkg/indicator/v2/{trend => }/qstick_test.go (88%) rename pkg/indicator/v2/{trend => }/rma.go (98%) rename pkg/indicator/v2/{momentum => }/rsi.go (87%) rename pkg/indicator/v2/{momentum => }/rsi_test.go (95%) rename pkg/indicator/v2/{pattern => }/separating_lines.go (88%) rename pkg/indicator/v2/{pattern => }/separating_lines_test.go (91%) rename pkg/indicator/v2/{pattern => }/side_by_side_whitelines.go (90%) rename pkg/indicator/v2/{pattern => }/side_by_side_whitelines_test.go (92%) rename pkg/indicator/v2/{trend => }/sma.go (96%) rename pkg/indicator/v2/{trend => }/sma_test.go (94%) rename pkg/indicator/v2/{pattern => }/spinning_top.go (91%) rename pkg/indicator/v2/{pattern => }/spinning_top_test.go (89%) rename pkg/indicator/v2/{momentum => }/stoch.go (87%) rename pkg/indicator/v2/{momentum => }/stoch_test.go (99%) rename pkg/indicator/v2/{momentum => }/stochstream_callbacks.go (93%) rename pkg/indicator/v2/{volume => }/testdata/BTCUSDT-1m-2022-05-06.csv (100%) rename pkg/indicator/v2/{pattern => }/three_crows.go (92%) rename pkg/indicator/v2/{pattern => }/three_crows_test.go (86%) rename pkg/indicator/v2/{pattern => }/three_line_strike.go (90%) rename pkg/indicator/v2/{pattern => }/three_line_strike_test.go (92%) rename pkg/indicator/v2/{pattern => }/three_white_soldiers.go (87%) rename pkg/indicator/v2/{pattern => }/three_white_soldiers_test.go (86%) rename pkg/indicator/v2/{volatility => }/tr.go (87%) rename pkg/indicator/v2/{volatility => }/tr_test.go (93%) rename pkg/indicator/v2/{trend => }/trend_line.go (87%) rename pkg/indicator/v2/{trend => }/trend_line_test.go (95%) rename pkg/indicator/v2/{trend => }/trima.go (97%) rename pkg/indicator/v2/{volatility => }/ulcer_index.go (84%) rename pkg/indicator/v2/{volatility => }/ulcer_index_test.go (96%) delete mode 100644 pkg/indicator/v2/volatility/atr.go rename pkg/indicator/v2/{volume => }/volume_profile.go (95%) rename pkg/indicator/v2/{volume => }/volume_profile_test.go (85%) rename pkg/indicator/v2/{trend => }/vortex.go (91%) rename pkg/indicator/v2/{trend => }/vortex_test.go (92%) rename pkg/indicator/v2/{volume => }/vwap.go (75%) rename pkg/indicator/v2/{volume => }/vwap_test.go (88%) rename pkg/indicator/v2/{trend => }/vwma.go (73%) rename pkg/indicator/v2/{trend => }/vwma_test.go (92%) rename pkg/indicator/v2/{momentum => }/williams_r.go (84%) rename pkg/indicator/v2/{momentum => }/williams_r_test.go (95%) rename pkg/{indicator/v2 => types}/bst/bst.go (100%) rename pkg/{indicator/v2 => types}/bst/bst_test.go (100%) rename pkg/{indicator/v2 => types}/bst/compare.go (100%) diff --git a/README.md b/README.md index b947f5acad..03ba7da2b6 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ the implementation. - [Tillson T3 Moving Average](./pkg/indicator/till.go) - [Triangular Moving Average](./pkg/indicator/tma.go) - [Variable Index Dynamic Average](./pkg/indicator/vidya.go) - - [Volatility Indicator](./pkg/indicator/volatility.go) + - [Volatility Indicator](./pkg/indicator/indicatorv2.go) - [Volume Weighted Average Price](./pkg/indicator/vwap.go) - [Zero Lag Exponential Moving Average](./pkg/indicator/zlema.go) - And more... diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index 7173b097c3..5a608af7cd 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -4,9 +4,6 @@ import ( "github.com/sirupsen/logrus" indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/momentum" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" - "github.com/c9s/bbgo/pkg/indicator/v2/volatility" "github.com/c9s/bbgo/pkg/types" ) @@ -76,34 +73,34 @@ func (i *IndicatorSet) VOLUME(interval types.Interval) *indicatorv2.PriceStream return indicatorv2.Volumes(i.KLines(interval)) } -func (i *IndicatorSet) RSI(iw types.IntervalWindow) *momentum.RSIStream { - return momentum.RSI2(i.CLOSE(iw.Interval), iw.Window) +func (i *IndicatorSet) RSI(iw types.IntervalWindow) *indicatorv2.RSIStream { + return indicatorv2.RSI2(i.CLOSE(iw.Interval), iw.Window) } -func (i *IndicatorSet) EMA(iw types.IntervalWindow) *trend.EWMAStream { +func (i *IndicatorSet) EMA(iw types.IntervalWindow) *indicatorv2.EWMAStream { return i.EWMA(iw) } -func (i *IndicatorSet) EWMA(iw types.IntervalWindow) *trend.EWMAStream { - return trend.EWMA2(i.CLOSE(iw.Interval), iw.Window) +func (i *IndicatorSet) EWMA(iw types.IntervalWindow) *indicatorv2.EWMAStream { + return indicatorv2.EWMA2(i.CLOSE(iw.Interval), iw.Window) } -func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *momentum.StochStream { - return momentum.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) +func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *indicatorv2.StochStream { + return indicatorv2.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) } -func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *volatility.BollingerStream { - return volatility.BollingerBand(i.CLOSE(iw.Interval), iw.Window, k) +func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BollingerStream { + return indicatorv2.BollingerBand(i.CLOSE(iw.Interval), iw.Window, k) } -func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *trend.MACDStream { - return trend.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) +func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *indicatorv2.MACDStream { + return indicatorv2.MACD2(i.CLOSE(interval), shortWindow, longWindow, signalWindow) } -func (i *IndicatorSet) ATR(interval types.Interval, window int) *volatility.ATRStream { - return volatility.ATR2(i.KLines(interval), window) +func (i *IndicatorSet) ATR(interval types.Interval, window int) *indicatorv2.ATRStream { + return indicatorv2.ATR2(i.KLines(interval), window) } -func (i *IndicatorSet) ATRP(interval types.Interval, window int) *volatility.ATRPStream { - return volatility.ATRP2(i.KLines(interval), window) +func (i *IndicatorSet) ATRP(interval types.Interval, window int) *indicatorv2.ATRPStream { + return indicatorv2.ATRP2(i.KLines(interval), window) } diff --git a/pkg/exchange/bybit/types.go b/pkg/exchange/bybit/types.go index 7ae55bd857..f85d65ceaf 100644 --- a/pkg/exchange/bybit/types.go +++ b/pkg/exchange/bybit/types.go @@ -331,7 +331,7 @@ type TradeEvent struct { IndexPrice fixedpoint.Value `json:"indexPrice"` // The underlying price of the symbol when executing. Valid for option UnderlyingPrice fixedpoint.Value `json:"underlyingPrice"` - // Implied volatility. Valid for option + // Implied indicatorv2. Valid for option TradeIv string `json:"tradeIv"` } diff --git a/pkg/indicator/atrp.go b/pkg/indicator/atrp.go index d97bb0af8b..7496d005d7 100644 --- a/pkg/indicator/atrp.go +++ b/pkg/indicator/atrp.go @@ -17,7 +17,7 @@ import ( // moves (sharp price movements that are allowed under certain exchange rules). The ATR is typically smoothed using a moving average to make it // more responsive to changes in the underlying price data. The ATRP is a useful indicator for traders because it provides a way to compare the // volatility of different securities, regardless of their individual prices. It can also be used to identify potential entry and exit points -// for trades based on changes in the security's volatility. +// for trades based on changes in the security's indicatorv2. // // Calculation: // diff --git a/pkg/indicator/v2/pattern/abondoned_baby.go b/pkg/indicator/v2/abondoned_baby.go similarity index 89% rename from pkg/indicator/v2/pattern/abondoned_baby.go rename to pkg/indicator/v2/abondoned_baby.go index 327143a9e0..f40c78cccb 100644 --- a/pkg/indicator/v2/pattern/abondoned_baby.go +++ b/pkg/indicator/v2/abondoned_baby.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type AbondonedBabyStream struct { window int } -func AbondonedBaby(source v2.KLineSubscription) *AbondonedBabyStream { +func AbondonedBaby(source KLineSubscription) *AbondonedBabyStream { s := &AbondonedBabyStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/abondoned_baby_test.go b/pkg/indicator/v2/abondoned_baby_test.go similarity index 86% rename from pkg/indicator/v2/pattern/abondoned_baby_test.go rename to pkg/indicator/v2/abondoned_baby_test.go index 5922914d41..d7d2f6701f 100644 --- a/pkg/indicator/v2/pattern/abondoned_baby_test.go +++ b/pkg/indicator/v2/abondoned_baby_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestAbandonedBaby(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := AbondonedBaby(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/volume/accumulation_distiribution.go b/pkg/indicator/v2/accumulation_distiribution.go similarity index 86% rename from pkg/indicator/v2/volume/accumulation_distiribution.go rename to pkg/indicator/v2/accumulation_distiribution.go index f710869635..e7d246ca23 100644 --- a/pkg/indicator/v2/volume/accumulation_distiribution.go +++ b/pkg/indicator/v2/accumulation_distiribution.go @@ -1,8 +1,8 @@ -package volume +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +17,7 @@ type AccumulationDistributionStream struct { *types.Float64Series } -func AccumulationDistribution(source v2.KLineSubscription) *AccumulationDistributionStream { +func AccumulationDistribution(source KLineSubscription) *AccumulationDistributionStream { s := &AccumulationDistributionStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/volume/accumulation_distiribution_test.go b/pkg/indicator/v2/accumulation_distiribution_test.go similarity index 96% rename from pkg/indicator/v2/volume/accumulation_distiribution_test.go rename to pkg/indicator/v2/accumulation_distiribution_test.go index 9077b36f21..0547da6329 100644 --- a/pkg/indicator/v2/volume/accumulation_distiribution_test.go +++ b/pkg/indicator/v2/accumulation_distiribution_test.go @@ -1,4 +1,4 @@ -package volume +package indicatorv2 import ( "encoding/json" @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -30,7 +29,7 @@ func TestAccumulationDistribution(t *testing.T) { expected := []float64{4774, -4855, -12019, -18249, -21006, -39976, -48785, -52785, -47317, -48561, -47216, -49574, -49866, -49354, -47389, -50907, -48813, -32474, -25128, -27144, -18028, -20193, -18000, -33099, -32056, -41816, -50575, -53856, -58988, -51631} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := AccumulationDistribution(kLines) k := buildKLines(h, l, c, v) for _, candle := range k { diff --git a/pkg/indicator/v2/trend/alma.go b/pkg/indicator/v2/alma.go similarity index 93% rename from pkg/indicator/v2/trend/alma.go rename to pkg/indicator/v2/alma.go index 1a6e1f8e1a..37624d6e9b 100644 --- a/pkg/indicator/v2/trend/alma.go +++ b/pkg/indicator/v2/alma.go @@ -1,12 +1,11 @@ // Copyright 2022 The Coln Group Ltd // SPDX-License-Identifier: MIT -package trend +package indicatorv2 import ( "math" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -49,7 +48,7 @@ func ALMAWithSigma(source types.Float64Source, window int, offset, sigma float64 func (s *ALMAStream) Calculate(v float64) float64 { - s.sample = v2.WindowAppend(s.sample, s.window-1, v) + s.sample = WindowAppend(s.sample, s.window-1, v) if s.window < 1 { return v diff --git a/pkg/indicator/v2/trend/alma_test.go b/pkg/indicator/v2/alma_test.go similarity index 97% rename from pkg/indicator/v2/trend/alma_test.go rename to pkg/indicator/v2/alma_test.go index 0988ef7626..963c35e1f2 100644 --- a/pkg/indicator/v2/trend/alma_test.go +++ b/pkg/indicator/v2/alma_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" diff --git a/pkg/indicator/v2/atr.go b/pkg/indicator/v2/atr.go new file mode 100644 index 0000000000..da92c5c5b8 --- /dev/null +++ b/pkg/indicator/v2/atr.go @@ -0,0 +1,12 @@ +package indicatorv2 + +type ATRStream struct { + // embedded struct + *RMAStream +} + +func ATR2(source KLineSubscription, window int) *ATRStream { + tr := TR2(source) + rma := RMA2(tr, window, true) + return &ATRStream{RMAStream: rma} +} diff --git a/pkg/indicator/v2/volatility/atr_test.go b/pkg/indicator/v2/atr_test.go similarity index 96% rename from pkg/indicator/v2/volatility/atr_test.go rename to pkg/indicator/v2/atr_test.go index b103b589a9..7beb2be4c0 100644 --- a/pkg/indicator/v2/volatility/atr_test.go +++ b/pkg/indicator/v2/atr_test.go @@ -1,4 +1,4 @@ -package volatility +package indicatorv2 import ( "encoding/json" @@ -6,7 +6,6 @@ import ( "testing" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -65,7 +64,7 @@ func Test_ATR2(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") atr := ATR2(kLines, tt.window) for _, k := range tt.kLines { diff --git a/pkg/indicator/v2/volatility/atrp.go b/pkg/indicator/v2/atrp.go similarity index 61% rename from pkg/indicator/v2/volatility/atrp.go rename to pkg/indicator/v2/atrp.go index 8466e782bd..431dec8740 100644 --- a/pkg/indicator/v2/volatility/atrp.go +++ b/pkg/indicator/v2/atrp.go @@ -1,8 +1,6 @@ -package volatility +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -10,12 +8,12 @@ type ATRPStream struct { *types.Float64Series } -func ATRP2(source v2.KLineSubscription, window int) *ATRPStream { +func ATRP2(source KLineSubscription, window int) *ATRPStream { s := &ATRPStream{ Float64Series: types.NewFloat64Series(), } tr := TR2(source) - atr := trend.RMA2(tr, window, true) + atr := RMA2(tr, window, true) atr.OnUpdate(func(x float64) { // x is the last rma k := source.Last(0) diff --git a/pkg/indicator/v2/momentum/awesome_osc_test.go b/pkg/indicator/v2/awesome_osc_test.go similarity index 87% rename from pkg/indicator/v2/momentum/awesome_osc_test.go rename to pkg/indicator/v2/awesome_osc_test.go index df62f967c0..c522964782 100644 --- a/pkg/indicator/v2/momentum/awesome_osc_test.go +++ b/pkg/indicator/v2/awesome_osc_test.go @@ -1,4 +1,4 @@ -package momentum +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -28,11 +27,11 @@ func Test_AwesomeOscillator(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - prices := v2.HL2(v2.KLines(stream, "", "")) + prices := HL2(KLines(stream, "", "")) ind := AwesomeOscillator(prices) - for _, k := range buildKLines(tt.high, tt.low) { + for _, k := range buildKLinesFromHL(tt.high, tt.low) { stream.EmitKLineClosed(k) } @@ -46,7 +45,7 @@ func Test_AwesomeOscillator(t *testing.T) { } } -func buildKLines(high, low []float64) (klines []types.KLine) { +func buildKLinesFromHL(high, low []float64) (klines []types.KLine) { for i := range high { klines = append(klines, types.KLine{High: n(high[i]), Low: n(low[i])}) } diff --git a/pkg/indicator/v2/momentum/awseome_osc.go b/pkg/indicator/v2/awseome_osc.go similarity index 78% rename from pkg/indicator/v2/momentum/awseome_osc.go rename to pkg/indicator/v2/awseome_osc.go index 3e161fc486..5a5be23664 100644 --- a/pkg/indicator/v2/momentum/awseome_osc.go +++ b/pkg/indicator/v2/awseome_osc.go @@ -1,9 +1,8 @@ -package momentum +package indicatorv2 import ( "fmt" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -11,8 +10,8 @@ import ( type AwesomeOscillatorStream struct { // embedded structs *types.Float64Series - sma5 *trend.SMAStream - sma34 *trend.SMAStream + sma5 *SMAStream + sma34 *SMAStream } // Awesome Oscillator. @@ -24,8 +23,8 @@ type AwesomeOscillatorStream struct { func AwesomeOscillator(source types.Float64Source) *AwesomeOscillatorStream { s := &AwesomeOscillatorStream{ Float64Series: types.NewFloat64Series(), - sma5: trend.SMA(source, 5), - sma34: trend.SMA(source, 34), + sma5: SMA(source, 5), + sma34: SMA(source, 34), } s.Bind(source, s) return s @@ -43,8 +42,8 @@ func (s *AwesomeOscillatorStream) Calculate(v float64) float64 { prevao = s.sma5.Last(0) - s.sma34.Last(0) currDiff = ao - v prevDiff = prevao - s.Slice.Last(0) - crossOver = CrossOver(currDiff, prevDiff, 0) - crossUnder = CrossUnder(currDiff, prevDiff, 0) + crossOver = crossOver(currDiff, prevDiff, 0) + crossUnder = crossUnder(currDiff, prevDiff, 0) ) if crossOver { fmt.Println("awesome oscillator changed to green: ", ao) @@ -63,7 +62,7 @@ func (s *AwesomeOscillatorStream) Truncate() { // todo move this // CrossOver returns true if the latest series values cross above x -func CrossOver(curr, prev, x float64) bool { +func crossOver(curr, prev, x float64) bool { if prev < x && curr > x { return true } @@ -71,7 +70,7 @@ func CrossOver(curr, prev, x float64) bool { } // CrossDown returns true if the latest series values cross below x -func CrossUnder(curr, prev, x float64) bool { +func crossUnder(curr, prev, x float64) bool { if prev > x && curr < x { return true } diff --git a/pkg/indicator/v2/pattern/belthold.go b/pkg/indicator/v2/belthold.go similarity index 87% rename from pkg/indicator/v2/pattern/belthold.go rename to pkg/indicator/v2/belthold.go index 02d462343d..32cad9781a 100644 --- a/pkg/indicator/v2/pattern/belthold.go +++ b/pkg/indicator/v2/belthold.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type BeltholdStream struct { window int } -func Belthold(source v2.KLineSubscription) *BeltholdStream { +func Belthold(source KLineSubscription) *BeltholdStream { s := &BeltholdStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/belthold_test.go b/pkg/indicator/v2/belthold_test.go similarity index 90% rename from pkg/indicator/v2/pattern/belthold_test.go rename to pkg/indicator/v2/belthold_test.go index ea05022292..fef871e156 100644 --- a/pkg/indicator/v2/pattern/belthold_test.go +++ b/pkg/indicator/v2/belthold_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestBelthold(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Belthold(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/volatility/bollinger_band.go b/pkg/indicator/v2/bollinger_band.go similarity index 91% rename from pkg/indicator/v2/volatility/bollinger_band.go rename to pkg/indicator/v2/bollinger_band.go index f414c56d3e..0a90bd9988 100644 --- a/pkg/indicator/v2/volatility/bollinger_band.go +++ b/pkg/indicator/v2/bollinger_band.go @@ -1,7 +1,6 @@ -package volatility +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ type BollingerStream struct { k float64 SMA *trend.SMAStream - StdDev *v2.StdDevStream + StdDev *StdDevStream } // BOOL2 is bollinger indicator @@ -28,7 +27,7 @@ type BollingerStream struct { func BollingerBand(source types.Float64Source, window int, k float64) *BollingerStream { // bind these indicators before our main calculator sma := trend.SMA(source, window) - stdDev := v2.StdDev(source, window) + stdDev := StdDev(source, window) s := &BollingerStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/volatility/bollinger_band_test.go b/pkg/indicator/v2/bollinger_band_test.go similarity index 99% rename from pkg/indicator/v2/volatility/bollinger_band_test.go rename to pkg/indicator/v2/bollinger_band_test.go index a431179ddb..3fc9928c54 100644 --- a/pkg/indicator/v2/volatility/bollinger_band_test.go +++ b/pkg/indicator/v2/bollinger_band_test.go @@ -1,4 +1,4 @@ -package volatility +package indicatorv2 import ( "strconv" diff --git a/pkg/indicator/v2/pattern/breakaway.go b/pkg/indicator/v2/breakaway.go similarity index 90% rename from pkg/indicator/v2/pattern/breakaway.go rename to pkg/indicator/v2/breakaway.go index 29868557d9..7e37a38c14 100644 --- a/pkg/indicator/v2/pattern/breakaway.go +++ b/pkg/indicator/v2/breakaway.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type BreakAwayStream struct { window int } -func BreakAway(source v2.KLineSubscription) *BreakAwayStream { +func BreakAway(source KLineSubscription) *BreakAwayStream { s := &BreakAwayStream{ Float64Series: types.NewFloat64Series(), window: 5, diff --git a/pkg/indicator/v2/pattern/breakaway_test.go b/pkg/indicator/v2/breakaway_test.go similarity index 92% rename from pkg/indicator/v2/pattern/breakaway_test.go rename to pkg/indicator/v2/breakaway_test.go index 0315c2e112..a267495a88 100644 --- a/pkg/indicator/v2/pattern/breakaway_test.go +++ b/pkg/indicator/v2/breakaway_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +16,7 @@ func TestBreakAway(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := BreakAway(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/cci.go b/pkg/indicator/v2/cci.go similarity index 99% rename from pkg/indicator/v2/trend/cci.go rename to pkg/indicator/v2/cci.go index b1ea70609d..77ca9e0bf0 100644 --- a/pkg/indicator/v2/trend/cci.go +++ b/pkg/indicator/v2/cci.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "math" diff --git a/pkg/indicator/v2/trend/cci_test.go b/pkg/indicator/v2/cci_test.go similarity index 91% rename from pkg/indicator/v2/trend/cci_test.go rename to pkg/indicator/v2/cci_test.go index 30291c2ec8..a662553ba2 100644 --- a/pkg/indicator/v2/trend/cci_test.go +++ b/pkg/indicator/v2/cci_test.go @@ -1,12 +1,10 @@ -package trend +package indicatorv2 import ( "encoding/json" "testing" "github.com/stretchr/testify/assert" - - v2 "github.com/c9s/bbgo/pkg/indicator/v2" ) /* @@ -25,7 +23,7 @@ func Test_CCI(t *testing.T) { panic(err) } t.Run("random_case", func(t *testing.T) { - price := v2.Price(nil, nil) + price := Price(nil, nil) cci := CCI(price, 16) for _, value := range input { price.PushAndEmit(value) diff --git a/pkg/indicator/v2/volume/chaikin_money_flow.go b/pkg/indicator/v2/chaikin_money_flow.go similarity index 69% rename from pkg/indicator/v2/volume/chaikin_money_flow.go rename to pkg/indicator/v2/chaikin_money_flow.go index e8f28f41de..29b2f4846e 100644 --- a/pkg/indicator/v2/volume/chaikin_money_flow.go +++ b/pkg/indicator/v2/chaikin_money_flow.go @@ -1,10 +1,10 @@ -package volume +package indicatorv2 import ( "gonum.org/v1/gonum/floats" bbfloat "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -20,16 +20,16 @@ type ChaikinMoneyFlowStream struct { // Money Flow Multiplier = ((Closing - Low) - (High - Closing)) / (High - Low) // Money Flow Volume = Money Flow Multiplier * Volume // Chaikin Money Flow = Sum(20, Money Flow Volume) / Sum(20, Volume) -func ChaikinMoneyFlow(source v2.KLineSubscription, window int) *ChaikinMoneyFlowStream { +func ChaikinMoneyFlow(source KLineSubscription, window int) *ChaikinMoneyFlowStream { var ( - closing = v2.ClosePrices(source) - low = v2.LowPrices(source) - high = v2.HighPrices(source) - volume = v2.Volumes(source) - cl = v2.Subtract(closing, low) - hc = v2.Subtract(high, closing) - flow = v2.Subtract(cl, hc) - hl = v2.Subtract(high, low) + closing = ClosePrices(source) + low = LowPrices(source) + high = HighPrices(source) + volume = Volumes(source) + cl = Subtract(closing, low) + hc = Subtract(high, closing) + flow = Subtract(cl, hc) + hl = Subtract(high, low) s = &ChaikinMoneyFlowStream{ Float64Series: types.NewFloat64Series(), window: window, @@ -53,6 +53,6 @@ func (s *ChaikinMoneyFlowStream) Truncate() { s.Slice = s.Slice.Truncate(5000) } -func ChaikinMoneyFlowDefault(source v2.KLineSubscription) *ChaikinMoneyFlowStream { +func ChaikinMoneyFlowDefault(source KLineSubscription) *ChaikinMoneyFlowStream { return ChaikinMoneyFlow(source, 20) } diff --git a/pkg/indicator/v2/volume/chaikin_money_flow_test.go b/pkg/indicator/v2/chaikin_money_flow_test.go similarity index 89% rename from pkg/indicator/v2/volume/chaikin_money_flow_test.go rename to pkg/indicator/v2/chaikin_money_flow_test.go index 350e08e33d..348726cf3b 100644 --- a/pkg/indicator/v2/volume/chaikin_money_flow_test.go +++ b/pkg/indicator/v2/chaikin_money_flow_test.go @@ -1,11 +1,10 @@ -package volume +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -20,7 +19,7 @@ func TestChaikinMoneyFlow(t *testing.T) { expected := []float64{0.5, 1.81, 0.67, -0.41, -0.87} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ChaikinMoneyFlowDefault(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/momentum/chaikin_osc.go b/pkg/indicator/v2/chaikin_osc.go similarity index 55% rename from pkg/indicator/v2/momentum/chaikin_osc.go rename to pkg/indicator/v2/chaikin_osc.go index ef833dd47f..a78d20cdd6 100644 --- a/pkg/indicator/v2/momentum/chaikin_osc.go +++ b/pkg/indicator/v2/chaikin_osc.go @@ -1,16 +1,13 @@ -package momentum +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" - "github.com/c9s/bbgo/pkg/indicator/v2/volume" "github.com/c9s/bbgo/pkg/types" ) // The DefaultChaikinOscillator function calculates Chaikin // Oscillator with the most frequently used fast and short // periods, 3 and 10. -func NewChaikinOscillatorDefault(source v2.KLineSubscription) *ChaikinOscillatorStream { +func NewChaikinOscillatorDefault(source KLineSubscription) *ChaikinOscillatorStream { return ChaikinOscillator(source, 3, 10) } @@ -19,10 +16,10 @@ type ChaikinOscillatorStream struct { *types.Float64Series } -func ChaikinOscillator(source v2.KLineSubscription, slow, fast int) *ChaikinOscillatorStream { +func ChaikinOscillator(source KLineSubscription, slow, fast int) *ChaikinOscillatorStream { var ( - accDist = volume.AccumulationDistribution(source) - diff = v2.Subtract(trend.EWMA2(accDist, slow), trend.EWMA2(accDist, fast)) + accDist = AccumulationDistribution(source) + diff = Subtract(EWMA2(accDist, slow), EWMA2(accDist, fast)) s = &ChaikinOscillatorStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/momentum/chaikin_osc_test.go b/pkg/indicator/v2/chaikin_osc_test.go similarity index 82% rename from pkg/indicator/v2/momentum/chaikin_osc_test.go rename to pkg/indicator/v2/chaikin_osc_test.go index a5b72661e4..dea8050935 100644 --- a/pkg/indicator/v2/momentum/chaikin_osc_test.go +++ b/pkg/indicator/v2/chaikin_osc_test.go @@ -1,12 +1,10 @@ -package momentum +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -25,7 +23,7 @@ func Test_ChaikinOscillator(t *testing.T) { expected := []float64{0, -7.41, -18.52, -31.69, -46.09, -61.27, -76.95, -92.97} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ChaikinOscillator(kLines, 2, 5) for _, candle := range ts { @@ -35,7 +33,3 @@ func Test_ChaikinOscillator(t *testing.T) { assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected chaikin_osc.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) } } - -func n(n float64) fixedpoint.Value { - return fixedpoint.NewFromFloat(n) -} diff --git a/pkg/indicator/v2/volatility/chandelier_exit.go b/pkg/indicator/v2/chandelier_exit.go similarity index 72% rename from pkg/indicator/v2/volatility/chandelier_exit.go rename to pkg/indicator/v2/chandelier_exit.go index 6b7de2b421..cec0623f6f 100644 --- a/pkg/indicator/v2/volatility/chandelier_exit.go +++ b/pkg/indicator/v2/chandelier_exit.go @@ -1,7 +1,6 @@ -package volatility +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -21,8 +20,8 @@ type ChandelierExitStream struct { *types.Float64Series atr *ATRStream - min *v2.MinValueStream - max *v2.MaxValueStream + min *MinValueStream + max *MaxValueStream } // Chandelier Exit. It sets a trailing stop-loss based on the Average True Value (ATR). @@ -31,11 +30,11 @@ type ChandelierExitStream struct { // Chandelier Exit Short = 22-Period SMA Low + ATR(22) * 3 // // Returns chandelierExitLong, chandelierExitShort -func ChandelierExit(source v2.KLineSubscription, os OrderSide, window int) *ChandelierExitStream { +func ChandelierExit(source KLineSubscription, os OrderSide, window int) *ChandelierExitStream { s := &ChandelierExitStream{ atr: ATR2(source, window), - min: v2.MinValue(v2.LowPrices(source), window), - max: v2.MaxValue(v2.HighPrices(source), window)} + min: MinValue(LowPrices(source), window), + max: MaxValue(HighPrices(source), window)} source.AddSubscriber(func(v types.KLine) { high := s.max.Last(0) @@ -53,7 +52,7 @@ func ChandelierExit(source v2.KLineSubscription, os OrderSide, window int) *Chan return s } -func ChandelierExitDefault(source v2.KLineSubscription, os OrderSide) *ChandelierExitStream { +func ChandelierExitDefault(source KLineSubscription, os OrderSide) *ChandelierExitStream { return ChandelierExit(source, os, 22) } diff --git a/pkg/indicator/v2/trend/cma.go b/pkg/indicator/v2/cma.go similarity index 96% rename from pkg/indicator/v2/trend/cma.go rename to pkg/indicator/v2/cma.go index ffccf295eb..9d0cbea648 100644 --- a/pkg/indicator/v2/trend/cma.go +++ b/pkg/indicator/v2/cma.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/indicator" diff --git a/pkg/indicator/v2/pattern/dark_cloud.go b/pkg/indicator/v2/dark_cloud.go similarity index 91% rename from pkg/indicator/v2/pattern/dark_cloud.go rename to pkg/indicator/v2/dark_cloud.go index 4f018bf88d..5a5939c366 100644 --- a/pkg/indicator/v2/pattern/dark_cloud.go +++ b/pkg/indicator/v2/dark_cloud.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +16,7 @@ type DarkCloudStream struct { // the prior bullish candle. // Both candles should be relatively large, showing strong participation by traders and investors. // When the pattern occurs with small candles it is typically less significant. -func DarkCloud(source v2.KLineSubscription) *DarkCloudStream { +func DarkCloud(source KLineSubscription) *DarkCloudStream { s := &DarkCloudStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/dark_cloud_test.go b/pkg/indicator/v2/dark_cloud_test.go similarity index 84% rename from pkg/indicator/v2/pattern/dark_cloud_test.go rename to pkg/indicator/v2/dark_cloud_test.go index 87b7355ff8..b9e06fe502 100644 --- a/pkg/indicator/v2/pattern/dark_cloud_test.go +++ b/pkg/indicator/v2/dark_cloud_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestDarkCloud(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := DarkCloud(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/dema.go b/pkg/indicator/v2/dema.go similarity index 98% rename from pkg/indicator/v2/trend/dema.go rename to pkg/indicator/v2/dema.go index 84bea5c030..2f3e242b80 100644 --- a/pkg/indicator/v2/trend/dema.go +++ b/pkg/indicator/v2/dema.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/pattern/doji.go b/pkg/indicator/v2/doji.go similarity index 89% rename from pkg/indicator/v2/pattern/doji.go rename to pkg/indicator/v2/doji.go index e60c379639..03668801ba 100644 --- a/pkg/indicator/v2/pattern/doji.go +++ b/pkg/indicator/v2/doji.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +14,7 @@ type DojiStream struct { // A doji formation generally can be interpreted as a sign of indecision, meaning neither bulls nor bears // can successfully take over. Of its variations, the dragonfly doji is seen as a bullish reversal pattern // that occurs at the bottom of downtrends. The gravestone doji is read as a bearish reversal at the peak of uptrends. -func Doji(source v2.KLineSubscription, maxDiff float64) *DojiStream { +func Doji(source KLineSubscription, maxDiff float64) *DojiStream { s := &DojiStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly.go b/pkg/indicator/v2/doji_dragon_fly.go similarity index 83% rename from pkg/indicator/v2/pattern/doji_dragon_fly.go rename to pkg/indicator/v2/doji_dragon_fly.go index 06ad563f24..f0dc717ecd 100644 --- a/pkg/indicator/v2/pattern/doji_dragon_fly.go +++ b/pkg/indicator/v2/doji_dragon_fly.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -10,7 +10,7 @@ type DojiDragonFlyStream struct { *types.Float64Series } -func DojiDragonFly(source v2.KLineSubscription, maxDiff float64) *DojiDragonFlyStream { +func DojiDragonFly(source KLineSubscription, maxDiff float64) *DojiDragonFlyStream { s := &DojiDragonFlyStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/pattern/doji_dragon_fly_test.go b/pkg/indicator/v2/doji_dragon_fly_test.go similarity index 89% rename from pkg/indicator/v2/pattern/doji_dragon_fly_test.go rename to pkg/indicator/v2/doji_dragon_fly_test.go index 4abd171f05..7d22023f6e 100644 --- a/pkg/indicator/v2/pattern/doji_dragon_fly_test.go +++ b/pkg/indicator/v2/doji_dragon_fly_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestDojiDragonFly(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := DojiDragonFly(kLines, 0.05) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/doji_gravestone.go b/pkg/indicator/v2/doji_gravestone.go similarity index 88% rename from pkg/indicator/v2/pattern/doji_gravestone.go rename to pkg/indicator/v2/doji_gravestone.go index 32781763e0..7c6bf57ba8 100644 --- a/pkg/indicator/v2/pattern/doji_gravestone.go +++ b/pkg/indicator/v2/doji_gravestone.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +14,7 @@ type DojiGraveStoneStream struct { // may soon undergo a bearish reversal. This pattern forms when the open, low, and closing prices of an asset // are close to each other and have a long upper shadow. The shadow in a candlestick chart is the thin part // showing the price action for the day as it differs from high to low prices. -func DojiGraveStone(source v2.KLineSubscription, maxDiff float64) *DojiGraveStoneStream { +func DojiGraveStone(source KLineSubscription, maxDiff float64) *DojiGraveStoneStream { s := &DojiGraveStoneStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/pattern/doji_gravestone_test.go b/pkg/indicator/v2/doji_gravestone_test.go similarity index 89% rename from pkg/indicator/v2/pattern/doji_gravestone_test.go rename to pkg/indicator/v2/doji_gravestone_test.go index 32f5b4fed8..7ab788d0a8 100644 --- a/pkg/indicator/v2/pattern/doji_gravestone_test.go +++ b/pkg/indicator/v2/doji_gravestone_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestDojiGraveStone(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := DojiGraveStone(kLines, 0.05) for _, candle := range hasPattern { diff --git a/pkg/indicator/v2/pattern/doji_long_legged.go b/pkg/indicator/v2/doji_long_legged.go similarity index 93% rename from pkg/indicator/v2/pattern/doji_long_legged.go rename to pkg/indicator/v2/doji_long_legged.go index f2e19f1ef0..c05f86a4b6 100644 --- a/pkg/indicator/v2/pattern/doji_long_legged.go +++ b/pkg/indicator/v2/doji_long_legged.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +17,7 @@ type DojiLongLeggedStream struct { // the same opening and closing prices. In addition to signaling indecision, the long-legged doji can also // indicate the beginning of a consolidation period where price action may soon break out to form a new trend. // These doji can be a sign that sentiment is changing and that a trend reversal is on the horizon. -func DojiLongLegged(source v2.KLineSubscription) *DojiLongLeggedStream { +func DojiLongLegged(source KLineSubscription) *DojiLongLeggedStream { s := &DojiLongLeggedStream{ Float64Series: types.NewFloat64Series(), window: 4, diff --git a/pkg/indicator/v2/pattern/doji_long_legged_test.go b/pkg/indicator/v2/doji_long_legged_test.go similarity index 92% rename from pkg/indicator/v2/pattern/doji_long_legged_test.go rename to pkg/indicator/v2/doji_long_legged_test.go index 38db4b6d08..db694dcd38 100644 --- a/pkg/indicator/v2/pattern/doji_long_legged_test.go +++ b/pkg/indicator/v2/doji_long_legged_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -16,7 +15,7 @@ func TestDojiLongLegged(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := DojiLongLegged(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/doji_star.go b/pkg/indicator/v2/doji_star.go similarity index 91% rename from pkg/indicator/v2/pattern/doji_star.go rename to pkg/indicator/v2/doji_star.go index 95bac42ec4..90455800a9 100644 --- a/pkg/indicator/v2/pattern/doji_star.go +++ b/pkg/indicator/v2/doji_star.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +13,7 @@ type DojiStarStream struct { } // maxDiff is the maximum deviation between a and b to consider them approximately equal -func DojiStar(source v2.KLineSubscription, direction Direction, maxDiff float64) *DojiStarStream { +func DojiStar(source KLineSubscription, direction Direction, maxDiff float64) *DojiStarStream { s := &DojiStarStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/doji_star_test.go b/pkg/indicator/v2/doji_star_test.go similarity index 89% rename from pkg/indicator/v2/pattern/doji_star_test.go rename to pkg/indicator/v2/doji_star_test.go index 3ec28b72fc..df3083dc14 100644 --- a/pkg/indicator/v2/pattern/doji_star_test.go +++ b/pkg/indicator/v2/doji_star_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestDojiStar(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := DojiStar(kLines, Bearish, 0.05) for _, candle := range ts { @@ -33,7 +32,7 @@ func TestDojiStar(t *testing.T) { {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(21.58)}, } stream = &types.StandardStream{} - kLines = v2.KLines(stream, "", "") + kLines = KLines(stream, "", "") ind = DojiStar(kLines, Bullish, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/doji_test.go b/pkg/indicator/v2/doji_test.go similarity index 89% rename from pkg/indicator/v2/pattern/doji_test.go rename to pkg/indicator/v2/doji_test.go index d5cbc22220..679699f76f 100644 --- a/pkg/indicator/v2/pattern/doji_test.go +++ b/pkg/indicator/v2/doji_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestDoji(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Doji(kLines, 0.05) for _, candle := range ts { diff --git a/pkg/indicator/v2/volatility/donchian_channel.go b/pkg/indicator/v2/donchian_channel.go similarity index 87% rename from pkg/indicator/v2/volatility/donchian_channel.go rename to pkg/indicator/v2/donchian_channel.go index 7040c7c58e..4629102368 100644 --- a/pkg/indicator/v2/volatility/donchian_channel.go +++ b/pkg/indicator/v2/donchian_channel.go @@ -1,7 +1,6 @@ -package volatility +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -19,9 +18,9 @@ type DonchianChannelStream struct { // Upper Channel = Mmax(period, closings) // Lower Channel = Mmin(period, closings) // Middle Channel = (Upper Channel + Lower Channel) / 2 -func DonchianChannel(source v2.KLineSubscription, window int) *DonchianChannelStream { +func DonchianChannel(source KLineSubscription, window int) *DonchianChannelStream { var ( - closing = v2.ClosePrices(source) + closing = ClosePrices(source) s = &DonchianChannelStream{ UpBand: types.NewFloat64Series(), DownBand: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/volatility/donchian_channel_test.go b/pkg/indicator/v2/donchian_channel_test.go similarity index 89% rename from pkg/indicator/v2/volatility/donchian_channel_test.go rename to pkg/indicator/v2/donchian_channel_test.go index 6f15200488..f7c905adb1 100644 --- a/pkg/indicator/v2/volatility/donchian_channel_test.go +++ b/pkg/indicator/v2/donchian_channel_test.go @@ -1,4 +1,4 @@ -package volatility +package indicatorv2 import ( "testing" @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +17,8 @@ func TestDonchianChannel(t *testing.T) { expectedLower := []float64{9, 9, 7, 7, 7} stream := &types.StandardStream{} - ind := DonchianChannel(v2.KLines(stream, "", ""), 4) + kLines := KLines(stream, "", "") + ind := DonchianChannel(kLines, 4) for i := range closing { stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(closing[i])}) } diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap.go b/pkg/indicator/v2/downside_tazuki_gap.go similarity index 89% rename from pkg/indicator/v2/pattern/downside_tazuki_gap.go rename to pkg/indicator/v2/downside_tazuki_gap.go index c117e00e7c..1d47b752ff 100644 --- a/pkg/indicator/v2/pattern/downside_tazuki_gap.go +++ b/pkg/indicator/v2/downside_tazuki_gap.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type TazukiGapStream struct { window int } -func TazukiGap(source v2.KLineSubscription) *TazukiGapStream { +func TazukiGap(source KLineSubscription) *TazukiGapStream { s := &TazukiGapStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go b/pkg/indicator/v2/downside_tazuki_gap_test.go similarity index 86% rename from pkg/indicator/v2/pattern/downside_tazuki_gap_test.go rename to pkg/indicator/v2/downside_tazuki_gap_test.go index 00d69da423..47d2b4e497 100644 --- a/pkg/indicator/v2/pattern/downside_tazuki_gap_test.go +++ b/pkg/indicator/v2/downside_tazuki_gap_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestTazukiGap(t *testing.T) { {Open: n(30.20), Low: n(29.80), High: n(36.63), Close: n(36.28)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := TazukiGap(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/ema.go b/pkg/indicator/v2/ema.go similarity index 96% rename from pkg/indicator/v2/trend/ema.go rename to pkg/indicator/v2/ema.go index e67d5363d7..fdd9745f0d 100644 --- a/pkg/indicator/v2/trend/ema.go +++ b/pkg/indicator/v2/ema.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/trend/ema_test.go b/pkg/indicator/v2/ema_test.go similarity index 86% rename from pkg/indicator/v2/trend/ema_test.go rename to pkg/indicator/v2/ema_test.go index bc3012dde0..10e45c61f2 100644 --- a/pkg/indicator/v2/trend/ema_test.go +++ b/pkg/indicator/v2/ema_test.go @@ -1,11 +1,9 @@ -package trend +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - - v2 "github.com/c9s/bbgo/pkg/indicator/v2" ) func TestExponentialMovingAverage(t *testing.T) { @@ -20,7 +18,7 @@ func TestExponentialMovingAverage(t *testing.T) { 63.7, 63.76, 63.43, 63.41, 62.58, 62.15, } - prices := v2.ClosePrices(nil) + prices := ClosePrices(nil) ind := EWMA2(prices, 4) for _, price := range closing { diff --git a/pkg/indicator/v2/pattern/engulfing.go b/pkg/indicator/v2/engulfing.go similarity index 88% rename from pkg/indicator/v2/pattern/engulfing.go rename to pkg/indicator/v2/engulfing.go index fc043f1699..39ad68b107 100644 --- a/pkg/indicator/v2/pattern/engulfing.go +++ b/pkg/indicator/v2/engulfing.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +11,7 @@ type EngulfingStream struct { } // Bullish engulfing patterns are more likely to signal reversals when they are preceded by four or more black candlesticks. -func Engulfing(source v2.KLineSubscription) *EngulfingStream { +func Engulfing(source KLineSubscription) *EngulfingStream { s := &EngulfingStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/engulfing_test.go b/pkg/indicator/v2/engulfing_test.go similarity index 90% rename from pkg/indicator/v2/pattern/engulfing_test.go rename to pkg/indicator/v2/engulfing_test.go index 90db9e8c7f..38a67cd3af 100644 --- a/pkg/indicator/v2/pattern/engulfing_test.go +++ b/pkg/indicator/v2/engulfing_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestEngulfing(t *testing.T) { {Open: n(100), Low: n(65), High: n(105), Close: n(70)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Engulfing(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/harami.go b/pkg/indicator/v2/harami.go similarity index 91% rename from pkg/indicator/v2/pattern/harami.go rename to pkg/indicator/v2/harami.go index 1a3a294e72..4d90aa82be 100644 --- a/pkg/indicator/v2/pattern/harami.go +++ b/pkg/indicator/v2/harami.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ type HaramiStream struct { // referred to as a doji, that is completely contained within the vertical range of the previous body. // To some, a line drawn around this pattern resembles a pregnant woman. The word harami comes from an // old Japanese word meaning pregnant. -func Harami(source v2.KLineSubscription) *HaramiStream { +func Harami(source KLineSubscription) *HaramiStream { s := &HaramiStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/harami_cross.go b/pkg/indicator/v2/harami_cross.go similarity index 93% rename from pkg/indicator/v2/pattern/harami_cross.go rename to pkg/indicator/v2/harami_cross.go index 6300f3c5e1..0ad9560a86 100644 --- a/pkg/indicator/v2/pattern/harami_cross.go +++ b/pkg/indicator/v2/harami_cross.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -23,7 +23,7 @@ type HaramiCrossStream struct { // must be contained within the real body of the prior candle. // If the price drops following the pattern, this confirms the pattern. // If the price continues to rise following the doji, the bearish pattern is invalidated. -func HaramiCross(source v2.KLineSubscription, direction Direction, maxDiff float64) *HaramiCrossStream { +func HaramiCross(source KLineSubscription, direction Direction, maxDiff float64) *HaramiCrossStream { s := &HaramiCrossStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/harami_cross_test.go b/pkg/indicator/v2/harami_cross_test.go similarity index 91% rename from pkg/indicator/v2/pattern/harami_cross_test.go rename to pkg/indicator/v2/harami_cross_test.go index 2d77f17472..ead6827e67 100644 --- a/pkg/indicator/v2/pattern/harami_cross_test.go +++ b/pkg/indicator/v2/harami_cross_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestHaramiCross(t *testing.T) { {Open: n(22.13), Low: n(21.31), High: n(22.76), Close: n(22.13)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := HaramiCross(kLines, Bearish, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/harami_test.go b/pkg/indicator/v2/harami_test.go similarity index 90% rename from pkg/indicator/v2/pattern/harami_test.go rename to pkg/indicator/v2/harami_test.go index 54c105d59e..2a79fdc43e 100644 --- a/pkg/indicator/v2/pattern/harami_test.go +++ b/pkg/indicator/v2/harami_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestHarami(t *testing.T) { {Open: n(110), Low: n(100), High: n(115), Close: n(105)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Harami(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/head_shoulders.go b/pkg/indicator/v2/head_shoulders.go similarity index 73% rename from pkg/indicator/v2/pattern/head_shoulders.go rename to pkg/indicator/v2/head_shoulders.go index 9b11fa0e06..e5b05a1a7b 100644 --- a/pkg/indicator/v2/pattern/head_shoulders.go +++ b/pkg/indicator/v2/head_shoulders.go @@ -1,28 +1,27 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) type HeadShoulderStream struct { *types.Float64Series - max *v2.MaxValueStream - min *v2.MinValueStream + max *MaxValueStream + min *MinValueStream window int } // Basic Head-Shoulder Detection -func HeadShoulderSimple(source v2.KLineSubscription) *HeadShoulderStream { +func HeadShoulderSimple(source KLineSubscription) *HeadShoulderStream { var ( window = 3 - high = v2.HighPrices(source) - low = v2.LowPrices(source) + high = HighPrices(source) + low = LowPrices(source) s = &HeadShoulderStream{ Float64Series: types.NewFloat64Series(), - max: v2.MaxValue(high, window), - min: v2.MinValue(low, window), + max: MaxValue(high, window), + min: MinValue(low, window), window: window, } ) diff --git a/pkg/indicator/v2/pattern/head_shoulders_test.go b/pkg/indicator/v2/head_shoulders_test.go similarity index 94% rename from pkg/indicator/v2/pattern/head_shoulders_test.go rename to pkg/indicator/v2/head_shoulders_test.go index f6dda70522..f8639f6b61 100644 --- a/pkg/indicator/v2/pattern/head_shoulders_test.go +++ b/pkg/indicator/v2/head_shoulders_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -21,7 +20,7 @@ func TestHeadShoulderSimple(t *testing.T) { {Open: n(90), Low: n(80), High: n(95), Close: n(90)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := HeadShoulderSimple(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/kdj.go b/pkg/indicator/v2/kdj.go similarity index 79% rename from pkg/indicator/v2/trend/kdj.go rename to pkg/indicator/v2/kdj.go index 339c022f80..ca7d89f1fc 100644 --- a/pkg/indicator/v2/trend/kdj.go +++ b/pkg/indicator/v2/kdj.go @@ -1,7 +1,6 @@ -package trend +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -9,8 +8,8 @@ type KDJStream struct { *types.Float64Series K *SMAStream D *SMAStream - min *v2.MinValueStream - max *v2.MaxValueStream + min *MinValueStream + max *MaxValueStream window int } @@ -30,12 +29,12 @@ type KDJStream struct { // K = Sma(RSV, kPeriod) // D = Sma(K, dPeriod) // J = (3 * K) - (2 * D) -func KDJ(source v2.KLineSubscription, window, kWindow, dWindow int) *KDJStream { +func KDJ(source KLineSubscription, window, kWindow, dWindow int) *KDJStream { s := &KDJStream{ Float64Series: types.NewFloat64Series(), - min: v2.MinValue(v2.LowPrices(source), window), - max: v2.MaxValue(v2.HighPrices(source), window), + min: MinValue(LowPrices(source), window), + max: MaxValue(HighPrices(source), window), K: SMA(nil, kWindow), D: SMA(nil, dWindow), window: window, @@ -58,7 +57,7 @@ func KDJ(source v2.KLineSubscription, window, kWindow, dWindow int) *KDJStream { // The DefaultKdj function calculates KDJ based on default periods // consisting of window of 9, kPeriod of 3, and dPeriod of 3. -func KDJDefault(source v2.KLineSubscription) *KDJStream { +func KDJDefault(source KLineSubscription) *KDJStream { return KDJ(source, 9, 3, 3) } diff --git a/pkg/indicator/v2/trend/kdj_test.go b/pkg/indicator/v2/kdj_test.go similarity index 92% rename from pkg/indicator/v2/trend/kdj_test.go rename to pkg/indicator/v2/kdj_test.go index 6f52615903..19329f9706 100644 --- a/pkg/indicator/v2/trend/kdj_test.go +++ b/pkg/indicator/v2/kdj_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -28,7 +27,7 @@ func TestKdj(t *testing.T) { expectedJ := []float64{44.44, 47.37, 48.72, 50.55, 50.32, 49.70, 49.58, 49.56, 49.57, 49.19} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := KDJDefault(kLines) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/pattern/kicking.go b/pkg/indicator/v2/kicking.go similarity index 91% rename from pkg/indicator/v2/pattern/kicking.go rename to pkg/indicator/v2/kicking.go index 3f26ee48d0..94b080bf0a 100644 --- a/pkg/indicator/v2/pattern/kicking.go +++ b/pkg/indicator/v2/kicking.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type KickingStream struct { window int } -func Kicking(source v2.KLineSubscription, maxDiff float64) *KickingStream { +func Kicking(source KLineSubscription, maxDiff float64) *KickingStream { s := &KickingStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/kicking_test.go b/pkg/indicator/v2/kicking_test.go similarity index 90% rename from pkg/indicator/v2/pattern/kicking_test.go rename to pkg/indicator/v2/kicking_test.go index 7a5e1ca68c..53e9a5634b 100644 --- a/pkg/indicator/v2/pattern/kicking_test.go +++ b/pkg/indicator/v2/kicking_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ func TestKicking(t *testing.T) { {Open: n(90), Low: n(70), High: n(90), Close: n(70)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Kicking(kLines, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/macd.go b/pkg/indicator/v2/macd.go similarity index 76% rename from pkg/indicator/v2/trend/macd.go rename to pkg/indicator/v2/macd.go index dc862b8937..1679cf6c09 100644 --- a/pkg/indicator/v2/trend/macd.go +++ b/pkg/indicator/v2/macd.go @@ -1,26 +1,25 @@ -package trend +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) type MACDStream struct { - *v2.SubtractStream + *SubtractStream shortWindow, longWindow, signalWindow int FastEWMA, SlowEWMA, Signal *EWMAStream - Histogram *v2.SubtractStream + Histogram *SubtractStream } func MACD2(source types.Float64Source, shortWindow, longWindow, signalWindow int) *MACDStream { // bind and calculate these first fastEWMA := EWMA2(source, shortWindow) slowEWMA := EWMA2(source, longWindow) - macd := v2.Subtract(fastEWMA, slowEWMA) + macd := Subtract(fastEWMA, slowEWMA) signal := EWMA2(macd, signalWindow) - histogram := v2.Subtract(macd, signal) + histogram := Subtract(macd, signal) return &MACDStream{ SubtractStream: macd, shortWindow: shortWindow, diff --git a/pkg/indicator/v2/trend/macd_test.go b/pkg/indicator/v2/macd_test.go similarity index 94% rename from pkg/indicator/v2/trend/macd_test.go rename to pkg/indicator/v2/macd_test.go index 4d20e46fdb..40778ca3c4 100644 --- a/pkg/indicator/v2/trend/macd_test.go +++ b/pkg/indicator/v2/macd_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "encoding/json" @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -50,7 +50,7 @@ func Test_MACD2(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - prices := v2.ClosePrices(nil) + prices := ClosePrices(nil) macd := MACD2(prices, 12, 26, 9) for _, k := range tt.kLines { prices.EmitUpdate(k.Close.Float64()) diff --git a/pkg/indicator/v2/pattern/marubozu.go b/pkg/indicator/v2/marubozu.go similarity index 86% rename from pkg/indicator/v2/pattern/marubozu.go rename to pkg/indicator/v2/marubozu.go index 9f1a156106..de1e4a4e3c 100644 --- a/pkg/indicator/v2/pattern/marubozu.go +++ b/pkg/indicator/v2/marubozu.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type MarubozuStream struct { window int } -func Marubozu(source v2.KLineSubscription, maxDiff float64) *MarubozuStream { +func Marubozu(source KLineSubscription, maxDiff float64) *MarubozuStream { s := &MarubozuStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/marubozu_test.go b/pkg/indicator/v2/marubozu_test.go similarity index 89% rename from pkg/indicator/v2/pattern/marubozu_test.go rename to pkg/indicator/v2/marubozu_test.go index e920916823..0cb0ada31d 100644 --- a/pkg/indicator/v2/pattern/marubozu_test.go +++ b/pkg/indicator/v2/marubozu_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +11,7 @@ func TestMarubozu(t *testing.T) { {Open: n(200), Low: n(100), High: n(200), Close: n(100)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Marubozu(kLines, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/maxval.go b/pkg/indicator/v2/maxval.go index b9f6d5e2e3..66d3bcb372 100644 --- a/pkg/indicator/v2/maxval.go +++ b/pkg/indicator/v2/maxval.go @@ -1,8 +1,8 @@ package indicatorv2 import ( - "github.com/c9s/bbgo/pkg/indicator/v2/bst" "github.com/c9s/bbgo/pkg/types" + "github.com/c9s/bbgo/pkg/types/bst" ) type MaxValueStream struct { diff --git a/pkg/indicator/v2/pattern/meeting_lines.go b/pkg/indicator/v2/meeting_lines.go similarity index 89% rename from pkg/indicator/v2/pattern/meeting_lines.go rename to pkg/indicator/v2/meeting_lines.go index 164484c857..80a9617f20 100644 --- a/pkg/indicator/v2/pattern/meeting_lines.go +++ b/pkg/indicator/v2/meeting_lines.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type MeetingLinesStream struct { window int } -func MeetingLines(source v2.KLineSubscription) *MeetingLinesStream { +func MeetingLines(source KLineSubscription) *MeetingLinesStream { s := &MeetingLinesStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/meeting_lines_test.go b/pkg/indicator/v2/meeting_lines_test.go similarity index 91% rename from pkg/indicator/v2/pattern/meeting_lines_test.go rename to pkg/indicator/v2/meeting_lines_test.go index 67da02dc60..2ae5d4ab2c 100644 --- a/pkg/indicator/v2/pattern/meeting_lines_test.go +++ b/pkg/indicator/v2/meeting_lines_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestMeetingLines(t *testing.T) { {Open: n(130), Low: n(105), High: n(140), Close: n(110)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := MeetingLines(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/minval.go b/pkg/indicator/v2/minval.go index b56fbbe0c3..6c7be658e0 100644 --- a/pkg/indicator/v2/minval.go +++ b/pkg/indicator/v2/minval.go @@ -1,8 +1,8 @@ package indicatorv2 import ( - "github.com/c9s/bbgo/pkg/indicator/v2/bst" "github.com/c9s/bbgo/pkg/types" + "github.com/c9s/bbgo/pkg/types/bst" ) type MinValueStream struct { diff --git a/pkg/indicator/v2/pattern/morning_evening_star.go b/pkg/indicator/v2/morning_evening_star.go similarity index 92% rename from pkg/indicator/v2/pattern/morning_evening_star.go rename to pkg/indicator/v2/morning_evening_star.go index 97b239b23f..de58b2a689 100644 --- a/pkg/indicator/v2/pattern/morning_evening_star.go +++ b/pkg/indicator/v2/morning_evening_star.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +17,7 @@ type MorningOrEveningStarStream struct { // The evening star pattern is rare but it's considered by traders to be a reliable technical indicator. // The evening star is the opposite of the morning star. // The candlestick pattern is bearish whereas the morning star pattern is bullish. -func MorningOrEveningStar(source v2.KLineSubscription, direction Direction) *MorningOrEveningStarStream { +func MorningOrEveningStar(source KLineSubscription, direction Direction) *MorningOrEveningStarStream { s := &MorningOrEveningStarStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/morning_evening_star_test.go b/pkg/indicator/v2/morning_evening_star_test.go similarity index 89% rename from pkg/indicator/v2/pattern/morning_evening_star_test.go rename to pkg/indicator/v2/morning_evening_star_test.go index 2952950696..92e7b00360 100644 --- a/pkg/indicator/v2/pattern/morning_evening_star_test.go +++ b/pkg/indicator/v2/morning_evening_star_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestMorningOrEveningStar(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := MorningOrEveningStar(kLines, Bearish) for _, candle := range ts { @@ -33,7 +32,7 @@ func TestMorningOrEveningStar(t *testing.T) { {Open: n(20.70), Low: n(20.40), High: n(21.82), Close: n(21.58)}, } stream = &types.StandardStream{} - kLines = v2.KLines(stream, "", "") + kLines = KLines(stream, "", "") ind = MorningOrEveningStar(kLines, Bullish) for _, candle := range ts { diff --git a/pkg/indicator/v2/volume/negative_volume_index.go b/pkg/indicator/v2/negative_volume_index.go similarity index 90% rename from pkg/indicator/v2/volume/negative_volume_index.go rename to pkg/indicator/v2/negative_volume_index.go index 5a0cf3dc6a..62529679d8 100644 --- a/pkg/indicator/v2/volume/negative_volume_index.go +++ b/pkg/indicator/v2/negative_volume_index.go @@ -1,8 +1,8 @@ -package volume +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -21,7 +21,7 @@ type NVIStream struct { // NVI = Previous NVI // Otherwise: // NVI = Previous NVI + (((Closing - Previous Closing) / Previous Closing) * Previous NVI) -func NegativeVolumeIndex(source v2.KLineSubscription) *NVIStream { +func NegativeVolumeIndex(source KLineSubscription) *NVIStream { s := &NVIStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/volume/negative_volume_index_test.go b/pkg/indicator/v2/negative_volume_index_test.go similarity index 77% rename from pkg/indicator/v2/volume/negative_volume_index_test.go rename to pkg/indicator/v2/negative_volume_index_test.go index 94e5df2523..a044ae6d80 100644 --- a/pkg/indicator/v2/volume/negative_volume_index_test.go +++ b/pkg/indicator/v2/negative_volume_index_test.go @@ -1,12 +1,10 @@ -package volume +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -20,7 +18,7 @@ func TestNegativeVolumeIndex(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := NegativeVolumeIndex(kLines) for _, candle := range ts { @@ -34,7 +32,3 @@ func TestNegativeVolumeIndex(t *testing.T) { assert.InDelta(t, 1000.0, ind.Last(4), 0.01) } - -func n(n float64) fixedpoint.Value { - return fixedpoint.NewFromFloat(n) -} diff --git a/pkg/indicator/v2/volume/obv.go b/pkg/indicator/v2/obv.go similarity index 86% rename from pkg/indicator/v2/volume/obv.go rename to pkg/indicator/v2/obv.go index 166cce0032..9010e02852 100644 --- a/pkg/indicator/v2/volume/obv.go +++ b/pkg/indicator/v2/obv.go @@ -1,7 +1,6 @@ -package volume +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type OBVStream struct { // The [Obv](https://pkg.go.dev/github.com/cinar/indicator#Obv) function calculates a technical // trading momentum indicator that uses volume flow to predict changes in stock price. -func OBV(source v2.KLineSubscription) *OBVStream { +func OBV(source KLineSubscription) *OBVStream { s := &OBVStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/volume/obv_test.go b/pkg/indicator/v2/obv_test.go similarity index 92% rename from pkg/indicator/v2/volume/obv_test.go rename to pkg/indicator/v2/obv_test.go index 32387d7972..dd15fe1bef 100644 --- a/pkg/indicator/v2/volume/obv_test.go +++ b/pkg/indicator/v2/obv_test.go @@ -1,4 +1,4 @@ -package volume +package indicatorv2 import ( "encoding/json" @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -26,7 +26,7 @@ func TestOBV(t *testing.T) { expected := []float64{0, 8200, 16300, 24600, 33500, 24300, 37600, 27300, 17400, 27500, 16200, 3600, -7100, 4400, 28200, 13600} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := OBV(kLines) k := buildKLines(c, v) for _, candle := range k { diff --git a/pkg/indicator/v2/trend/parabolic_sar.go b/pkg/indicator/v2/parabolic_sar.go similarity index 91% rename from pkg/indicator/v2/trend/parabolic_sar.go rename to pkg/indicator/v2/parabolic_sar.go index 7174685a0b..a53f766f11 100644 --- a/pkg/indicator/v2/trend/parabolic_sar.go +++ b/pkg/indicator/v2/parabolic_sar.go @@ -1,9 +1,8 @@ -package trend +package indicatorv2 import ( "math" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -47,11 +46,11 @@ type PSARStream struct { af, ep float64 } -func ParabolicSar(source v2.KLineSubscription) *PSARStream { +func ParabolicSar(source KLineSubscription) *PSARStream { var ( - low = v2.LowPrices(source) - high = v2.HighPrices(source) - closing = v2.ClosePrices(source) + low = LowPrices(source) + high = HighPrices(source) + closing = ClosePrices(source) s = &PSARStream{ Float64Series: types.NewFloat64Series(), Trend: []Trend{}, diff --git a/pkg/indicator/v2/trend/parabolic_sar_test.go b/pkg/indicator/v2/parabolic_sar_test.go similarity index 88% rename from pkg/indicator/v2/trend/parabolic_sar_test.go rename to pkg/indicator/v2/parabolic_sar_test.go index 94383f363a..ac7f95d8e5 100644 --- a/pkg/indicator/v2/trend/parabolic_sar_test.go +++ b/pkg/indicator/v2/parabolic_sar_test.go @@ -1,12 +1,10 @@ -package trend +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -48,7 +46,7 @@ func TestParabolicSAR(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ParabolicSar(kLines) for _, candle := range ts { stream.EmitKLineClosed(candle) @@ -61,7 +59,3 @@ func TestParabolicSAR(t *testing.T) { assert.Equal(t, v, ind.Trend[i], "Expected PSAR.Trend[%d] to be %v, but got %v", i, v, ind.Trend[i]) } } - -func n(n float64) fixedpoint.Value { - return fixedpoint.NewFromFloat(n) -} diff --git a/pkg/indicator/v2/pattern/pattern.go b/pkg/indicator/v2/pattern.go similarity index 95% rename from pkg/indicator/v2/pattern/pattern.go rename to pkg/indicator/v2/pattern.go index 941c78a64e..0a91e34552 100644 --- a/pkg/indicator/v2/pattern/pattern.go +++ b/pkg/indicator/v2/pattern.go @@ -1,4 +1,4 @@ -package pattern +package indicatorv2 import "github.com/c9s/bbgo/pkg/fixedpoint" diff --git a/pkg/indicator/v2/pattern/piercing_line.go b/pkg/indicator/v2/piercing_line.go similarity index 87% rename from pkg/indicator/v2/pattern/piercing_line.go rename to pkg/indicator/v2/piercing_line.go index 44c3ffa8cf..af58e2c5d3 100644 --- a/pkg/indicator/v2/pattern/piercing_line.go +++ b/pkg/indicator/v2/piercing_line.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type PiercingLineStream struct { window int } -func PiercingLine(source v2.KLineSubscription) *PiercingLineStream { +func PiercingLine(source KLineSubscription) *PiercingLineStream { s := &PiercingLineStream{ Float64Series: types.NewFloat64Series(), window: 2, diff --git a/pkg/indicator/v2/pattern/piercing_line_test.go b/pkg/indicator/v2/piercing_line_test.go similarity index 85% rename from pkg/indicator/v2/pattern/piercing_line_test.go rename to pkg/indicator/v2/piercing_line_test.go index 51c25c0c18..46b3c5bdb8 100644 --- a/pkg/indicator/v2/pattern/piercing_line_test.go +++ b/pkg/indicator/v2/piercing_line_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestPiercingLine(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := PiercingLine(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/qstick.go b/pkg/indicator/v2/qstick.go similarity index 68% rename from pkg/indicator/v2/trend/qstick.go rename to pkg/indicator/v2/qstick.go index c533541060..96068852ca 100644 --- a/pkg/indicator/v2/trend/qstick.go +++ b/pkg/indicator/v2/qstick.go @@ -1,7 +1,6 @@ -package trend +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,11 +12,11 @@ type QstickStream struct { // The Qstick function calculates the ratio of recent up and down bars. // // QS = Sma(Closing - Opening) -func Qstick(source v2.KLineSubscription, window int) *QstickStream { +func Qstick(source KLineSubscription, window int) *QstickStream { var ( s = &QstickStream{ Float64Series: types.NewFloat64Series(), - sma: SMA(v2.CloseSubOpen(source), window), + sma: SMA(CloseSubOpen(source), window), } ) source.AddSubscriber(func(v types.KLine) { diff --git a/pkg/indicator/v2/trend/qstick_test.go b/pkg/indicator/v2/qstick_test.go similarity index 88% rename from pkg/indicator/v2/trend/qstick_test.go rename to pkg/indicator/v2/qstick_test.go index e06d3361aa..d066b9dcb5 100644 --- a/pkg/indicator/v2/trend/qstick_test.go +++ b/pkg/indicator/v2/qstick_test.go @@ -1,11 +1,10 @@ -package trend +package indicatorv2 import ( "testing" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -23,7 +22,7 @@ func TestQstick(t *testing.T) { expected := []float64{10, 2.5, 13.33, 11.25, 9.4, 5.2, 3.8, -5.2} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Qstick(kLines, 5) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/trend/rma.go b/pkg/indicator/v2/rma.go similarity index 98% rename from pkg/indicator/v2/trend/rma.go rename to pkg/indicator/v2/rma.go index ecd7a91565..cae09fac60 100644 --- a/pkg/indicator/v2/trend/rma.go +++ b/pkg/indicator/v2/rma.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/momentum/rsi.go b/pkg/indicator/v2/rsi.go similarity index 87% rename from pkg/indicator/v2/momentum/rsi.go rename to pkg/indicator/v2/rsi.go index 34f34135b3..f3654bd04e 100644 --- a/pkg/indicator/v2/momentum/rsi.go +++ b/pkg/indicator/v2/rsi.go @@ -1,7 +1,6 @@ -package momentum +package indicatorv2 import ( - indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -29,7 +28,7 @@ func RSI2(source types.Float64Source, window int) *RSIStream { func (s *RSIStream) Calculate(_ float64) float64 { var gainSum, lossSum float64 var sourceLen = s.source.Length() - var limit = indicatorv2.Min(s.window, sourceLen) + var limit = Min(s.window, sourceLen) for i := 0; i < limit; i++ { value := s.source.Last(i) prev := s.source.Last(i + 1) diff --git a/pkg/indicator/v2/momentum/rsi_test.go b/pkg/indicator/v2/rsi_test.go similarity index 95% rename from pkg/indicator/v2/momentum/rsi_test.go rename to pkg/indicator/v2/rsi_test.go index 3789acc97a..779132d34c 100644 --- a/pkg/indicator/v2/momentum/rsi_test.go +++ b/pkg/indicator/v2/rsi_test.go @@ -1,4 +1,4 @@ -package momentum +package indicatorv2 import ( "encoding/json" @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" ) func Test_RSI2(t *testing.T) { @@ -68,7 +67,7 @@ func Test_RSI2(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // RSI2() - prices := v2.ClosePrices(nil) + prices := ClosePrices(nil) rsi := RSI2(prices, tt.window) t.Logf("data length: %d", len(tt.values)) diff --git a/pkg/indicator/v2/pattern/separating_lines.go b/pkg/indicator/v2/separating_lines.go similarity index 88% rename from pkg/indicator/v2/pattern/separating_lines.go rename to pkg/indicator/v2/separating_lines.go index 31009d993b..88ae8ddd15 100644 --- a/pkg/indicator/v2/pattern/separating_lines.go +++ b/pkg/indicator/v2/separating_lines.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type SeparatingLinesStream struct { window int } -func SeparatingLines(source v2.KLineSubscription, maxDiff float64) *SeparatingLinesStream { +func SeparatingLines(source KLineSubscription, maxDiff float64) *SeparatingLinesStream { s := &SeparatingLinesStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/separating_lines_test.go b/pkg/indicator/v2/separating_lines_test.go similarity index 91% rename from pkg/indicator/v2/pattern/separating_lines_test.go rename to pkg/indicator/v2/separating_lines_test.go index 190885c54c..82afa8b0ec 100644 --- a/pkg/indicator/v2/pattern/separating_lines_test.go +++ b/pkg/indicator/v2/separating_lines_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestSeparatingLines(t *testing.T) { {Open: n(152), Low: n(120), High: n(152), Close: n(130)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := SeparatingLines(kLines, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines.go b/pkg/indicator/v2/side_by_side_whitelines.go similarity index 90% rename from pkg/indicator/v2/pattern/side_by_side_whitelines.go rename to pkg/indicator/v2/side_by_side_whitelines.go index 8a20c14dcf..a91faf3876 100644 --- a/pkg/indicator/v2/pattern/side_by_side_whitelines.go +++ b/pkg/indicator/v2/side_by_side_whitelines.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +12,7 @@ type SideBySideWhiteLinesStream struct { window int } -func SideBySideWhiteLines(source v2.KLineSubscription, maxDiff float64) *SideBySideWhiteLinesStream { +func SideBySideWhiteLines(source KLineSubscription, maxDiff float64) *SideBySideWhiteLinesStream { s := &SideBySideWhiteLinesStream{ Float64Series: types.NewFloat64Series(), window: 4, diff --git a/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go b/pkg/indicator/v2/side_by_side_whitelines_test.go similarity index 92% rename from pkg/indicator/v2/pattern/side_by_side_whitelines_test.go rename to pkg/indicator/v2/side_by_side_whitelines_test.go index 504629cfb4..0fcc872fa2 100644 --- a/pkg/indicator/v2/pattern/side_by_side_whitelines_test.go +++ b/pkg/indicator/v2/side_by_side_whitelines_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestSideBySideWhiteLines(t *testing.T) { {Open: n(50), Low: n(42), High: n(77), Close: n(68)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := SideBySideWhiteLines(kLines, 0.01) for _, candle := range ts { diff --git a/pkg/indicator/v2/trend/sma.go b/pkg/indicator/v2/sma.go similarity index 96% rename from pkg/indicator/v2/trend/sma.go rename to pkg/indicator/v2/sma.go index 297d7d3e61..f844a895e5 100644 --- a/pkg/indicator/v2/trend/sma.go +++ b/pkg/indicator/v2/sma.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/trend/sma_test.go b/pkg/indicator/v2/sma_test.go similarity index 94% rename from pkg/indicator/v2/trend/sma_test.go rename to pkg/indicator/v2/sma_test.go index 59c836a6bd..384964ba39 100644 --- a/pkg/indicator/v2/trend/sma_test.go +++ b/pkg/indicator/v2/sma_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" diff --git a/pkg/indicator/v2/pattern/spinning_top.go b/pkg/indicator/v2/spinning_top.go similarity index 91% rename from pkg/indicator/v2/pattern/spinning_top.go rename to pkg/indicator/v2/spinning_top.go index 70408deeef..6399879771 100644 --- a/pkg/indicator/v2/pattern/spinning_top.go +++ b/pkg/indicator/v2/spinning_top.go @@ -1,8 +1,8 @@ -package pattern +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +15,7 @@ type SpinningTopStream struct { // The real body should be small, showing little difference between the open and close prices. // Since buyers and sellers both pushed the price, but couldn't maintain it, the pattern shows // indecision. More sideways movement could follow. -func SpinningTop(source v2.KLineSubscription, direction Direction) *SpinningTopStream { +func SpinningTop(source KLineSubscription, direction Direction) *SpinningTopStream { s := &SpinningTopStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/pattern/spinning_top_test.go b/pkg/indicator/v2/spinning_top_test.go similarity index 89% rename from pkg/indicator/v2/pattern/spinning_top_test.go rename to pkg/indicator/v2/spinning_top_test.go index 24b2c21c4f..6abb1bee3d 100644 --- a/pkg/indicator/v2/pattern/spinning_top_test.go +++ b/pkg/indicator/v2/spinning_top_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -12,7 +11,7 @@ func TestSpinningTop(t *testing.T) { {Open: n(20.50), Low: n(20.23), High: n(20.87), Close: n(20.62)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := SpinningTop(kLines, Bearish) for _, candle := range ts { diff --git a/pkg/indicator/v2/momentum/stoch.go b/pkg/indicator/v2/stoch.go similarity index 87% rename from pkg/indicator/v2/momentum/stoch.go rename to pkg/indicator/v2/stoch.go index 3a95241213..ab4d4d122b 100644 --- a/pkg/indicator/v2/momentum/stoch.go +++ b/pkg/indicator/v2/stoch.go @@ -1,8 +1,8 @@ -package momentum +package indicatorv2 import ( "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -27,15 +27,15 @@ type StochStream struct { window int dPeriod int - highPrices, lowPrices *v2.PriceStream + highPrices, lowPrices *PriceStream updateCallbacks []func(k, d float64) } // Stochastic Oscillator -func Stoch(source v2.KLineSubscription, window, dPeriod int) *StochStream { - highPrices := v2.HighPrices(source) - lowPrices := v2.LowPrices(source) +func Stoch(source KLineSubscription, window, dPeriod int) *StochStream { + highPrices := HighPrices(source) + lowPrices := LowPrices(source) s := &StochStream{ window: window, diff --git a/pkg/indicator/v2/momentum/stoch_test.go b/pkg/indicator/v2/stoch_test.go similarity index 99% rename from pkg/indicator/v2/momentum/stoch_test.go rename to pkg/indicator/v2/stoch_test.go index 3d632d96bc..06792d78f5 100644 --- a/pkg/indicator/v2/momentum/stoch_test.go +++ b/pkg/indicator/v2/stoch_test.go @@ -1,4 +1,4 @@ -package momentum +package indicatorv2 import ( "encoding/json" @@ -7,7 +7,7 @@ import ( "time" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -58,7 +58,7 @@ func TestSTOCH2_update(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") kd := Stoch(kLines, tt.window, DPeriod) for _, k := range tt.kLines { diff --git a/pkg/indicator/v2/momentum/stochstream_callbacks.go b/pkg/indicator/v2/stochstream_callbacks.go similarity index 93% rename from pkg/indicator/v2/momentum/stochstream_callbacks.go rename to pkg/indicator/v2/stochstream_callbacks.go index 00e8f34920..b4bc8bb80c 100644 --- a/pkg/indicator/v2/momentum/stochstream_callbacks.go +++ b/pkg/indicator/v2/stochstream_callbacks.go @@ -1,6 +1,6 @@ // Code generated by "callbackgen -type StochStream"; DO NOT EDIT. -package momentum +package indicatorv2 import () diff --git a/pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv b/pkg/indicator/v2/testdata/BTCUSDT-1m-2022-05-06.csv similarity index 100% rename from pkg/indicator/v2/volume/testdata/BTCUSDT-1m-2022-05-06.csv rename to pkg/indicator/v2/testdata/BTCUSDT-1m-2022-05-06.csv diff --git a/pkg/indicator/v2/pattern/three_crows.go b/pkg/indicator/v2/three_crows.go similarity index 92% rename from pkg/indicator/v2/pattern/three_crows.go rename to pkg/indicator/v2/three_crows.go index 0c41d378af..b519adf7bd 100644 --- a/pkg/indicator/v2/pattern/three_crows.go +++ b/pkg/indicator/v2/three_crows.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -17,7 +16,7 @@ type ThreeCrowsStream struct { // a trendline or the nearest support area which may be formed by the first candle’s line. // If the pattern is not confirmed it may act only as a temporary pause within an uptrend. // Although the pattern name suggest that two lines form it, in fact, it contains three lines -func ThreeCrows(source v2.KLineSubscription) *ThreeCrowsStream { +func ThreeCrows(source KLineSubscription) *ThreeCrowsStream { s := &ThreeCrowsStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/three_crows_test.go b/pkg/indicator/v2/three_crows_test.go similarity index 86% rename from pkg/indicator/v2/pattern/three_crows_test.go rename to pkg/indicator/v2/three_crows_test.go index 335410ec36..a28ba82aeb 100644 --- a/pkg/indicator/v2/pattern/three_crows_test.go +++ b/pkg/indicator/v2/three_crows_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -14,7 +13,7 @@ func TestThreeCrows(t *testing.T) { {Open: n(21.25), Low: n(20.60), High: n(21.35), Close: n(20.70)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ThreeCrows(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/three_line_strike.go b/pkg/indicator/v2/three_line_strike.go similarity index 90% rename from pkg/indicator/v2/pattern/three_line_strike.go rename to pkg/indicator/v2/three_line_strike.go index 46ca551ecc..138f7e15ae 100644 --- a/pkg/indicator/v2/pattern/three_line_strike.go +++ b/pkg/indicator/v2/three_line_strike.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type ThreeLineStrikeStream struct { window int } -func ThreeLineStrike(source v2.KLineSubscription) *ThreeLineStrikeStream { +func ThreeLineStrike(source KLineSubscription) *ThreeLineStrikeStream { s := &ThreeLineStrikeStream{ Float64Series: types.NewFloat64Series(), window: 4, diff --git a/pkg/indicator/v2/pattern/three_line_strike_test.go b/pkg/indicator/v2/three_line_strike_test.go similarity index 92% rename from pkg/indicator/v2/pattern/three_line_strike_test.go rename to pkg/indicator/v2/three_line_strike_test.go index 9402714b87..f4ba487ba4 100644 --- a/pkg/indicator/v2/pattern/three_line_strike_test.go +++ b/pkg/indicator/v2/three_line_strike_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestThreeLineStrike(t *testing.T) { {Open: n(62), Low: n(59), High: n(103), Close: n(101)}, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ThreeLineStrike(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/pattern/three_white_soldiers.go b/pkg/indicator/v2/three_white_soldiers.go similarity index 87% rename from pkg/indicator/v2/pattern/three_white_soldiers.go rename to pkg/indicator/v2/three_white_soldiers.go index 78c31677be..197aa2f156 100644 --- a/pkg/indicator/v2/pattern/three_white_soldiers.go +++ b/pkg/indicator/v2/three_white_soldiers.go @@ -1,7 +1,6 @@ -package pattern +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -11,7 +10,7 @@ type ThreeWhiteSoldiersStream struct { window int } -func ThreeWhiteSoldiers(source v2.KLineSubscription) *ThreeWhiteSoldiersStream { +func ThreeWhiteSoldiers(source KLineSubscription) *ThreeWhiteSoldiersStream { s := &ThreeWhiteSoldiersStream{ Float64Series: types.NewFloat64Series(), window: 3, diff --git a/pkg/indicator/v2/pattern/three_white_soldiers_test.go b/pkg/indicator/v2/three_white_soldiers_test.go similarity index 86% rename from pkg/indicator/v2/pattern/three_white_soldiers_test.go rename to pkg/indicator/v2/three_white_soldiers_test.go index c31a2b845c..b40a4dbae8 100644 --- a/pkg/indicator/v2/pattern/three_white_soldiers_test.go +++ b/pkg/indicator/v2/three_white_soldiers_test.go @@ -1,9 +1,8 @@ -package pattern +package indicatorv2 import ( "testing" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +14,7 @@ func TestThreeWhiteSoldiers(t *testing.T) { } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := ThreeWhiteSoldiers(kLines) for _, candle := range ts { diff --git a/pkg/indicator/v2/volatility/tr.go b/pkg/indicator/v2/tr.go similarity index 87% rename from pkg/indicator/v2/volatility/tr.go rename to pkg/indicator/v2/tr.go index 1ec8b2638d..66d7cec5df 100644 --- a/pkg/indicator/v2/volatility/tr.go +++ b/pkg/indicator/v2/tr.go @@ -1,9 +1,8 @@ -package volatility +package indicatorv2 import ( "math" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -16,7 +15,7 @@ type TRStream struct { previousClose float64 } -func TR2(source v2.KLineSubscription) *TRStream { +func TR2(source KLineSubscription) *TRStream { s := &TRStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/volatility/tr_test.go b/pkg/indicator/v2/tr_test.go similarity index 93% rename from pkg/indicator/v2/volatility/tr_test.go rename to pkg/indicator/v2/tr_test.go index adc3eb911f..82afd8269e 100644 --- a/pkg/indicator/v2/volatility/tr_test.go +++ b/pkg/indicator/v2/tr_test.go @@ -1,4 +1,4 @@ -package volatility +package indicatorv2 import ( "encoding/json" @@ -6,8 +6,6 @@ import ( "testing" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -66,9 +64,9 @@ func Test_TR_and_RMA(t *testing.T) { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") atr := TR2(kLines) - rma := trend.RMA2(atr, tt.window, true) + rma := RMA2(atr, tt.window, true) for _, k := range tt.kLines { stream.EmitKLineClosed(k) diff --git a/pkg/indicator/v2/trend/trend_line.go b/pkg/indicator/v2/trend_line.go similarity index 87% rename from pkg/indicator/v2/trend/trend_line.go rename to pkg/indicator/v2/trend_line.go index 0403d56bc1..88c040f0da 100644 --- a/pkg/indicator/v2/trend/trend_line.go +++ b/pkg/indicator/v2/trend_line.go @@ -1,9 +1,8 @@ -package trend +package indicatorv2 import ( "math" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -13,9 +12,9 @@ type TrendLineStream struct { // NewTrendlineIndicator returns an indicator whose output is the slope of the trend // line given by the values in the window. -func TrendLine(source v2.KLineSubscription, window int) *TrendLineStream { +func TrendLine(source KLineSubscription, window int) *TrendLineStream { var ( - closing = v2.ClosePrices(source) + closing = ClosePrices(source) s = &TrendLineStream{ Float64Series: types.NewFloat64Series(), } diff --git a/pkg/indicator/v2/trend/trend_line_test.go b/pkg/indicator/v2/trend_line_test.go similarity index 95% rename from pkg/indicator/v2/trend/trend_line_test.go rename to pkg/indicator/v2/trend_line_test.go index d5f8f75ec7..67b9632f61 100644 --- a/pkg/indicator/v2/trend/trend_line_test.go +++ b/pkg/indicator/v2/trend_line_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -32,7 +31,7 @@ func TestTrendIndicator(t *testing.T) { for _, tt := range tests { stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := TrendLine(kLines, 3) buildKLines := func(closing []float64) (kLines []types.KLine) { for i := range closing { diff --git a/pkg/indicator/v2/trend/trima.go b/pkg/indicator/v2/trima.go similarity index 97% rename from pkg/indicator/v2/trend/trima.go rename to pkg/indicator/v2/trima.go index e7fe72e812..f0c5cb433e 100644 --- a/pkg/indicator/v2/trend/trima.go +++ b/pkg/indicator/v2/trima.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import "github.com/c9s/bbgo/pkg/types" diff --git a/pkg/indicator/v2/volatility/ulcer_index.go b/pkg/indicator/v2/ulcer_index.go similarity index 84% rename from pkg/indicator/v2/volatility/ulcer_index.go rename to pkg/indicator/v2/ulcer_index.go index 7c0bd19183..2475d53ef5 100644 --- a/pkg/indicator/v2/volatility/ulcer_index.go +++ b/pkg/indicator/v2/ulcer_index.go @@ -1,16 +1,14 @@ -package volatility +package indicatorv2 import ( "math" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) type UlcerIndexStream struct { *types.Float64Series - sma *trend.SMAStream + sma *SMAStream } // The Ulcer Index (UI) measures downside risk. The index increases in value @@ -26,7 +24,7 @@ type UlcerIndexStream struct { func UlcerIndex(source types.Float64Source, window int) *UlcerIndexStream { s := &UlcerIndexStream{ Float64Series: types.NewFloat64Series(), - sma: trend.SMA(v2.SquaredAverage(source, window), window), + sma: SMA(SquaredAverage(source, window), window), } s.Bind(source, s) diff --git a/pkg/indicator/v2/volatility/ulcer_index_test.go b/pkg/indicator/v2/ulcer_index_test.go similarity index 96% rename from pkg/indicator/v2/volatility/ulcer_index_test.go rename to pkg/indicator/v2/ulcer_index_test.go index af616b7e41..fcaff116b5 100644 --- a/pkg/indicator/v2/volatility/ulcer_index_test.go +++ b/pkg/indicator/v2/ulcer_index_test.go @@ -1,4 +1,4 @@ -package volatility +package indicatorv2 import ( "testing" diff --git a/pkg/indicator/v2/volatility/atr.go b/pkg/indicator/v2/volatility/atr.go deleted file mode 100644 index 564bc752dd..0000000000 --- a/pkg/indicator/v2/volatility/atr.go +++ /dev/null @@ -1,17 +0,0 @@ -package volatility - -import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" -) - -type ATRStream struct { - // embedded struct - *trend.RMAStream -} - -func ATR2(source v2.KLineSubscription, window int) *ATRStream { - tr := TR2(source) - rma := trend.RMA2(tr, window, true) - return &ATRStream{RMAStream: rma} -} diff --git a/pkg/indicator/v2/volume/volume_profile.go b/pkg/indicator/v2/volume_profile.go similarity index 95% rename from pkg/indicator/v2/volume/volume_profile.go rename to pkg/indicator/v2/volume_profile.go index e4ac56226b..ad8622d935 100644 --- a/pkg/indicator/v2/volume/volume_profile.go +++ b/pkg/indicator/v2/volume_profile.go @@ -1,4 +1,4 @@ -package volume +package indicatorv2 import ( "math" @@ -8,7 +8,7 @@ import ( "gonum.org/v1/gonum/stat" bbgofloats "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -66,9 +66,9 @@ type VolumeLevel struct { Volume float64 } -func NewVolumeProfile(source v2.KLineSubscription, window int) *VolumeProfileStream { - prices := v2.HLC3(source) - volumes := v2.Volumes(source) +func NewVolumeProfile(source KLineSubscription, window int) *VolumeProfileStream { + prices := HLC3(source) + volumes := Volumes(source) s := &VolumeProfileStream{ Float64Series: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/volume/volume_profile_test.go b/pkg/indicator/v2/volume_profile_test.go similarity index 85% rename from pkg/indicator/v2/volume/volume_profile_test.go rename to pkg/indicator/v2/volume_profile_test.go index 16a0f67236..4feb90845a 100644 --- a/pkg/indicator/v2/volume/volume_profile_test.go +++ b/pkg/indicator/v2/volume_profile_test.go @@ -1,4 +1,4 @@ -package volume +package indicatorv2 import ( "encoding/csv" @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/datasource/csvsource" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -21,11 +21,11 @@ func TestVolumeProfile(t *testing.T) { assert.NoError(t, file.Close()) }() - candles, err := csvsource.NewCSVKlineReader(csv.NewReader(file)).ReadAll(time.Minute) + candles, err := csvsource.NewCSVKLineReader(csv.NewReader(file)).ReadAll(time.Minute) assert.NoError(t, err) stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := NewVolumeProfile(kLines, 10) for _, candle := range candles { diff --git a/pkg/indicator/v2/trend/vortex.go b/pkg/indicator/v2/vortex.go similarity index 91% rename from pkg/indicator/v2/trend/vortex.go rename to pkg/indicator/v2/vortex.go index 6e96368959..41a514502d 100644 --- a/pkg/indicator/v2/trend/vortex.go +++ b/pkg/indicator/v2/vortex.go @@ -1,10 +1,10 @@ -package trend +package indicatorv2 import ( "math" "github.com/c9s/bbgo/pkg/datatype/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -34,11 +34,11 @@ type VortexStream struct { window int } -func Vortex(source v2.KLineSubscription) *VortexStream { +func Vortex(source KLineSubscription) *VortexStream { var ( - low = v2.LowPrices(source) - high = v2.HighPrices(source) - closing = v2.ClosePrices(source) + low = LowPrices(source) + high = HighPrices(source) + closing = ClosePrices(source) window = 14 s = &VortexStream{ PlusVi: types.NewFloat64Series(), diff --git a/pkg/indicator/v2/trend/vortex_test.go b/pkg/indicator/v2/vortex_test.go similarity index 92% rename from pkg/indicator/v2/trend/vortex_test.go rename to pkg/indicator/v2/vortex_test.go index df28518d31..a27668d903 100644 --- a/pkg/indicator/v2/trend/vortex_test.go +++ b/pkg/indicator/v2/vortex_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -18,7 +17,7 @@ func TestVortex(t *testing.T) { expectedMinusVi := []float64{0.00000, 0.74685, 0.89492, 0.93361, 0.83404} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Vortex(kLines) var ts []types.KLine for i := range closing { diff --git a/pkg/indicator/v2/volume/vwap.go b/pkg/indicator/v2/vwap.go similarity index 75% rename from pkg/indicator/v2/volume/vwap.go rename to pkg/indicator/v2/vwap.go index 5d7a254242..d48a4142f7 100644 --- a/pkg/indicator/v2/volume/vwap.go +++ b/pkg/indicator/v2/vwap.go @@ -1,9 +1,8 @@ -package volume +package indicatorv2 import ( "gonum.org/v1/gonum/floats" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -16,10 +15,10 @@ type VWAPStream struct { // the asset has traded weighted by volume. // // VWAP = Sum(Closing * Volume) / Sum(Volume) -func VWAP(source v2.KLineSubscription, window int) *VWAPStream { +func VWAP(source KLineSubscription, window int) *VWAPStream { var ( - pv = v2.CloseMulVolume(source) - volume = v2.Volumes(source) + pv = CloseMulVolume(source) + volume = Volumes(source) s = &VWAPStream{ Float64Series: types.NewFloat64Series(), window: window, @@ -33,7 +32,7 @@ func VWAP(source v2.KLineSubscription, window int) *VWAPStream { return s } -func VwapDefault(source v2.KLineSubscription) *VWAPStream { +func VwapDefault(source KLineSubscription) *VWAPStream { return VWAP(source, 14) } diff --git a/pkg/indicator/v2/volume/vwap_test.go b/pkg/indicator/v2/vwap_test.go similarity index 88% rename from pkg/indicator/v2/volume/vwap_test.go rename to pkg/indicator/v2/vwap_test.go index bfc51516aa..663c93160c 100644 --- a/pkg/indicator/v2/volume/vwap_test.go +++ b/pkg/indicator/v2/vwap_test.go @@ -1,4 +1,4 @@ -package volume +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -21,7 +20,7 @@ func TestVolumeWeightedAveragePrice(t *testing.T) { expected := []float64{9, 10.05, 9.32, 8.8, 9.14} stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := VWAP(kLines, 2) for _, candle := range ts { stream.EmitKLineClosed(candle) diff --git a/pkg/indicator/v2/trend/vwma.go b/pkg/indicator/v2/vwma.go similarity index 73% rename from pkg/indicator/v2/trend/vwma.go rename to pkg/indicator/v2/vwma.go index 11a8ff50b7..c5d6d18653 100644 --- a/pkg/indicator/v2/trend/vwma.go +++ b/pkg/indicator/v2/vwma.go @@ -1,7 +1,6 @@ -package trend +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -17,11 +16,11 @@ type VwmaStream struct { // with higher volume will have a greater weight. // // VWMA = Sum(Price * Volume) / Sum(Volume) for a given Period. -func Vwma(source v2.KLineSubscription, window int) *VwmaStream { +func Vwma(source KLineSubscription, window int) *VwmaStream { s := &VwmaStream{ Float64Series: types.NewFloat64Series(), - sma1: SMA(v2.CloseMulVolume(source), window), - sma2: SMA(v2.Volumes(source), window), + sma1: SMA(CloseMulVolume(source), window), + sma2: SMA(Volumes(source), window), window: window, } source.AddSubscriber(func(v types.KLine) { @@ -32,7 +31,7 @@ func Vwma(source v2.KLineSubscription, window int) *VwmaStream { } // The DefaultVwma function calculates VWMA with a period of 20. -func VwmaDefault(source v2.KLineSubscription) *VwmaStream { +func VwmaDefault(source KLineSubscription) *VwmaStream { return Vwma(source, 20) } diff --git a/pkg/indicator/v2/trend/vwma_test.go b/pkg/indicator/v2/vwma_test.go similarity index 92% rename from pkg/indicator/v2/trend/vwma_test.go rename to pkg/indicator/v2/vwma_test.go index 5168ef3d8d..588a54847d 100644 --- a/pkg/indicator/v2/trend/vwma_test.go +++ b/pkg/indicator/v2/vwma_test.go @@ -1,4 +1,4 @@ -package trend +package indicatorv2 import ( "testing" @@ -6,7 +6,6 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -37,7 +36,7 @@ func TestVwma(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := Vwma(kLines, tt.window) var ts []types.KLine for i := range tt.closing { diff --git a/pkg/indicator/v2/momentum/williams_r.go b/pkg/indicator/v2/williams_r.go similarity index 84% rename from pkg/indicator/v2/momentum/williams_r.go rename to pkg/indicator/v2/williams_r.go index 510f62d092..f25c6c3aba 100644 --- a/pkg/indicator/v2/momentum/williams_r.go +++ b/pkg/indicator/v2/williams_r.go @@ -1,7 +1,6 @@ -package momentum +package indicatorv2 import ( - v2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -28,15 +27,15 @@ import ( type WilliamsRStream struct { // embedded structs *types.Float64Series - min *v2.MinValueStream - max *v2.MaxValueStream + min *MinValueStream + max *MaxValueStream } -func WilliamsR(source v2.KLineSubscription, window int) *WilliamsRStream { +func WilliamsR(source KLineSubscription, window int) *WilliamsRStream { s := &WilliamsRStream{ Float64Series: types.NewFloat64Series(), - min: v2.MinValue(v2.LowPrices(source), window), - max: v2.MaxValue(v2.HighPrices(source), window), + min: MinValue(LowPrices(source), window), + max: MaxValue(HighPrices(source), window), } source.AddSubscriber(func(v types.KLine) { diff --git a/pkg/indicator/v2/momentum/williams_r_test.go b/pkg/indicator/v2/williams_r_test.go similarity index 95% rename from pkg/indicator/v2/momentum/williams_r_test.go rename to pkg/indicator/v2/williams_r_test.go index f8477740ee..4ca92af82b 100644 --- a/pkg/indicator/v2/momentum/williams_r_test.go +++ b/pkg/indicator/v2/williams_r_test.go @@ -1,4 +1,4 @@ -package momentum +package indicatorv2 import ( "encoding/json" @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - v2 "github.com/c9s/bbgo/pkg/indicator/v2" + "github.com/c9s/bbgo/pkg/types" ) @@ -47,7 +47,7 @@ func Test_WilliamsR(t *testing.T) { -43.26858026481079, } stream := &types.StandardStream{} - kLines := v2.KLines(stream, "", "") + kLines := KLines(stream, "", "") ind := WilliamsR(kLines, 14) k := buildKLines(h, l, c) for _, candle := range k { diff --git a/pkg/report/profit_report.go b/pkg/report/profit_report.go index 701d3e3c9e..bb20866047 100644 --- a/pkg/report/profit_report.go +++ b/pkg/report/profit_report.go @@ -7,7 +7,7 @@ import ( "github.com/c9s/bbgo/pkg/data/tsv" "github.com/c9s/bbgo/pkg/datatype/floats" "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -34,7 +34,7 @@ type AccumulatedProfitReport struct { accumulatedProfitPerInterval *types.Float64Series // Accumulated profit MA - profitMA *trend.SMAStream + profitMA *indicatorv2.SMAStream profitMAPerInterval floats.Slice // Profit of each interval @@ -76,7 +76,7 @@ func (r *AccumulatedProfitReport) Initialize(symbol string, interval types.Inter } r.accumulatedProfitPerInterval = types.NewFloat64Series() - r.profitMA = trend.SMA(r.accumulatedProfitPerInterval, r.ProfitMAWindow) + r.profitMA = indicatorv2.SMA(r.accumulatedProfitPerInterval, r.ProfitMAWindow) } func (r *AccumulatedProfitReport) AddStrategyParameter(title string, value string) { diff --git a/pkg/risk/riskcontrol/circuit_break.go b/pkg/risk/riskcontrol/circuit_break.go index a73eb4d103..e8e8ad3b09 100644 --- a/pkg/risk/riskcontrol/circuit_break.go +++ b/pkg/risk/riskcontrol/circuit_break.go @@ -6,14 +6,14 @@ import ( log "github.com/sirupsen/logrus" "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) type CircuitBreakRiskControl struct { // Since price could be fluctuated large, // use an EWMA to smooth it in running time - price *trend.EWMAStream + price *indicatorv2.EWMAStream position *types.Position profitStats *types.ProfitStats lossThreshold fixedpoint.Value @@ -24,7 +24,7 @@ type CircuitBreakRiskControl struct { func NewCircuitBreakRiskControl( position *types.Position, - price *trend.EWMAStream, + price *indicatorv2.EWMAStream, lossThreshold fixedpoint.Value, profitStats *types.ProfitStats, haltedDuration time.Duration, diff --git a/pkg/risk/riskcontrol/circuit_break_test.go b/pkg/risk/riskcontrol/circuit_break_test.go index 33c9eb1184..54f523d4b1 100644 --- a/pkg/risk/riskcontrol/circuit_break_test.go +++ b/pkg/risk/riskcontrol/circuit_break_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -19,7 +19,7 @@ func Test_IsHalted(t *testing.T) { ) window := types.IntervalWindow{Window: 30, Interval: types.Interval1m} - priceEWMA := trend.EWMA2(nil, window.Window) + priceEWMA := indicatorv2.EWMA2(nil, window.Window) priceEWMA.PushAndEmit(price) cases := []struct { diff --git a/pkg/strategy/bollmaker/dynamic_spread.go b/pkg/strategy/bollmaker/dynamic_spread.go index 6ae08607c6..0f9ceb0f3d 100644 --- a/pkg/strategy/bollmaker/dynamic_spread.go +++ b/pkg/strategy/bollmaker/dynamic_spread.go @@ -7,7 +7,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/indicator" - "github.com/c9s/bbgo/pkg/indicator/v2/volatility" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -29,7 +29,7 @@ type DynamicSpreadSettings struct { } // Initialize dynamic spreads and preload SMAs -func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *volatility.BollingerStream) { +func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *indicatorv2.BollingerStream) { switch { case ds.AmpSpreadSettings != nil: ds.AmpSpreadSettings.initialize(symbol, session) @@ -165,10 +165,10 @@ type DynamicSpreadBollWidthRatioSettings struct { // A positive number. The greater factor, the sharper weighting function. Default set to 1.0 . Sensitivity float64 `json:"sensitivity"` - defaultBoll, neutralBoll *volatility.BollingerStream + defaultBoll, neutralBoll *indicatorv2.BollingerStream } -func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *volatility.BollingerStream) { +func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *indicatorv2.BollingerStream) { ds.neutralBoll = neutralBoll ds.defaultBoll = defaultBoll if ds.Sensitivity <= 0. { diff --git a/pkg/strategy/bollmaker/strategy.go b/pkg/strategy/bollmaker/strategy.go index 23c9d48d47..6ffc3c6b85 100644 --- a/pkg/strategy/bollmaker/strategy.go +++ b/pkg/strategy/bollmaker/strategy.go @@ -11,7 +11,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/volatility" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/util" ) @@ -157,10 +157,10 @@ type Strategy struct { groupID uint32 // defaultBoll is the BOLLINGER indicator we used for predicting the price. - defaultBoll *volatility.BollingerStream + defaultBoll *indicatorv2.BollingerStream // neutralBoll is the neutral price section - neutralBoll *volatility.BollingerStream + neutralBoll *indicatorv2.BollingerStream // StrategyController bbgo.StrategyController diff --git a/pkg/strategy/bollmaker/trend.go b/pkg/strategy/bollmaker/trend.go index 3ea9dd89a1..150fedd9b2 100644 --- a/pkg/strategy/bollmaker/trend.go +++ b/pkg/strategy/bollmaker/trend.go @@ -1,6 +1,6 @@ package bollmaker -import "github.com/c9s/bbgo/pkg/indicator/v2/volatility" +import indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" type PriceTrend string @@ -11,7 +11,7 @@ const ( UnknownTrend PriceTrend = "unknown" ) -func detectPriceTrend(inc *volatility.BollingerStream, price float64) PriceTrend { +func detectPriceTrend(inc *indicatorv2.BollingerStream, price float64) PriceTrend { if inBetween(price, inc.DownBand.Last(0), inc.UpBand.Last(0)) { return NeutralTrend } diff --git a/pkg/strategy/scmaker/intensity.go b/pkg/strategy/scmaker/intensity.go index 57393f7c5c..0472241230 100644 --- a/pkg/strategy/scmaker/intensity.go +++ b/pkg/strategy/scmaker/intensity.go @@ -3,14 +3,13 @@ package scmaker import ( "github.com/c9s/bbgo/pkg/fixedpoint" indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) type IntensityStream struct { *types.Float64Series - Buy, Sell *trend.RMAStream + Buy, Sell *indicatorv2.RMAStream window int } @@ -19,8 +18,8 @@ func Intensity(source indicatorv2.KLineSubscription, window int) *IntensityStrea Float64Series: types.NewFloat64Series(), window: window, - Buy: trend.RMA2(types.NewFloat64Series(), window, false), - Sell: trend.RMA2(types.NewFloat64Series(), window, false), + Buy: indicatorv2.RMA2(types.NewFloat64Series(), window, false), + Sell: indicatorv2.RMA2(types.NewFloat64Series(), window, false), } threshold := fixedpoint.NewFromFloat(100.0) diff --git a/pkg/strategy/scmaker/strategy.go b/pkg/strategy/scmaker/strategy.go index 153012bcf5..4165fe549f 100644 --- a/pkg/strategy/scmaker/strategy.go +++ b/pkg/strategy/scmaker/strategy.go @@ -11,9 +11,7 @@ import ( "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/fixedpoint" - . "github.com/c9s/bbgo/pkg/indicator/v2" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" - "github.com/c9s/bbgo/pkg/indicator/v2/volatility" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/risk/riskcontrol" "github.com/c9s/bbgo/pkg/strategy/common" "github.com/c9s/bbgo/pkg/types" @@ -76,8 +74,8 @@ type Strategy struct { liquidityScale bbgo.Scale // indicators - ewma *trend.EWMAStream - boll *volatility.BollingerStream + ewma *indicatorv2.EWMAStream + boll *indicatorv2.BollingerStream intensity *IntensityStream positionRiskControl *riskcontrol.PositionRiskControl @@ -176,7 +174,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se return nil } -func (s *Strategy) preloadKLines(inc *KLineStream, session *bbgo.ExchangeSession, symbol string, interval types.Interval) { +func (s *Strategy) preloadKLines(inc *indicatorv2.KLineStream, session *bbgo.ExchangeSession, symbol string, interval types.Interval) { if store, ok := session.MarketDataStore(symbol); ok { if kLinesData, ok := store.KLinesOfInterval(interval); ok { for _, k := range *kLinesData { @@ -187,23 +185,23 @@ func (s *Strategy) preloadKLines(inc *KLineStream, session *bbgo.ExchangeSession } func (s *Strategy) initializeMidPriceEMA(session *bbgo.ExchangeSession) { - kLines := KLines(session.MarketDataStream, s.Symbol, s.MidPriceEMA.Interval) - s.ewma = trend.EWMA2(ClosePrices(kLines), s.MidPriceEMA.Window) + kLines := indicatorv2.KLines(session.MarketDataStream, s.Symbol, s.MidPriceEMA.Interval) + s.ewma = indicatorv2.EWMA2(indicatorv2.ClosePrices(kLines), s.MidPriceEMA.Window) s.preloadKLines(kLines, session, s.Symbol, s.MidPriceEMA.Interval) } func (s *Strategy) initializeIntensityIndicator(session *bbgo.ExchangeSession) { - kLines := KLines(session.MarketDataStream, s.Symbol, s.StrengthInterval) + kLines := indicatorv2.KLines(session.MarketDataStream, s.Symbol, s.StrengthInterval) s.intensity = Intensity(kLines, 10) s.preloadKLines(kLines, session, s.Symbol, s.StrengthInterval) } func (s *Strategy) initializePriceRangeBollinger(session *bbgo.ExchangeSession) { - kLines := KLines(session.MarketDataStream, s.Symbol, s.PriceRangeBollinger.Interval) - closePrices := ClosePrices(kLines) - s.boll = volatility.BollingerBand(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) + kLines := indicatorv2.KLines(session.MarketDataStream, s.Symbol, s.PriceRangeBollinger.Interval) + closePrices := indicatorv2.ClosePrices(kLines) + s.boll = indicatorv2.BollingerBand(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) s.preloadKLines(kLines, session, s.Symbol, s.PriceRangeBollinger.Interval) } diff --git a/pkg/strategy/trendtrader/strategy.go b/pkg/strategy/trendtrader/strategy.go index 3feedfa754..2766b6b610 100644 --- a/pkg/strategy/trendtrader/strategy.go +++ b/pkg/strategy/trendtrader/strategy.go @@ -1,4 +1,4 @@ -package trendtrader +package indicatorv2trader import ( "context" diff --git a/pkg/strategy/trendtrader/trend.go b/pkg/strategy/trendtrader/trend.go index d562e83443..9200f64ce5 100644 --- a/pkg/strategy/trendtrader/trend.go +++ b/pkg/strategy/trendtrader/trend.go @@ -1,4 +1,4 @@ -package trendtrader +package indicatorv2trader import ( "context" diff --git a/pkg/strategy/xfixedmaker/order_price_risk.go b/pkg/strategy/xfixedmaker/order_price_risk.go index bbd8a1d745..e7ec81b1c9 100644 --- a/pkg/strategy/xfixedmaker/order_price_risk.go +++ b/pkg/strategy/xfixedmaker/order_price_risk.go @@ -2,16 +2,16 @@ package xfixedmaker import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) type OrderPriceRiskControl struct { - referencePrice *trend.EWMAStream + referencePrice *indicatorv2.EWMAStream lossThreshold fixedpoint.Value } -func NewOrderPriceRiskControl(referencePrice *trend.EWMAStream, threshold fixedpoint.Value) *OrderPriceRiskControl { +func NewOrderPriceRiskControl(referencePrice *indicatorv2.EWMAStream, threshold fixedpoint.Value) *OrderPriceRiskControl { return &OrderPriceRiskControl{ referencePrice: referencePrice, lossThreshold: threshold, diff --git a/pkg/strategy/xfixedmaker/order_price_risk_test.go b/pkg/strategy/xfixedmaker/order_price_risk_test.go index d18fc2d647..da023c733e 100644 --- a/pkg/strategy/xfixedmaker/order_price_risk_test.go +++ b/pkg/strategy/xfixedmaker/order_price_risk_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/indicator/v2/trend" + indicatorv2 "github.com/c9s/bbgo/pkg/indicator/v2" "github.com/c9s/bbgo/pkg/types" ) @@ -15,7 +15,7 @@ func Test_OrderPriceRiskControl_IsSafe(t *testing.T) { lossThreshold := fixedpoint.NewFromFloat(-100) window := types.IntervalWindow{Window: 30, Interval: types.Interval1m} - refPriceEWMA := trend.EWMA2(nil, window.Window) + refPriceEWMA := indicatorv2.EWMA2(nil, window.Window) refPriceEWMA.PushAndEmit(refPrice) cases := []struct { diff --git a/pkg/indicator/v2/bst/bst.go b/pkg/types/bst/bst.go similarity index 100% rename from pkg/indicator/v2/bst/bst.go rename to pkg/types/bst/bst.go diff --git a/pkg/indicator/v2/bst/bst_test.go b/pkg/types/bst/bst_test.go similarity index 100% rename from pkg/indicator/v2/bst/bst_test.go rename to pkg/types/bst/bst_test.go diff --git a/pkg/indicator/v2/bst/compare.go b/pkg/types/bst/compare.go similarity index 100% rename from pkg/indicator/v2/bst/compare.go rename to pkg/types/bst/compare.go From 6f8bb9358f6789acfa37389d6d37cccf9a40b8da Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 30 Oct 2023 19:55:13 +0100 Subject: [PATCH 09/17] address csvsource comments --- .../csvsource/bybit_tick_downloader.go | 101 --------------- pkg/datasource/csvsource/enum.go | 20 +++ .../csvsource/exchange_tick_downloader.go | 118 +++++++++++++++++ .../exchange_tick_downloader_test.go | 28 ++++ ..._to_kline.go => exchange_tick_to_kline.go} | 121 ++++++++++-------- pkg/indicator/v2/bollinger_band.go | 5 +- pkg/indicator/v2/ema.go | 5 +- pkg/indicator/v2/kdj_test.go | 2 - pkg/indicator/v2/subtract_test.go | 48 +++---- 9 files changed, 261 insertions(+), 187 deletions(-) delete mode 100644 pkg/datasource/csvsource/bybit_tick_downloader.go create mode 100644 pkg/datasource/csvsource/enum.go create mode 100644 pkg/datasource/csvsource/exchange_tick_downloader.go create mode 100644 pkg/datasource/csvsource/exchange_tick_downloader_test.go rename pkg/datasource/csvsource/{bybit_tick_to_kline.go => exchange_tick_to_kline.go} (69%) diff --git a/pkg/datasource/csvsource/bybit_tick_downloader.go b/pkg/datasource/csvsource/bybit_tick_downloader.go deleted file mode 100644 index 6d37231a1c..0000000000 --- a/pkg/datasource/csvsource/bybit_tick_downloader.go +++ /dev/null @@ -1,101 +0,0 @@ -package csvsource - -import ( - "bytes" - "compress/gzip" - "errors" - "fmt" - "io" - "net/http" - "os" - "strings" - "time" -) - -func Download(symbol string, start time.Time) { - for { - var ( - path = fmt.Sprintf("pkg/datasource/csv/testdata/bybit/%s/", symbol) - fileName = fmt.Sprintf("%s%s.csv", strings.ToUpper(symbol), start.Format("2006-01-02")) - ) - - if fileExists(path + fileName) { - start = start.AddDate(0, 0, 1) - continue - } - - var url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", - strings.ToUpper(symbol), - fileName) - - fmt.Println("fetching ", url) - - err := readCSVFromUrl(url, path, fileName) - if err != nil { - fmt.Println(err) - break - } - - start = start.AddDate(0, 0, 1) - } -} - -func readCSVFromUrl(url, path, fileName string) error { - resp, err := http.Get(url) - if err != nil { - return err - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - csvContent, err := gUnzipData(body) - if err != nil { - return err - } - - if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { - err := os.MkdirAll(path, os.ModePerm) - if err != nil { - return err - } - } - - err = os.WriteFile(path+fileName, csvContent, 0666) - if err != nil { - return err - } - - return nil -} - -func gUnzipData(data []byte) (resData []byte, err error) { - b := bytes.NewBuffer(data) - - var r io.Reader - r, err = gzip.NewReader(b) - if err != nil { - return - } - - var resB bytes.Buffer - _, err = resB.ReadFrom(r) - if err != nil { - return - } - - resData = resB.Bytes() - - return -} - -func fileExists(fileName string) bool { - info, err := os.Stat(fileName) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} diff --git a/pkg/datasource/csvsource/enum.go b/pkg/datasource/csvsource/enum.go new file mode 100644 index 0000000000..0e75eb957c --- /dev/null +++ b/pkg/datasource/csvsource/enum.go @@ -0,0 +1,20 @@ +package csvsource + +type SupportedExchange int + +const ( + Bybit SupportedExchange = 0 +) + +type KLineInterval string + +const ( + M1 KLineInterval = "1m" + M5 KLineInterval = "5m" + M15 KLineInterval = "15m" + M30 KLineInterval = "30m" + H1 KLineInterval = "1h" + H2 KLineInterval = "2h" + H4 KLineInterval = "4h" + D1 KLineInterval = "1d" +) diff --git a/pkg/datasource/csvsource/exchange_tick_downloader.go b/pkg/datasource/csvsource/exchange_tick_downloader.go new file mode 100644 index 0000000000..26af4dc6b4 --- /dev/null +++ b/pkg/datasource/csvsource/exchange_tick_downloader.go @@ -0,0 +1,118 @@ +package csvsource + +import ( + "bytes" + "compress/gzip" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + log "github.com/sirupsen/logrus" +) + +func Download(saveToPath, symbol string, exchange SupportedExchange, start time.Time) error { + for { + var ( + fileName = fmt.Sprintf("%s%s.csv", symbol, start.Format("2006-01-02")) + url string + ) + + if fileExists(filepath.Join(saveToPath, fileName)) { + start = start.AddDate(0, 0, 1) + continue + } + + switch exchange { + case Bybit: + url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", + symbol, + fileName) + } + + log.Info("fetching ", url) + + csvContent, err := readCSVFromUrl(url) + if err != nil { + log.Error(err) + break + } + + err = write(csvContent, saveToPath, fileName) + if err != nil { + log.Error(err) + break + } + start = start.AddDate(0, 0, 1) + } + + return nil +} + +func readCSVFromUrl(url string) (csvContent []byte, err error) { + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("get %s: %w", url, err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read body %s: %w", url, err) + } + + csvContent, err = gUnzipData(body) + if err != nil { + return nil, fmt.Errorf("unzip data %s: %w", url, err) + } + + return csvContent, nil +} + +func write(content []byte, saveToPath, fileName string) error { + + if _, err := os.Stat(saveToPath); errors.Is(err, os.ErrNotExist) { + err := os.MkdirAll(saveToPath, os.ModePerm) + if err != nil { + return fmt.Errorf("mkdir %s: %w", saveToPath, err) + } + } + + err := os.WriteFile(fmt.Sprintf("%s/%s", saveToPath, fileName), content, 0666) + if err != nil { + return fmt.Errorf("write %s: %w", saveToPath+fileName, err) + } + + return nil +} + +func gUnzipData(data []byte) (resData []byte, err error) { + b := bytes.NewBuffer(data) + + var r io.Reader + r, err = gzip.NewReader(b) + if err != nil { + return + } + + var resB bytes.Buffer + _, err = resB.ReadFrom(r) + if err != nil { + return + } + + resData = resB.Bytes() + + return +} + +func fileExists(fileName string) bool { + info, err := os.Stat(fileName) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/pkg/datasource/csvsource/exchange_tick_downloader_test.go b/pkg/datasource/csvsource/exchange_tick_downloader_test.go new file mode 100644 index 0000000000..b7ec9f64a1 --- /dev/null +++ b/pkg/datasource/csvsource/exchange_tick_downloader_test.go @@ -0,0 +1,28 @@ +package csvsource + +import ( + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_Download(t *testing.T) { + var ( + symbol = strings.ToUpper("fxsusdt") + path = "testdata/bybit/" + symbol + start = time.Now().Round(0).Add(-24 * time.Hour) + ) + + err := Download(path, symbol, Bybit, start) + assert.NoError(t, err) + klines, err := ConvertTicksToKLines(path, symbol, M30) + assert.NoError(t, err) + err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, M30), klines) + assert.NoError(t, err) + err = os.RemoveAll("testdata/bybit/") + assert.NoError(t, err) +} diff --git a/pkg/datasource/csvsource/bybit_tick_to_kline.go b/pkg/datasource/csvsource/exchange_tick_to_kline.go similarity index 69% rename from pkg/datasource/csvsource/bybit_tick_to_kline.go rename to pkg/datasource/csvsource/exchange_tick_to_kline.go index 800a0240cb..4c5d78524e 100644 --- a/pkg/datasource/csvsource/bybit_tick_to_kline.go +++ b/pkg/datasource/csvsource/exchange_tick_to_kline.go @@ -28,24 +28,22 @@ type BybitCsvTick struct { ForeignNotional fixedpoint.Value `json:"foreignNotional"` } -func ConvertTicksToKLines(symbol string, interval time.Duration) error { +func ConvertTicksToKLines(path, symbol string, interval KLineInterval) ([]types.KLine, error) { err := filepath.Walk( - fmt.Sprintf("pkg/datasource/csv/testdata/bybit/%s/", symbol), + path, func(path string, info os.FileInfo, err error) error { if err != nil { - fmt.Println(err) - return err + return fmt.Errorf("walk %s: %w", path, err) } - fmt.Printf("dir: %v: name: %s\n", info.IsDir(), path) if !info.IsDir() { file, err := os.Open(path) if err != nil { - return err + return fmt.Errorf("open %s: %w", path, err) } reader := csv.NewReader(file) data, err := reader.ReadAll() if err != nil { - return err + return fmt.Errorf("read %s: %w", path, err) } for idx, row := range data { // skip header @@ -55,25 +53,26 @@ func ConvertTicksToKLines(symbol string, interval time.Duration) error { if idx == 1 { continue } - timestamp, err := strconv.ParseInt(strings.Split(row[0], ".")[0], 10, 64) + startTime := strings.Split(row[0], ".")[0] + timestamp, err := strconv.ParseInt(startTime, 10, 64) if err != nil { - return err + return fmt.Errorf("parse time %s: %w", startTime, err) } size, err := strconv.ParseFloat(row[3], 64) if err != nil { - return err + return fmt.Errorf("parse size %s: %w", row[3], err) } price, err := strconv.ParseFloat(row[4], 64) if err != nil { - return err + return fmt.Errorf("parse price %s: %w", row[4], err) } - homeNotional, err := strconv.ParseFloat(row[5], 64) + homeNotional, err := strconv.ParseFloat(row[8], 64) if err != nil { - return err + return fmt.Errorf("parse home notional %s: %w", row[8], err) } foreignNotional, err := strconv.ParseFloat(row[9], 64) if err != nil { - return err + return fmt.Errorf("parse foreign notional %s: %w", row[9], err) } ConvertBybitCsvTickToCandles(BybitCsvTick{ Timestamp: int64(timestamp), @@ -90,45 +89,14 @@ func ConvertTicksToKLines(symbol string, interval time.Duration) error { return nil }) if err != nil { - return err + return nil, err } - return WriteKLines(fmt.Sprintf("pkg/datasource/csv/testdata/%s_%s.csv", symbol, interval.String()), klines) -} - -// WriteKLines write csv to path. -func WriteKLines(path string, prices []types.KLine) (err error) { - file, err := os.Create(path) - if err != nil { - return errors.Wrap(err, "failed to open file") - } - defer func() { - err = file.Close() - if err != nil { - panic("failed to close file") - } - }() - w := csv.NewWriter(file) - defer w.Flush() - // Using Write - for _, record := range prices { - row := []string{strconv.Itoa(int(record.StartTime.UnixMilli())), dtos(record.Open), dtos(record.High), dtos(record.Low), dtos(record.Close), dtos(record.Volume)} - if err := w.Write(row); err != nil { - return errors.Wrap(err, "writing record to file") - } - } - if err != nil { - return err - } - - return nil -} - -func dtos(n fixedpoint.Value) string { - return fmt.Sprintf("%f", n.Float64()) + return klines, nil } -func ConvertBybitCsvTickToCandles(tick BybitCsvTick, interval time.Duration) { +// Conver ticks to KLine with interval +func ConvertBybitCsvTickToCandles(tick BybitCsvTick, interval KLineInterval) { var ( currentCandle = types.KLine{} high = fixedpoint.Zero @@ -178,10 +146,39 @@ func ConvertBybitCsvTickToCandles(tick BybitCsvTick, interval time.Duration) { } } -func detCandleStart(ts time.Time, interval time.Duration) (isOpen, isClose bool, t time.Time) { +// WriteKLines writes csv to path. +func WriteKLines(path string, prices []types.KLine) (err error) { + file, err := os.Create(path) + if err != nil { + return errors.Wrap(err, "failed to open file") + } + defer func() { + err = file.Close() + if err != nil { + panic("failed to close file") + } + }() + w := csv.NewWriter(file) + defer w.Flush() + // Using Write + for _, record := range prices { + row := []string{strconv.Itoa(int(record.StartTime.UnixMilli())), record.Open.String(), record.High.String(), record.Low.String(), record.Close.String(), record.Volume.String()} + if err := w.Write(row); err != nil { + return errors.Wrap(err, "writing record to file") + } + } + if err != nil { + return err + } + + return nil +} + +func detCandleStart(ts time.Time, kInterval KLineInterval) (isOpen, isClose bool, t time.Time) { + interval := convertInterval(kInterval) if len(klines) == 0 { start := time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour()+1, 0, 0, 0, ts.Location()) - if t.Minute() < int(interval.Minutes()) { // supported intervals 5 10 15 30 + if t.Minute() < int(interval.Minutes()) { // todo make enum of supported intervals 5 10 15 30 and extend to other intervals start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), int(interval.Minutes()), 0, 0, ts.Location()) } return true, false, start @@ -195,3 +192,25 @@ func detCandleStart(ts time.Time, interval time.Duration) (isOpen, isClose bool, return false, false, t } + +func convertInterval(kInterval KLineInterval) time.Duration { + var interval = time.Minute + switch kInterval { + case M1: + case M5: + interval = time.Minute * 5 + case M15: + interval = time.Minute * 15 + case M30: + interval = time.Minute * 30 + case H1: + interval = time.Hour + case H2: + interval = time.Hour * 2 + case H4: + interval = time.Hour * 4 + case D1: + interval = time.Hour * 24 + } + return interval +} diff --git a/pkg/indicator/v2/bollinger_band.go b/pkg/indicator/v2/bollinger_band.go index 0a90bd9988..68ec80a4e3 100644 --- a/pkg/indicator/v2/bollinger_band.go +++ b/pkg/indicator/v2/bollinger_band.go @@ -1,7 +1,6 @@ package indicatorv2 import ( - "github.com/c9s/bbgo/pkg/indicator/v2/trend" "github.com/c9s/bbgo/pkg/types" ) @@ -13,7 +12,7 @@ type BollingerStream struct { k float64 - SMA *trend.SMAStream + SMA *SMAStream StdDev *StdDevStream } @@ -26,7 +25,7 @@ type BollingerStream struct { // -> calculate stdDev -> calculate bandWidth -> get latest SMA -> upBand, downBand func BollingerBand(source types.Float64Source, window int, k float64) *BollingerStream { // bind these indicators before our main calculator - sma := trend.SMA(source, window) + sma := SMA(source, window) stdDev := StdDev(source, window) s := &BollingerStream{ diff --git a/pkg/indicator/v2/ema.go b/pkg/indicator/v2/ema.go index fdd9745f0d..fd62ca2ca1 100644 --- a/pkg/indicator/v2/ema.go +++ b/pkg/indicator/v2/ema.go @@ -9,12 +9,15 @@ type EWMAStream struct { multiplier float64 } -func EWMA2(source types.Float64Source, window int) *EWMAStream { +func EWMA2(source types.Float64Source, window int, multiplier ...float64) *EWMAStream { s := &EWMAStream{ Float64Series: types.NewFloat64Series(), window: window, multiplier: 2.0 / float64(1+window), } + if len(multiplier) == 1 { + s.multiplier = multiplier[0] + } s.Bind(source, s) return s } diff --git a/pkg/indicator/v2/kdj_test.go b/pkg/indicator/v2/kdj_test.go index 19329f9706..7c806904d3 100644 --- a/pkg/indicator/v2/kdj_test.go +++ b/pkg/indicator/v2/kdj_test.go @@ -3,7 +3,6 @@ package indicatorv2 import ( "testing" - "github.com/davecgh/go-spew/spew" "github.com/stretchr/testify/assert" "github.com/c9s/bbgo/pkg/types" @@ -32,7 +31,6 @@ func TestKdj(t *testing.T) { for _, candle := range ts { stream.EmitKLineClosed(candle) } - spew.Dump(ind) for i, v := range expectedJ { assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected KDJ.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) } diff --git a/pkg/indicator/v2/subtract_test.go b/pkg/indicator/v2/subtract_test.go index b8b3662c45..1ef3aace3a 100644 --- a/pkg/indicator/v2/subtract_test.go +++ b/pkg/indicator/v2/subtract_test.go @@ -2,39 +2,29 @@ package indicatorv2 import ( "testing" -) -func Test_v2_Subtract(t *testing.T) { - // stream := &types.StandardStream{} - // kLines := KLines(stream, "", "") - // closePrices := ClosePrices(kLines) - // toDiff := []DiffValue{ - // { - // Minuend: dec.New(10), - // Subtrahend: dec.New(8), - // }, - // { - // Minuend: dec.New(9), - // Subtrahend: dec.New(9), - // }, - // { - // Minuend: dec.New(8), - // Subtrahend: dec.New(10), - // }, - // } + "github.com/stretchr/testify/assert" - // diff := Subtract(fastEMA, slowEMA) + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) - // for i := .0; i < 50.0; i++ { - // stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(19_000.0 + i)}) - // } +func Test_v2_Subtract(t *testing.T) { + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + closePrices := ClosePrices(kLines) + fastEMA := EWMA2(closePrices, 10) + slowEMA := EWMA2(closePrices, 25) + subtract := Subtract(fastEMA, slowEMA) - // assert.Equal(t, []float64{2, 0, -2}, dec.FloatSlice(2, diff.Series()...)) + for i := .0; i < 50.0; i++ { + stream.EmitKLineClosed(types.KLine{Close: fixedpoint.NewFromFloat(19_000.0 + i)}) + } - // t.Logf("fastEMA: %+v", fastEMA.Slice) - // t.Logf("slowEMA: %+v", slowEMA.Slice) + t.Logf("fastEMA: %+v", fastEMA.Slice) + t.Logf("slowEMA: %+v", slowEMA.Slice) - // assert.Equal(t, len(subtract.a), len(subtract.b)) - // assert.Equal(t, len(subtract.a), len(subtract.Slice)) - // assert.InDelta(t, subtract.Slice[0], subtract.a[0]-subtract.b[0], 0.0001) + assert.Equal(t, len(subtract.a), len(subtract.b)) + assert.Equal(t, len(subtract.a), len(subtract.Slice)) + assert.InDelta(t, subtract.Slice[0], subtract.a[0]-subtract.b[0], 0.0001) } From 76f825fb302ef5f90d936b43b561e966a330e183 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Tue, 31 Oct 2023 03:31:39 +0100 Subject: [PATCH 10/17] refactor csvsource --- .gitignore | 1 + README.md | 2 +- pkg/datasource/csvsource/csv_kline_decoder.go | 1 + .../csvsource/csv_kline_reader_test.go | 4 +- .../csvsource/csv_tick_converter.go | 73 ++++++ pkg/datasource/csvsource/csv_tick_decoder.go | 95 ++++++++ pkg/datasource/csvsource/csv_tick_reader.go | 64 ++++++ .../csvsource/csv_tick_reader_test.go | 74 ++++++ pkg/datasource/csvsource/enum.go | 20 -- .../exchange_tick_downloader_test.go | 28 --- .../csvsource/exchange_tick_to_kline.go | 216 ------------------ pkg/datasource/csvsource/read_klines_test.go | 18 +- pkg/datasource/csvsource/read_ticks.go | 55 +++++ pkg/datasource/csvsource/read_ticks_test.go | 25 ++ .../testdata/FXSUSDT-ticks-2023-10-29.csv | 5 + ..._tick_downloader.go => tick_downloader.go} | 57 ++++- .../csvsource/tick_downloader_test.go | 47 ++++ pkg/datasource/csvsource/types.go | 87 +++++++ pkg/datasource/csvsource/write_klines.go | 39 ++++ 19 files changed, 630 insertions(+), 281 deletions(-) create mode 100644 pkg/datasource/csvsource/csv_tick_converter.go create mode 100644 pkg/datasource/csvsource/csv_tick_decoder.go create mode 100644 pkg/datasource/csvsource/csv_tick_reader.go create mode 100644 pkg/datasource/csvsource/csv_tick_reader_test.go delete mode 100644 pkg/datasource/csvsource/enum.go delete mode 100644 pkg/datasource/csvsource/exchange_tick_downloader_test.go delete mode 100644 pkg/datasource/csvsource/exchange_tick_to_kline.go create mode 100644 pkg/datasource/csvsource/read_ticks.go create mode 100644 pkg/datasource/csvsource/read_ticks_test.go create mode 100644 pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv rename pkg/datasource/csvsource/{exchange_tick_downloader.go => tick_downloader.go} (62%) create mode 100644 pkg/datasource/csvsource/tick_downloader_test.go create mode 100644 pkg/datasource/csvsource/types.go create mode 100644 pkg/datasource/csvsource/write_klines.go diff --git a/.gitignore b/.gitignore index f41e4ff8a7..5b42b45fd8 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ *.out .idea +.vscode # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/README.md b/README.md index 3712b7169a..12af0d06f1 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ the implementation. - [Tillson T3 Moving Average](./pkg/indicator/till.go) - [Triangular Moving Average](./pkg/indicator/tma.go) - [Variable Index Dynamic Average](./pkg/indicator/vidya.go) - - [Volatility Indicator](./pkg/indicator/indicatorv2.go) + - [Volatility Indicator](./pkg/indicator/volatility.go) - [Volume Weighted Average Price](./pkg/indicator/vwap.go) - [Zero Lag Exponential Moving Average](./pkg/indicator/zlema.go) - And more... diff --git a/pkg/datasource/csvsource/csv_kline_decoder.go b/pkg/datasource/csvsource/csv_kline_decoder.go index 38be70c13f..7bf0c146c6 100644 --- a/pkg/datasource/csvsource/csv_kline_decoder.go +++ b/pkg/datasource/csvsource/csv_kline_decoder.go @@ -118,6 +118,7 @@ func MetaTraderCSVKLineDecoder(record []string, interval time.Duration) (types.K return empty, ErrInvalidTimeFormat } k.StartTime = types.NewTimeFromUnix(t.Unix(), 0) + k.EndTime = types.NewTimeFromUnix(t.Add(interval).Unix(), 0) open, err := strconv.ParseFloat(record[2], 64) if err != nil { diff --git a/pkg/datasource/csvsource/csv_kline_reader_test.go b/pkg/datasource/csvsource/csv_kline_reader_test.go index 20bb68970b..0779613c13 100644 --- a/pkg/datasource/csvsource/csv_kline_reader_test.go +++ b/pkg/datasource/csvsource/csv_kline_reader_test.go @@ -32,7 +32,7 @@ func TestCSVKLineReader_ReadWithBinanceDecoder(t *testing.T) { name: "Read DOHLCV", give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", want: types.KLine{ - StartTime: types.NewTimeFromUnix(1609459200000, 0), + StartTime: types.NewTimeFromUnix(1609459200, 0), Open: fixedpoint.NewFromFloat(28923.63), High: fixedpoint.NewFromFloat(29031.34), Low: fixedpoint.NewFromFloat(28690.17), @@ -44,7 +44,7 @@ func TestCSVKLineReader_ReadWithBinanceDecoder(t *testing.T) { name: "Read DOHLC", give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000", want: types.KLine{ - StartTime: types.NewTimeFromUnix(1609459200000, 0), + StartTime: types.NewTimeFromUnix(1609459200, 0), Open: fixedpoint.NewFromFloat(28923.63), High: fixedpoint.NewFromFloat(29031.34), Low: fixedpoint.NewFromFloat(28690.17), diff --git a/pkg/datasource/csvsource/csv_tick_converter.go b/pkg/datasource/csvsource/csv_tick_converter.go new file mode 100644 index 0000000000..c6c9e1de47 --- /dev/null +++ b/pkg/datasource/csvsource/csv_tick_converter.go @@ -0,0 +1,73 @@ +package csvsource + +import ( + "time" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +var klines []types.KLine + +// Convert ticks to KLine with interval +func ConvertCsvTickToKLines(tick *CsvTick, interval KLineInterval) { + var ( + currentCandle = types.KLine{} + high = fixedpoint.Zero + low = fixedpoint.Zero + tickTimeStamp = time.Unix(tick.Timestamp, 0) + ) + isOpen, t := detCandleStart(tickTimeStamp, interval) + + if isOpen { + klines = append(klines, types.KLine{ + StartTime: types.NewTimeFromUnix(t.Unix(), 0), + EndTime: types.NewTimeFromUnix(t.Add(convertInterval(interval)).Unix(), 0), + Open: tick.Price, + High: tick.Price, + Low: tick.Price, + Close: tick.Price, + Volume: tick.HomeNotional, + }) + return + } + + currentCandle = klines[len(klines)-1] + + if tick.Price.Float64() > currentCandle.High.Float64() { + high = tick.Price + } else { + high = currentCandle.High + } + + if tick.Price.Float64() < currentCandle.Low.Float64() { + low = tick.Price + } else { + low = currentCandle.Low + } + + klines[len(klines)-1] = types.KLine{ + StartTime: currentCandle.StartTime, + EndTime: currentCandle.EndTime, + Open: currentCandle.Open, + High: high, + Low: low, + Close: tick.Price, + Volume: currentCandle.Volume.Add(tick.HomeNotional), + } +} + +func detCandleStart(ts time.Time, kInterval KLineInterval) (isOpen bool, t time.Time) { + if len(klines) == 0 { + return true, convertTimestamp(ts, kInterval) + } + var ( + current = klines[len(klines)-1] + end = current.EndTime.Time() + ) + if ts.After(end) { + return true, end + } + + return false, t +} diff --git a/pkg/datasource/csvsource/csv_tick_decoder.go b/pkg/datasource/csvsource/csv_tick_decoder.go new file mode 100644 index 0000000000..938efdd221 --- /dev/null +++ b/pkg/datasource/csvsource/csv_tick_decoder.go @@ -0,0 +1,95 @@ +package csvsource + +import ( + "encoding/csv" + "strconv" + "strings" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +// CSVTickDecoder is an extension point for CSVTickReader to support custom file formats. +type CSVTickDecoder func(record []string, index int) (*CsvTick, error) + +// NewBinanceCSVTickReader creates a new CSVTickReader for Binance CSV files. +func NewBinanceCSVTickReader(csv *csv.Reader) *CSVTickReader { + return &CSVTickReader{ + csv: csv, + decoder: BinanceCSVTickDecoder, + } +} + +// BinanceCSVKLineDecoder decodes a CSV record from Binance into a CsvTick. +func BinanceCSVTickDecoder(row []string, intex int) (*CsvTick, error) { + if len(row) < 7 { + return nil, ErrNotEnoughColumns + } + timestamp, err := strconv.ParseInt(row[5], 10, 64) + if err != nil { + return nil, ErrInvalidTimeFormat + } + size, err := strconv.ParseFloat(row[2], 64) + if err != nil { + return nil, ErrInvalidVolumeFormat + } + price, err := strconv.ParseFloat(row[1], 64) + if err != nil { + return nil, ErrInvalidPriceFormat + } + return &CsvTick{ + Timestamp: timestamp / 1000, + Size: fixedpoint.NewFromFloat(size), + Price: fixedpoint.NewFromFloat(price), + HomeNotional: fixedpoint.NewFromFloat(price * size), + }, nil +} + +// NewBinanceCSVTickReader creates a new CSVTickReader for Bybit CSV files. +func NewBybitCSVTickReader(csv *csv.Reader) *CSVTickReader { + return &CSVTickReader{ + csv: csv, + decoder: BybitCSVTickDecoder, + } +} + +// BybitCSVTickDecoder decodes a CSV record from Bybit into a CsvTick. +func BybitCSVTickDecoder(row []string, index int) (*CsvTick, error) { + if len(row) < 9 { + return nil, ErrNotEnoughColumns + } + if index == 0 { + return nil, nil + } + startTime := strings.Split(row[0], ".")[0] + timestamp, err := strconv.ParseInt(startTime, 10, 64) + if err != nil { + return nil, ErrInvalidTimeFormat + } + size, err := strconv.ParseFloat(row[3], 64) + if err != nil { + return nil, ErrInvalidVolumeFormat + } + price, err := strconv.ParseFloat(row[4], 64) + if err != nil { + return nil, ErrInvalidPriceFormat + } + homeNotional, err := strconv.ParseFloat(row[8], 64) + if err != nil { + return nil, ErrInvalidVolumeFormat + } + foreignNotional, err := strconv.ParseFloat(row[9], 64) + if err != nil { + return nil, ErrInvalidVolumeFormat + } + + return &CsvTick{ + Timestamp: timestamp, + Symbol: row[1], + Side: row[2], + Size: fixedpoint.NewFromFloat(size), + Price: fixedpoint.NewFromFloat(price), + TickDirection: row[5], + HomeNotional: fixedpoint.NewFromFloat(homeNotional), + ForeignNotional: fixedpoint.NewFromFloat(foreignNotional), + }, nil +} diff --git a/pkg/datasource/csvsource/csv_tick_reader.go b/pkg/datasource/csvsource/csv_tick_reader.go new file mode 100644 index 0000000000..1235260ad8 --- /dev/null +++ b/pkg/datasource/csvsource/csv_tick_reader.go @@ -0,0 +1,64 @@ +package csvsource + +import ( + "encoding/csv" + "io" +) + +var _ TickReader = (*CSVTickReader)(nil) + +// CSVTickReader is a CSVTickReader that reads from a CSV file. +type CSVTickReader struct { + csv *csv.Reader + decoder CSVTickDecoder +} + +// MakeCSVTickReader is a factory method type that creates a new CSVTickReader. +type MakeCSVTickReader func(csv *csv.Reader) *CSVTickReader + +// NewCSVKLineReader creates a new CSVKLineReader with the default Binance decoder. +func NewCSVTickReader(csv *csv.Reader) *CSVTickReader { + return &CSVTickReader{ + csv: csv, + decoder: BinanceCSVTickDecoder, + } +} + +// NewCSVTickReaderWithDecoder creates a new CSVKLineReader with the given decoder. +func NewCSVTickReaderWithDecoder(csv *csv.Reader, decoder CSVTickDecoder) *CSVTickReader { + return &CSVTickReader{ + csv: csv, + decoder: decoder, + } +} + +// ReadAll reads all the KLines from the underlying CSV data. +func (r *CSVTickReader) ReadAll(interval KLineInterval) error { + var i int + for { + tick, err := r.Read(i) + if err == io.EOF { + break + } + if err != nil { + return err + } + i++ + if tick == nil { + continue + } + ConvertCsvTickToKLines(tick, interval) + } + + return nil +} + +// Read reads the next KLine from the underlying CSV data. +func (r *CSVTickReader) Read(i int) (*CsvTick, error) { + rec, err := r.csv.Read() + if err != nil { + return nil, err + } + + return r.decoder(rec, i) +} diff --git a/pkg/datasource/csvsource/csv_tick_reader_test.go b/pkg/datasource/csvsource/csv_tick_reader_test.go new file mode 100644 index 0000000000..8c610a6c33 --- /dev/null +++ b/pkg/datasource/csvsource/csv_tick_reader_test.go @@ -0,0 +1,74 @@ +package csvsource + +import ( + "encoding/csv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +var assertTickEq = func(t *testing.T, exp, act *CsvTick) { + assert.Equal(t, exp.Timestamp, act.Timestamp) + assert.True(t, exp.Price == act.Price) + assert.True(t, exp.Size == act.Size) + assert.True(t, exp.HomeNotional == act.HomeNotional) +} + +func TestCSVTickReader_ReadWithBinanceDecoder(t *testing.T) { + tests := []struct { + name string + give string + want *CsvTick + err error + }{ + { + name: "Read Tick", + give: "11782578,6.00000000,1.00000000,14974844,14974844,1698623884463,True,True", + want: &CsvTick{ + Timestamp: 1698623884, + Size: fixedpoint.NewFromFloat(1), + Price: fixedpoint.NewFromFloat(6), + HomeNotional: fixedpoint.NewFromFloat(6), + }, + err: nil, + }, + { + name: "Not enough columns", + give: "1609459200000,28923.63000000,29031.34000000", + want: nil, + err: ErrNotEnoughColumns, + }, + { + name: "Invalid time format", + give: "11782578,6.00000000,1.00000000,14974844,14974844,23/12/2021,True,True", + want: nil, + err: ErrInvalidTimeFormat, + }, + { + name: "Invalid price format", + give: "11782578,sixty,1.00000000,14974844,14974844,1698623884463,True,True", + want: nil, + err: ErrInvalidPriceFormat, + }, + { + name: "Invalid size format", + give: "11782578,1.00000000,one,14974844,14974844,1698623884463,True,True", + want: nil, + err: ErrInvalidVolumeFormat, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + reader := NewBinanceCSVTickReader(csv.NewReader(strings.NewReader(tt.give))) + kline, err := reader.Read(0) + if err == nil { + assertTickEq(t, tt.want, kline) + } + assert.Equal(t, tt.err, err) + }) + } +} diff --git a/pkg/datasource/csvsource/enum.go b/pkg/datasource/csvsource/enum.go deleted file mode 100644 index 0e75eb957c..0000000000 --- a/pkg/datasource/csvsource/enum.go +++ /dev/null @@ -1,20 +0,0 @@ -package csvsource - -type SupportedExchange int - -const ( - Bybit SupportedExchange = 0 -) - -type KLineInterval string - -const ( - M1 KLineInterval = "1m" - M5 KLineInterval = "5m" - M15 KLineInterval = "15m" - M30 KLineInterval = "30m" - H1 KLineInterval = "1h" - H2 KLineInterval = "2h" - H4 KLineInterval = "4h" - D1 KLineInterval = "1d" -) diff --git a/pkg/datasource/csvsource/exchange_tick_downloader_test.go b/pkg/datasource/csvsource/exchange_tick_downloader_test.go deleted file mode 100644 index b7ec9f64a1..0000000000 --- a/pkg/datasource/csvsource/exchange_tick_downloader_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package csvsource - -import ( - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func Test_Download(t *testing.T) { - var ( - symbol = strings.ToUpper("fxsusdt") - path = "testdata/bybit/" + symbol - start = time.Now().Round(0).Add(-24 * time.Hour) - ) - - err := Download(path, symbol, Bybit, start) - assert.NoError(t, err) - klines, err := ConvertTicksToKLines(path, symbol, M30) - assert.NoError(t, err) - err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, M30), klines) - assert.NoError(t, err) - err = os.RemoveAll("testdata/bybit/") - assert.NoError(t, err) -} diff --git a/pkg/datasource/csvsource/exchange_tick_to_kline.go b/pkg/datasource/csvsource/exchange_tick_to_kline.go deleted file mode 100644 index 4c5d78524e..0000000000 --- a/pkg/datasource/csvsource/exchange_tick_to_kline.go +++ /dev/null @@ -1,216 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - "time" - - "github.com/pkg/errors" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -var klines []types.KLine - -type BybitCsvTick struct { - Timestamp int64 `json:"timestamp"` - Symbol string `json:"symbol"` - Side string `json:"side"` - TickDirection string `json:"tickDirection"` - Size fixedpoint.Value `json:"size"` - Price fixedpoint.Value `json:"price"` - HomeNotional fixedpoint.Value `json:"homeNotional"` - ForeignNotional fixedpoint.Value `json:"foreignNotional"` -} - -func ConvertTicksToKLines(path, symbol string, interval KLineInterval) ([]types.KLine, error) { - err := filepath.Walk( - path, - func(path string, info os.FileInfo, err error) error { - if err != nil { - return fmt.Errorf("walk %s: %w", path, err) - } - if !info.IsDir() { - file, err := os.Open(path) - if err != nil { - return fmt.Errorf("open %s: %w", path, err) - } - reader := csv.NewReader(file) - data, err := reader.ReadAll() - if err != nil { - return fmt.Errorf("read %s: %w", path, err) - } - for idx, row := range data { - // skip header - if idx == 0 { - continue - } - if idx == 1 { - continue - } - startTime := strings.Split(row[0], ".")[0] - timestamp, err := strconv.ParseInt(startTime, 10, 64) - if err != nil { - return fmt.Errorf("parse time %s: %w", startTime, err) - } - size, err := strconv.ParseFloat(row[3], 64) - if err != nil { - return fmt.Errorf("parse size %s: %w", row[3], err) - } - price, err := strconv.ParseFloat(row[4], 64) - if err != nil { - return fmt.Errorf("parse price %s: %w", row[4], err) - } - homeNotional, err := strconv.ParseFloat(row[8], 64) - if err != nil { - return fmt.Errorf("parse home notional %s: %w", row[8], err) - } - foreignNotional, err := strconv.ParseFloat(row[9], 64) - if err != nil { - return fmt.Errorf("parse foreign notional %s: %w", row[9], err) - } - ConvertBybitCsvTickToCandles(BybitCsvTick{ - Timestamp: int64(timestamp), - Symbol: row[1], - Side: row[2], - Size: fixedpoint.NewFromFloat(size), - Price: fixedpoint.NewFromFloat(price), - TickDirection: row[5], - HomeNotional: fixedpoint.NewFromFloat(homeNotional), - ForeignNotional: fixedpoint.NewFromFloat(foreignNotional), - }, interval) - } - } - return nil - }) - if err != nil { - return nil, err - } - - return klines, nil -} - -// Conver ticks to KLine with interval -func ConvertBybitCsvTickToCandles(tick BybitCsvTick, interval KLineInterval) { - var ( - currentCandle = types.KLine{} - high = fixedpoint.Zero - low = fixedpoint.Zero - tickTimeStamp = time.Unix(tick.Timestamp, 0) - ) - isOpen, isCLose, openTime := detCandleStart(tickTimeStamp, interval) - - if isOpen { - klines = append(klines, types.KLine{ - StartTime: types.NewTimeFromUnix(openTime.Unix(), 0), - Open: tick.Price, - High: tick.Price, - Low: tick.Price, - Close: tick.Price, - Volume: tick.HomeNotional, - }) - return - } - - currentCandle = klines[len(klines)-1] - - if tick.Price > currentCandle.High { - high = tick.Price - } else { - high = currentCandle.High - } - - if tick.Price < currentCandle.Low { - low = tick.Price - } else { - low = currentCandle.Low - } - - kline := types.KLine{ - StartTime: currentCandle.StartTime, - Open: currentCandle.Open, - High: high, - Low: low, - Close: tick.Price, - Volume: currentCandle.Volume.Add(tick.HomeNotional), - } - if isCLose { - klines = append(klines, kline) - } else { - klines[len(klines)-1] = kline - } -} - -// WriteKLines writes csv to path. -func WriteKLines(path string, prices []types.KLine) (err error) { - file, err := os.Create(path) - if err != nil { - return errors.Wrap(err, "failed to open file") - } - defer func() { - err = file.Close() - if err != nil { - panic("failed to close file") - } - }() - w := csv.NewWriter(file) - defer w.Flush() - // Using Write - for _, record := range prices { - row := []string{strconv.Itoa(int(record.StartTime.UnixMilli())), record.Open.String(), record.High.String(), record.Low.String(), record.Close.String(), record.Volume.String()} - if err := w.Write(row); err != nil { - return errors.Wrap(err, "writing record to file") - } - } - if err != nil { - return err - } - - return nil -} - -func detCandleStart(ts time.Time, kInterval KLineInterval) (isOpen, isClose bool, t time.Time) { - interval := convertInterval(kInterval) - if len(klines) == 0 { - start := time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour()+1, 0, 0, 0, ts.Location()) - if t.Minute() < int(interval.Minutes()) { // todo make enum of supported intervals 5 10 15 30 and extend to other intervals - start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), int(interval.Minutes()), 0, 0, ts.Location()) - } - return true, false, start - } else { - current := klines[len(klines)-1] - end := current.StartTime.Time().Add(interval) - if end.After(ts) { - return false, true, end - } - } - - return false, false, t -} - -func convertInterval(kInterval KLineInterval) time.Duration { - var interval = time.Minute - switch kInterval { - case M1: - case M5: - interval = time.Minute * 5 - case M15: - interval = time.Minute * 15 - case M30: - interval = time.Minute * 30 - case H1: - interval = time.Hour - case H2: - interval = time.Hour * 2 - case H4: - interval = time.Hour * 4 - case D1: - interval = time.Hour * 24 - } - return interval -} diff --git a/pkg/datasource/csvsource/read_klines_test.go b/pkg/datasource/csvsource/read_klines_test.go index 24a055dd57..4968800d22 100644 --- a/pkg/datasource/csvsource/read_klines_test.go +++ b/pkg/datasource/csvsource/read_klines_test.go @@ -10,14 +10,14 @@ import ( func TestReadKLinesFromCSV(t *testing.T) { expectedEndTime := time.Unix(1609459200, 0).Add(time.Hour) - prices, err := ReadKLinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) + klines, err := ReadKLinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) assert.NoError(t, err) - assert.Len(t, prices, 2158) - assert.Equal(t, int64(1609459200), prices[0].StartTime.Unix(), "StartTime") - assert.Equal(t, expectedEndTime.Unix(), prices[0].EndTime.Unix(), "EndTime") - assert.Equal(t, 28923.63, prices[0].Open.Float64(), "Open") - assert.Equal(t, 29031.34, prices[0].High.Float64(), "High") - assert.Equal(t, 28690.17, prices[0].Low.Float64(), "Low") - assert.Equal(t, 28995.13, prices[0].Close.Float64(), "Close") - assert.Equal(t, 2311.81144499, prices[0].Volume.Float64(), "Volume") + assert.Len(t, klines, 2158) + assert.Equal(t, int64(1609459200), klines[0].StartTime.Unix(), "StartTime") + assert.Equal(t, expectedEndTime.Unix(), klines[0].EndTime.Unix(), "EndTime") + assert.Equal(t, 28923.63, klines[0].Open.Float64(), "Open") + assert.Equal(t, 29031.34, klines[0].High.Float64(), "High") + assert.Equal(t, 28690.17, klines[0].Low.Float64(), "Low") + assert.Equal(t, 28995.13, klines[0].Close.Float64(), "Close") + assert.Equal(t, 2311.81144499, klines[0].Volume.Float64(), "Volume") } diff --git a/pkg/datasource/csvsource/read_ticks.go b/pkg/datasource/csvsource/read_ticks.go new file mode 100644 index 0000000000..ec7eefe631 --- /dev/null +++ b/pkg/datasource/csvsource/read_ticks.go @@ -0,0 +1,55 @@ +package csvsource + +import ( + "encoding/csv" + "io/fs" + "os" + "path/filepath" + + "github.com/c9s/bbgo/pkg/types" +) + +// TickReader is an interface for reading candlesticks. +type TickReader interface { + Read(i int) (*CsvTick, error) + ReadAll(interval KLineInterval) error +} + +// ReadTicksFromCSV reads all the .csv files in a given directory or a single file into a slice of Ticks. +// Wraps a default CSVTickReader with Binance decoder for convenience. +// For finer grained memory management use the base kline reader. +func ReadTicksFromCSV(path string, interval KLineInterval) ([]types.KLine, error) { + return ReadTicksFromCSVWithDecoder(path, interval, MakeCSVTickReader(NewBinanceCSVTickReader)) +} + +// ReadTicksFromCSVWithDecoder permits using a custom CSVTickReader. +func ReadTicksFromCSVWithDecoder(path string, interval KLineInterval, maker MakeCSVTickReader) ([]types.KLine, error) { + err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if filepath.Ext(path) != ".csv" { + return nil + } + file, err := os.Open(path) + if err != nil { + return err + } + //nolint:errcheck // Read ops only so safe to ignore err return + defer file.Close() + reader := maker(csv.NewReader(file)) + err = reader.ReadAll(interval) + if err != nil { + return err + } + return nil + }) + if err != nil { + return nil, err + } + + return klines, nil +} diff --git a/pkg/datasource/csvsource/read_ticks_test.go b/pkg/datasource/csvsource/read_ticks_test.go new file mode 100644 index 0000000000..928d93137e --- /dev/null +++ b/pkg/datasource/csvsource/read_ticks_test.go @@ -0,0 +1,25 @@ +package csvsource + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestReadTicksFromCSV(t *testing.T) { + expectedStartTime := time.Unix(1698623881260, 0) + expectedEndTime := expectedStartTime.Add(time.Minute) + // 11771900,6.06300000,7.70000000,14959258,14959262,1698537604628,False,True + + klines, err := ReadTicksFromCSV("./testdata/FXSUSDT-ticks-2023-10-29.csv", M1) + assert.NoError(t, err) + assert.Len(t, klines, 1) + assert.Equal(t, expectedStartTime.Unix(), klines[0].StartTime.Unix(), "StartTime") + assert.Equal(t, expectedEndTime.Unix(), klines[0].EndTime.Unix(), "EndTime") + assert.Equal(t, 6.0, klines[0].Open.Float64(), "Open") + assert.Equal(t, 6.0, klines[0].High.Float64(), "High") + assert.Equal(t, 6.0, klines[0].Low.Float64(), "Low") + assert.Equal(t, 6.0, klines[0].Close.Float64(), "Close") + assert.Equal(t, 111.0, klines[0].Volume.Float64(), "Volume") +} diff --git a/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv b/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv new file mode 100644 index 0000000000..2c9b593d47 --- /dev/null +++ b/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv @@ -0,0 +1,5 @@ +11782578,6.00000000,1.00000000,14974844,14974844,1698623884463,True,True +11782579,6.00000000,1.00000000,14974845,14974845,1698623893787,True,True +11782580,6.00000000,1.00000000,14974846,14974846,1698623893793,True,True +11782581,6.00000000,5.00000000,14974847,14974847,1698623920955,True,True +11782582,6.00000000,10.50000000,14974848,14974848,1698623939783,False,True diff --git a/pkg/datasource/csvsource/exchange_tick_downloader.go b/pkg/datasource/csvsource/tick_downloader.go similarity index 62% rename from pkg/datasource/csvsource/exchange_tick_downloader.go rename to pkg/datasource/csvsource/tick_downloader.go index 26af4dc6b4..039c0f4bf0 100644 --- a/pkg/datasource/csvsource/exchange_tick_downloader.go +++ b/pkg/datasource/csvsource/tick_downloader.go @@ -1,6 +1,7 @@ package csvsource import ( + "archive/zip" "bytes" "compress/gzip" "errors" @@ -31,11 +32,17 @@ func Download(saveToPath, symbol string, exchange SupportedExchange, start time. url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", symbol, fileName) + + case Binance: + url = fmt.Sprintf("https://data.binance.vision/data/spot/daily/aggTrades/%s/%s-aggTrades-%s.zip", + symbol, + symbol, + start.Format("2006-01-02")) } log.Info("fetching ", url) - csvContent, err := readCSVFromUrl(url) + csvContent, err := readCSVFromUrl(exchange, url) if err != nil { log.Error(err) break @@ -52,7 +59,7 @@ func Download(saveToPath, symbol string, exchange SupportedExchange, start time. return nil } -func readCSVFromUrl(url string) (csvContent []byte, err error) { +func readCSVFromUrl(exchange SupportedExchange, url string) (csvContent []byte, err error) { resp, err := http.Get(url) if err != nil { return nil, fmt.Errorf("get %s: %w", url, err) @@ -64,9 +71,18 @@ func readCSVFromUrl(url string) (csvContent []byte, err error) { return nil, fmt.Errorf("read body %s: %w", url, err) } - csvContent, err = gUnzipData(body) - if err != nil { - return nil, fmt.Errorf("unzip data %s: %w", url, err) + switch exchange { + case Bybit: + csvContent, err = gUnzipData(body) + if err != nil { + return nil, fmt.Errorf("gunzip data %s: %w", url, err) + } + + case Binance: + csvContent, err = unzipData(body) + if err != nil { + return nil, fmt.Errorf("unzip data %s: %w", url, err) + } } return csvContent, nil @@ -89,6 +105,37 @@ func write(content []byte, saveToPath, fileName string) error { return nil } +func unzipData(data []byte) (resData []byte, err error) { + zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + log.Error(err) + } + + if zipReader == nil || len(zipReader.File) == 0 { + return nil, errors.New("no data to unzip") + } + + // Read all the files from zip archive + for _, zipFile := range zipReader.File { + resData, err = readZipFile(zipFile) + if err != nil { + log.Error(err) + break + } + } + + return +} + +func readZipFile(zf *zip.File) ([]byte, error) { + f, err := zf.Open() + if err != nil { + return nil, err + } + defer f.Close() + return io.ReadAll(f) +} + func gUnzipData(data []byte) (resData []byte, err error) { b := bytes.NewBuffer(data) diff --git a/pkg/datasource/csvsource/tick_downloader_test.go b/pkg/datasource/csvsource/tick_downloader_test.go new file mode 100644 index 0000000000..e1dca905ea --- /dev/null +++ b/pkg/datasource/csvsource/tick_downloader_test.go @@ -0,0 +1,47 @@ +package csvsource + +import ( + "fmt" + "os" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_Download_Binance_Default(t *testing.T) { + var ( + symbol = strings.ToUpper("fxsusdt") + path = "testdata/binance/" + symbol + start = time.Now().Round(0).Add(-24 * time.Hour) + ) + + err := Download(path, symbol, Binance, start) + assert.NoError(t, err) + klines, err := ReadTicksFromCSV(path, H1) + assert.NoError(t, err) + assert.Equal(t, 24, len(klines)) + err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, H1), klines) + assert.NoError(t, err) + err = os.RemoveAll("testdata/binance/") + assert.NoError(t, err) +} + +func Test_Download_Bybit(t *testing.T) { + var ( + symbol = strings.ToUpper("fxsusdt") + path = "testdata/bybit/" + symbol + start = time.Now().Round(0).Add(-24 * time.Hour) + ) + + err := Download(path, symbol, Bybit, start) + assert.NoError(t, err) + klines, err := ReadTicksFromCSVWithDecoder(path, H1, MakeCSVTickReader(NewBybitCSVTickReader)) + assert.NoError(t, err) + assert.Equal(t, 24, len(klines)) + err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, H1), klines) + assert.NoError(t, err) + err = os.RemoveAll("testdata/bybit/") + assert.NoError(t, err) +} diff --git a/pkg/datasource/csvsource/types.go b/pkg/datasource/csvsource/types.go new file mode 100644 index 0000000000..3565505825 --- /dev/null +++ b/pkg/datasource/csvsource/types.go @@ -0,0 +1,87 @@ +package csvsource + +import ( + "time" + + "github.com/c9s/bbgo/pkg/fixedpoint" +) + +type CsvTick struct { + Timestamp int64 `json:"timestamp"` + Symbol string `json:"symbol"` + Side string `json:"side"` + TickDirection string `json:"tickDirection"` + Size fixedpoint.Value `json:"size"` + Price fixedpoint.Value `json:"price"` + HomeNotional fixedpoint.Value `json:"homeNotional"` + ForeignNotional fixedpoint.Value `json:"foreignNotional"` +} + +type SupportedExchange int + +const ( + Bybit SupportedExchange = 0 + Binance SupportedExchange = 1 +) + +type KLineInterval string + +const ( + M1 KLineInterval = "1m" + M5 KLineInterval = "5m" + M15 KLineInterval = "15m" + M30 KLineInterval = "30m" + H1 KLineInterval = "1h" + H2 KLineInterval = "2h" + H4 KLineInterval = "4h" + D1 KLineInterval = "1d" +) + +func convertInterval(kInterval KLineInterval) time.Duration { + var interval = time.Minute + switch kInterval { + case M1: + case M5: + return time.Minute * 5 + case M15: + return time.Minute * 15 + case M30: + return time.Minute * 30 + case H1: + return time.Hour + case H2: + return time.Hour * 2 + case H4: + return time.Hour * 4 + case D1: + return time.Hour * 24 + } + return interval +} + +func convertTimestamp(ts time.Time, kInterval KLineInterval) time.Time { + var start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), 0, 0, ts.Location()) + switch kInterval { + case M1: // default start as defined above + case M5: + minute := ts.Minute() - (ts.Minute() % 5) + start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) + case M15: + minute := ts.Minute() - (ts.Minute() % 15) + start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) + case M30: + minute := ts.Minute() - (ts.Minute() % 30) + start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) + case H1: + start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), 0, 0, 0, ts.Location()) + case H2: + hour := ts.Hour() - (ts.Hour() % 2) + start = time.Date(ts.Year(), ts.Month(), ts.Day(), hour, 0, 0, 0, ts.Location()) + case H4: + hour := ts.Hour() - (ts.Hour() % 4) + start = time.Date(ts.Year(), ts.Month(), ts.Day(), hour, 0, 0, 0, ts.Location()) + case D1: + start = time.Date(ts.Year(), ts.Month(), ts.Day(), 0, 0, 0, 0, ts.Location()) + } + return start +} diff --git a/pkg/datasource/csvsource/write_klines.go b/pkg/datasource/csvsource/write_klines.go new file mode 100644 index 0000000000..c1c4aecc1f --- /dev/null +++ b/pkg/datasource/csvsource/write_klines.go @@ -0,0 +1,39 @@ +package csvsource + +import ( + "encoding/csv" + "os" + "strconv" + + "github.com/pkg/errors" + + "github.com/c9s/bbgo/pkg/types" +) + +// WriteKLines writes csv to path. +func WriteKLines(path string, prices []types.KLine) (err error) { + file, err := os.Create(path) + if err != nil { + return errors.Wrap(err, "failed to open file") + } + defer func() { + err = file.Close() + if err != nil { + panic("failed to close file") + } + }() + w := csv.NewWriter(file) + defer w.Flush() + // Using Write + for _, record := range prices { + row := []string{strconv.Itoa(int(record.StartTime.Unix())), record.Open.String(), record.High.String(), record.Low.String(), record.Close.String(), record.Volume.String()} + if err := w.Write(row); err != nil { + return errors.Wrap(err, "writing record to file") + } + } + if err != nil { + return err + } + + return nil +} From 3b02bd43252b6843c556f3d70d7a98ec220fed1e Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Tue, 31 Oct 2023 16:29:51 +0100 Subject: [PATCH 11/17] clean-up pr --- pkg/exchange/bybit/types.go | 2 +- pkg/indicator/atrp.go | 2 +- pkg/indicator/v2/awesome_osc_test.go | 8 +++++++ pkg/indicator/v2/bollinger_band_test.go | 26 ++------------------- pkg/indicator/v2/trend_line_test.go | 30 ------------------------- pkg/strategy/trendtrader/trend.go | 2 +- 6 files changed, 13 insertions(+), 57 deletions(-) diff --git a/pkg/exchange/bybit/types.go b/pkg/exchange/bybit/types.go index f85d65ceaf..7ae55bd857 100644 --- a/pkg/exchange/bybit/types.go +++ b/pkg/exchange/bybit/types.go @@ -331,7 +331,7 @@ type TradeEvent struct { IndexPrice fixedpoint.Value `json:"indexPrice"` // The underlying price of the symbol when executing. Valid for option UnderlyingPrice fixedpoint.Value `json:"underlyingPrice"` - // Implied indicatorv2. Valid for option + // Implied volatility. Valid for option TradeIv string `json:"tradeIv"` } diff --git a/pkg/indicator/atrp.go b/pkg/indicator/atrp.go index 7496d005d7..d97bb0af8b 100644 --- a/pkg/indicator/atrp.go +++ b/pkg/indicator/atrp.go @@ -17,7 +17,7 @@ import ( // moves (sharp price movements that are allowed under certain exchange rules). The ATR is typically smoothed using a moving average to make it // more responsive to changes in the underlying price data. The ATRP is a useful indicator for traders because it provides a way to compare the // volatility of different securities, regardless of their individual prices. It can also be used to identify potential entry and exit points -// for trades based on changes in the security's indicatorv2. +// for trades based on changes in the security's volatility. // // Calculation: // diff --git a/pkg/indicator/v2/awesome_osc_test.go b/pkg/indicator/v2/awesome_osc_test.go index c522964782..3629d12b4f 100644 --- a/pkg/indicator/v2/awesome_osc_test.go +++ b/pkg/indicator/v2/awesome_osc_test.go @@ -52,3 +52,11 @@ func buildKLinesFromHL(high, low []float64) (klines []types.KLine) { return klines } + +func buildKLinesFromC(closing []float64) (klines []types.KLine) { + for i := range closing { + klines = append(klines, types.KLine{Close: n(closing[i])}) + } + + return klines +} diff --git a/pkg/indicator/v2/bollinger_band_test.go b/pkg/indicator/v2/bollinger_band_test.go index 3fc9928c54..6d8de18060 100644 --- a/pkg/indicator/v2/bollinger_band_test.go +++ b/pkg/indicator/v2/bollinger_band_test.go @@ -90,29 +90,14 @@ func TestBollingerBand(t *testing.T) { for _, line := range expectedLines { tokens := strings.Split(line, "\t") if len(tokens) == 5 { - // f1, _ := strconv.ParseFloat(tokens[0], 64) - // SMAs = append(SMAs, f1) - // f2, _ := strconv.ParseFloat(tokens[1], 64) - // STDEVs = append(STDEVs, f2) f3, _ := strconv.ParseFloat(tokens[2], 64) BBUPs = append(BBUPs, f3) f4, _ := strconv.ParseFloat(tokens[3], 64) BBLOs = append(BBLOs, f4) - // f5, _ := strconv.ParseFloat(tokens[4], 64) - // BBWs = append(BBWs, f5) } } - // assert.Equal(t, len(SMAs), 23) - window := 20 sigma := 2.0 - // ts := dec.Slice(src...) - // isma := trend.NewSimpleMovingAverage(window) - // isma.Update(ts...) - // smaHistory := isma.Series() - // iwstd := NewWindowedStandardDeviation(window) - // iwstd.Update(ts...) - // wstdHistory := iwstd.Series() source := types.NewFloat64Series() ind := BollingerBand(source, window, sigma) @@ -122,14 +107,7 @@ func TestBollingerBand(t *testing.T) { } for i := window - 1; i < len(ts); i++ { j := i - (window - 1) - // decimalAlmostEquals(t, smaHistory[i], SMAs[j], 0.01) - // decimalAlmostEquals(t, wstdHistory[i], STDEVs[j], 0.01) - decimalAlmostEquals(t, ind.UpBand.Slice[i], BBUPs[j], 0.01) - decimalAlmostEquals(t, ind.DownBand.Slice[i], BBLOs[j], 0.01) - // decimalAlmostEquals(t, bbUPHistory[i].Sub(bbLOHistory[i]), BBWs[j], 0.01) + assert.InEpsilon(t, ind.UpBand.Slice[i], BBUPs[j], 0.01) + assert.InEpsilon(t, ind.DownBand.Slice[i], BBLOs[j], 0.01) } } - -func decimalAlmostEquals(t *testing.T, actual float64, expected, epsilon float64) { - assert.InEpsilon(t, expected, actual, epsilon) -} diff --git a/pkg/indicator/v2/trend_line_test.go b/pkg/indicator/v2/trend_line_test.go index 67b9632f61..97adb93291 100644 --- a/pkg/indicator/v2/trend_line_test.go +++ b/pkg/indicator/v2/trend_line_test.go @@ -49,34 +49,4 @@ func TestTrendIndicator(t *testing.T) { } }) - - // t.Run("respects the window", func(t *testing.T) { - // indicator := NewTrendLine(4) - // indicator.Update(dec.Slice(-100, 1000, 0, 1, 2, 3)...) - // source := types.NewFloat64Series() - // sma := SMA(source, 9) - - // data := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9} - // for _, d := range data { - // source.PushAndEmit(d) - // } - - // assert.InDelta(t, 5, sma.Last(0), 0.001) - // assert.EqualValues(t, 1, indicator.Value().Float64()) - // }) - - // t.Run("does not allow an index out of bounds on the low end", func(t *testing.T) { - // indicator := NewTrendLine(2) - // indicator.Update(dec.Slice(0, 0, 1)...) - // source := types.NewFloat64Series() - // sma := SMA(source, 9) - - // data := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9} - // for _, d := range data { - // source.PushAndEmit(d) - // } - - // assert.InDelta(t, 5, sma.Last(0), 0.001) - // assert.EqualValues(t, 1, indicator.Value().Float64()) - // }) } diff --git a/pkg/strategy/trendtrader/trend.go b/pkg/strategy/trendtrader/trend.go index 9200f64ce5..d562e83443 100644 --- a/pkg/strategy/trendtrader/trend.go +++ b/pkg/strategy/trendtrader/trend.go @@ -1,4 +1,4 @@ -package indicatorv2trader +package trendtrader import ( "context" From 451e1835955a846be8ee58d757b2c904eac589a2 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Tue, 31 Oct 2023 23:07:11 +0100 Subject: [PATCH 12/17] continue to address comments --- pkg/datasource/csvsource/csv_kline_decoder.go | 75 +++---------------- .../csvsource/csv_tick_converter.go | 8 +- pkg/datasource/csvsource/csv_tick_decoder.go | 42 +++-------- pkg/datasource/csvsource/csv_tick_reader.go | 4 +- pkg/datasource/csvsource/read_ticks.go | 6 +- pkg/datasource/csvsource/read_ticks_test.go | 4 +- pkg/datasource/csvsource/tick_downloader.go | 40 +++++----- .../csvsource/tick_downloader_test.go | 20 +++-- pkg/datasource/csvsource/types.go | 71 ------------------ pkg/strategy/trendtrader/strategy.go | 2 +- pkg/types/interval.go | 55 ++++++++++++++ 11 files changed, 126 insertions(+), 201 deletions(-) diff --git a/pkg/datasource/csvsource/csv_kline_decoder.go b/pkg/datasource/csvsource/csv_kline_decoder.go index 7bf0c146c6..66119e90f4 100644 --- a/pkg/datasource/csvsource/csv_kline_decoder.go +++ b/pkg/datasource/csvsource/csv_kline_decoder.go @@ -56,39 +56,11 @@ func BinanceCSVKLineDecoder(record []string, interval time.Duration) (types.KLin } k.StartTime = types.NewTimeFromUnix(time.UnixMilli(msec).Unix(), 0) k.EndTime = types.NewTimeFromUnix(k.StartTime.Time().Add(interval).Unix(), 0) - - open, err := strconv.ParseFloat(record[1], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Open = fixedpoint.NewFromFloat(open) - - high, err := strconv.ParseFloat(record[2], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.High = fixedpoint.NewFromFloat(high) - - low, err := strconv.ParseFloat(record[3], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Low = fixedpoint.NewFromFloat(low) - - close, err := strconv.ParseFloat(record[4], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Close = fixedpoint.NewFromFloat(close) - - if len(record) > 5 { - vol, err := strconv.ParseFloat(record[5], 64) - if err != nil { - return empty, ErrInvalidVolumeFormat - } - k.Volume = fixedpoint.NewFromFloat(vol) - } - + k.Open = fixedpoint.MustNewFromString(record[1]) + k.High = fixedpoint.MustNewFromString(record[2]) + k.Low = fixedpoint.MustNewFromString(record[3]) + k.Close = fixedpoint.MustNewFromString(record[4]) + k.Volume = fixedpoint.MustNewFromString(record[5]) return k, nil } @@ -119,38 +91,11 @@ func MetaTraderCSVKLineDecoder(record []string, interval time.Duration) (types.K } k.StartTime = types.NewTimeFromUnix(t.Unix(), 0) k.EndTime = types.NewTimeFromUnix(t.Add(interval).Unix(), 0) - - open, err := strconv.ParseFloat(record[2], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Open = fixedpoint.NewFromFloat(open) - - high, err := strconv.ParseFloat(record[3], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.High = fixedpoint.NewFromFloat(high) - - low, err := strconv.ParseFloat(record[4], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Low = fixedpoint.NewFromFloat(low) - - close, err := strconv.ParseFloat(record[5], 64) - if err != nil { - return empty, ErrInvalidPriceFormat - } - k.Close = fixedpoint.NewFromFloat(close) - - if len(record) > 5 { - vol, err := strconv.ParseFloat(record[6], 64) - if err != nil { - return empty, ErrInvalidVolumeFormat - } - k.Volume = fixedpoint.NewFromFloat(vol) - } + k.Open = fixedpoint.MustNewFromString(record[2]) + k.High = fixedpoint.MustNewFromString(record[3]) + k.Low = fixedpoint.MustNewFromString(record[4]) + k.Close = fixedpoint.MustNewFromString(record[5]) + k.Volume = fixedpoint.MustNewFromString(record[6]) return k, nil } diff --git a/pkg/datasource/csvsource/csv_tick_converter.go b/pkg/datasource/csvsource/csv_tick_converter.go index c6c9e1de47..df2b2be77b 100644 --- a/pkg/datasource/csvsource/csv_tick_converter.go +++ b/pkg/datasource/csvsource/csv_tick_converter.go @@ -10,7 +10,7 @@ import ( var klines []types.KLine // Convert ticks to KLine with interval -func ConvertCsvTickToKLines(tick *CsvTick, interval KLineInterval) { +func ConvertCsvTickToKLines(tick *CsvTick, interval types.Interval) { var ( currentCandle = types.KLine{} high = fixedpoint.Zero @@ -22,7 +22,7 @@ func ConvertCsvTickToKLines(tick *CsvTick, interval KLineInterval) { if isOpen { klines = append(klines, types.KLine{ StartTime: types.NewTimeFromUnix(t.Unix(), 0), - EndTime: types.NewTimeFromUnix(t.Add(convertInterval(interval)).Unix(), 0), + EndTime: types.NewTimeFromUnix(t.Add(interval.Duration()).Unix(), 0), Open: tick.Price, High: tick.Price, Low: tick.Price, @@ -57,9 +57,9 @@ func ConvertCsvTickToKLines(tick *CsvTick, interval KLineInterval) { } } -func detCandleStart(ts time.Time, kInterval KLineInterval) (isOpen bool, t time.Time) { +func detCandleStart(ts time.Time, interval types.Interval) (isOpen bool, t time.Time) { if len(klines) == 0 { - return true, convertTimestamp(ts, kInterval) + return true, interval.Convert(ts) } var ( current = klines[len(klines)-1] diff --git a/pkg/datasource/csvsource/csv_tick_decoder.go b/pkg/datasource/csvsource/csv_tick_decoder.go index 938efdd221..1877f98c3c 100644 --- a/pkg/datasource/csvsource/csv_tick_decoder.go +++ b/pkg/datasource/csvsource/csv_tick_decoder.go @@ -28,19 +28,14 @@ func BinanceCSVTickDecoder(row []string, intex int) (*CsvTick, error) { if err != nil { return nil, ErrInvalidTimeFormat } - size, err := strconv.ParseFloat(row[2], 64) - if err != nil { - return nil, ErrInvalidVolumeFormat - } - price, err := strconv.ParseFloat(row[1], 64) - if err != nil { - return nil, ErrInvalidPriceFormat - } + size := fixedpoint.MustNewFromString(row[2]) + price := fixedpoint.MustNewFromString(row[1]) + hn := price.Mul(size) return &CsvTick{ Timestamp: timestamp / 1000, - Size: fixedpoint.NewFromFloat(size), - Price: fixedpoint.NewFromFloat(price), - HomeNotional: fixedpoint.NewFromFloat(price * size), + Size: size, + Price: price, + HomeNotional: hn, }, nil } @@ -65,31 +60,14 @@ func BybitCSVTickDecoder(row []string, index int) (*CsvTick, error) { if err != nil { return nil, ErrInvalidTimeFormat } - size, err := strconv.ParseFloat(row[3], 64) - if err != nil { - return nil, ErrInvalidVolumeFormat - } - price, err := strconv.ParseFloat(row[4], 64) - if err != nil { - return nil, ErrInvalidPriceFormat - } - homeNotional, err := strconv.ParseFloat(row[8], 64) - if err != nil { - return nil, ErrInvalidVolumeFormat - } - foreignNotional, err := strconv.ParseFloat(row[9], 64) - if err != nil { - return nil, ErrInvalidVolumeFormat - } - return &CsvTick{ Timestamp: timestamp, Symbol: row[1], Side: row[2], - Size: fixedpoint.NewFromFloat(size), - Price: fixedpoint.NewFromFloat(price), + Size: fixedpoint.MustNewFromString(row[3]), + Price: fixedpoint.MustNewFromString(row[4]), TickDirection: row[5], - HomeNotional: fixedpoint.NewFromFloat(homeNotional), - ForeignNotional: fixedpoint.NewFromFloat(foreignNotional), + HomeNotional: fixedpoint.MustNewFromString(row[8]), + ForeignNotional: fixedpoint.MustNewFromString(row[9]), }, nil } diff --git a/pkg/datasource/csvsource/csv_tick_reader.go b/pkg/datasource/csvsource/csv_tick_reader.go index 1235260ad8..ce06d6ed99 100644 --- a/pkg/datasource/csvsource/csv_tick_reader.go +++ b/pkg/datasource/csvsource/csv_tick_reader.go @@ -3,6 +3,8 @@ package csvsource import ( "encoding/csv" "io" + + "github.com/c9s/bbgo/pkg/types" ) var _ TickReader = (*CSVTickReader)(nil) @@ -33,7 +35,7 @@ func NewCSVTickReaderWithDecoder(csv *csv.Reader, decoder CSVTickDecoder) *CSVTi } // ReadAll reads all the KLines from the underlying CSV data. -func (r *CSVTickReader) ReadAll(interval KLineInterval) error { +func (r *CSVTickReader) ReadAll(interval types.Interval) error { var i int for { tick, err := r.Read(i) diff --git a/pkg/datasource/csvsource/read_ticks.go b/pkg/datasource/csvsource/read_ticks.go index ec7eefe631..dce70fb863 100644 --- a/pkg/datasource/csvsource/read_ticks.go +++ b/pkg/datasource/csvsource/read_ticks.go @@ -12,18 +12,18 @@ import ( // TickReader is an interface for reading candlesticks. type TickReader interface { Read(i int) (*CsvTick, error) - ReadAll(interval KLineInterval) error + ReadAll(interval types.Interval) error } // ReadTicksFromCSV reads all the .csv files in a given directory or a single file into a slice of Ticks. // Wraps a default CSVTickReader with Binance decoder for convenience. // For finer grained memory management use the base kline reader. -func ReadTicksFromCSV(path string, interval KLineInterval) ([]types.KLine, error) { +func ReadTicksFromCSV(path string, interval types.Interval) ([]types.KLine, error) { return ReadTicksFromCSVWithDecoder(path, interval, MakeCSVTickReader(NewBinanceCSVTickReader)) } // ReadTicksFromCSVWithDecoder permits using a custom CSVTickReader. -func ReadTicksFromCSVWithDecoder(path string, interval KLineInterval, maker MakeCSVTickReader) ([]types.KLine, error) { +func ReadTicksFromCSVWithDecoder(path string, interval types.Interval, maker MakeCSVTickReader) ([]types.KLine, error) { err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { if err != nil { return err diff --git a/pkg/datasource/csvsource/read_ticks_test.go b/pkg/datasource/csvsource/read_ticks_test.go index 928d93137e..73927a249d 100644 --- a/pkg/datasource/csvsource/read_ticks_test.go +++ b/pkg/datasource/csvsource/read_ticks_test.go @@ -5,6 +5,8 @@ import ( "time" "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" ) func TestReadTicksFromCSV(t *testing.T) { @@ -12,7 +14,7 @@ func TestReadTicksFromCSV(t *testing.T) { expectedEndTime := expectedStartTime.Add(time.Minute) // 11771900,6.06300000,7.70000000,14959258,14959262,1698537604628,False,True - klines, err := ReadTicksFromCSV("./testdata/FXSUSDT-ticks-2023-10-29.csv", M1) + klines, err := ReadTicksFromCSV("./testdata/FXSUSDT-ticks-2023-10-29.csv", types.Interval1m) assert.NoError(t, err) assert.Len(t, klines, 1) assert.Equal(t, expectedStartTime.Unix(), klines[0].StartTime.Unix(), "StartTime") diff --git a/pkg/datasource/csvsource/tick_downloader.go b/pkg/datasource/csvsource/tick_downloader.go index 039c0f4bf0..fe0dd12f85 100644 --- a/pkg/datasource/csvsource/tick_downloader.go +++ b/pkg/datasource/csvsource/tick_downloader.go @@ -13,13 +13,14 @@ import ( "time" log "github.com/sirupsen/logrus" + + "github.com/c9s/bbgo/pkg/types" ) -func Download(saveToPath, symbol string, exchange SupportedExchange, start time.Time) error { +func Download(saveToPath, symbol string, exchange types.ExchangeName, start time.Time) error { for { var ( fileName = fmt.Sprintf("%s%s.csv", symbol, start.Format("2006-01-02")) - url string ) if fileExists(filepath.Join(saveToPath, fileName)) { @@ -27,18 +28,7 @@ func Download(saveToPath, symbol string, exchange SupportedExchange, start time. continue } - switch exchange { - case Bybit: - url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", - symbol, - fileName) - - case Binance: - url = fmt.Sprintf("https://data.binance.vision/data/spot/daily/aggTrades/%s/%s-aggTrades-%s.zip", - symbol, - symbol, - start.Format("2006-01-02")) - } + var url = buildURL(exchange, symbol, fileName, start) log.Info("fetching ", url) @@ -59,7 +49,23 @@ func Download(saveToPath, symbol string, exchange SupportedExchange, start time. return nil } -func readCSVFromUrl(exchange SupportedExchange, url string) (csvContent []byte, err error) { +func buildURL(exchange types.ExchangeName, symbol string, fileName string, start time.Time) (url string) { + switch exchange { + case types.ExchangeBybit: + url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", + symbol, + fileName) + + case types.ExchangeBinance: + url = fmt.Sprintf("https://data.binance.vision/data/spot/daily/aggTrades/%s/%s-aggTrades-%s.zip", + symbol, + symbol, + start.Format("2006-01-02")) + } + return url +} + +func readCSVFromUrl(exchange types.ExchangeName, url string) (csvContent []byte, err error) { resp, err := http.Get(url) if err != nil { return nil, fmt.Errorf("get %s: %w", url, err) @@ -72,13 +78,13 @@ func readCSVFromUrl(exchange SupportedExchange, url string) (csvContent []byte, } switch exchange { - case Bybit: + case types.ExchangeBybit: csvContent, err = gUnzipData(body) if err != nil { return nil, fmt.Errorf("gunzip data %s: %w", url, err) } - case Binance: + case types.ExchangeBinance: csvContent, err = unzipData(body) if err != nil { return nil, fmt.Errorf("unzip data %s: %w", url, err) diff --git a/pkg/datasource/csvsource/tick_downloader_test.go b/pkg/datasource/csvsource/tick_downloader_test.go index e1dca905ea..d124d12775 100644 --- a/pkg/datasource/csvsource/tick_downloader_test.go +++ b/pkg/datasource/csvsource/tick_downloader_test.go @@ -8,39 +8,47 @@ import ( "time" "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" ) func Test_Download_Binance_Default(t *testing.T) { + if _, ok := os.LookupEnv("TEST_CSV_DOWNLOADER"); !ok { + t.Skip() + } var ( symbol = strings.ToUpper("fxsusdt") path = "testdata/binance/" + symbol start = time.Now().Round(0).Add(-24 * time.Hour) ) - err := Download(path, symbol, Binance, start) + err := Download(path, symbol, types.ExchangeBinance, start) assert.NoError(t, err) - klines, err := ReadTicksFromCSV(path, H1) + klines, err := ReadTicksFromCSV(path, types.Interval1h) assert.NoError(t, err) assert.Equal(t, 24, len(klines)) - err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, H1), klines) + err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, types.Interval1h), klines) assert.NoError(t, err) err = os.RemoveAll("testdata/binance/") assert.NoError(t, err) } func Test_Download_Bybit(t *testing.T) { + if _, ok := os.LookupEnv("TEST_CSV_DOWNLOADER"); !ok { + t.Skip() + } var ( symbol = strings.ToUpper("fxsusdt") path = "testdata/bybit/" + symbol start = time.Now().Round(0).Add(-24 * time.Hour) ) - err := Download(path, symbol, Bybit, start) + err := Download(path, symbol, types.ExchangeBybit, start) assert.NoError(t, err) - klines, err := ReadTicksFromCSVWithDecoder(path, H1, MakeCSVTickReader(NewBybitCSVTickReader)) + klines, err := ReadTicksFromCSVWithDecoder(path, types.Interval1h, MakeCSVTickReader(NewBybitCSVTickReader)) assert.NoError(t, err) assert.Equal(t, 24, len(klines)) - err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, H1), klines) + err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, types.Interval1h), klines) assert.NoError(t, err) err = os.RemoveAll("testdata/bybit/") assert.NoError(t, err) diff --git a/pkg/datasource/csvsource/types.go b/pkg/datasource/csvsource/types.go index 3565505825..e260e66937 100644 --- a/pkg/datasource/csvsource/types.go +++ b/pkg/datasource/csvsource/types.go @@ -1,8 +1,6 @@ package csvsource import ( - "time" - "github.com/c9s/bbgo/pkg/fixedpoint" ) @@ -16,72 +14,3 @@ type CsvTick struct { HomeNotional fixedpoint.Value `json:"homeNotional"` ForeignNotional fixedpoint.Value `json:"foreignNotional"` } - -type SupportedExchange int - -const ( - Bybit SupportedExchange = 0 - Binance SupportedExchange = 1 -) - -type KLineInterval string - -const ( - M1 KLineInterval = "1m" - M5 KLineInterval = "5m" - M15 KLineInterval = "15m" - M30 KLineInterval = "30m" - H1 KLineInterval = "1h" - H2 KLineInterval = "2h" - H4 KLineInterval = "4h" - D1 KLineInterval = "1d" -) - -func convertInterval(kInterval KLineInterval) time.Duration { - var interval = time.Minute - switch kInterval { - case M1: - case M5: - return time.Minute * 5 - case M15: - return time.Minute * 15 - case M30: - return time.Minute * 30 - case H1: - return time.Hour - case H2: - return time.Hour * 2 - case H4: - return time.Hour * 4 - case D1: - return time.Hour * 24 - } - return interval -} - -func convertTimestamp(ts time.Time, kInterval KLineInterval) time.Time { - var start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), 0, 0, ts.Location()) - switch kInterval { - case M1: // default start as defined above - case M5: - minute := ts.Minute() - (ts.Minute() % 5) - start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) - case M15: - minute := ts.Minute() - (ts.Minute() % 15) - start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) - case M30: - minute := ts.Minute() - (ts.Minute() % 30) - start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) - case H1: - start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), 0, 0, 0, ts.Location()) - case H2: - hour := ts.Hour() - (ts.Hour() % 2) - start = time.Date(ts.Year(), ts.Month(), ts.Day(), hour, 0, 0, 0, ts.Location()) - case H4: - hour := ts.Hour() - (ts.Hour() % 4) - start = time.Date(ts.Year(), ts.Month(), ts.Day(), hour, 0, 0, 0, ts.Location()) - case D1: - start = time.Date(ts.Year(), ts.Month(), ts.Day(), 0, 0, 0, 0, ts.Location()) - } - return start -} diff --git a/pkg/strategy/trendtrader/strategy.go b/pkg/strategy/trendtrader/strategy.go index 2766b6b610..3feedfa754 100644 --- a/pkg/strategy/trendtrader/strategy.go +++ b/pkg/strategy/trendtrader/strategy.go @@ -1,4 +1,4 @@ -package indicatorv2trader +package trendtrader import ( "context" diff --git a/pkg/types/interval.go b/pkg/types/interval.go index 689da68e71..d4ff8e4fbc 100644 --- a/pkg/types/interval.go +++ b/pkg/types/interval.go @@ -64,6 +64,61 @@ func (i Interval) Duration() time.Duration { return time.Duration(i.Milliseconds()) * time.Millisecond } +// Convert determines the candle open time from a given timestamp +// eg interval 1 hour and tick at timestamp 00:58 will return timestamp shifted to 00:00 +func (i Interval) Convert(ts time.Time) time.Time { + var start = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Second(), 0, 0, ts.Location()) + switch i { + case Interval1s: // default start as defined above + case Interval1m: + return time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), 0, 0, ts.Location()) + case Interval3m: + return shiftMinute(ts, 3) + case Interval5m: + return shiftMinute(ts, 5) + case Interval15m: + return shiftMinute(ts, 15) + case Interval30m: + return shiftMinute(ts, 30) + case Interval1h: + return time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), 0, 0, 0, ts.Location()) + case Interval2h: + return shiftHour(ts, 2) + case Interval4h: + return shiftHour(ts, 4) + case Interval6h: + return shiftHour(ts, 6) + case Interval12h: + return shiftHour(ts, 12) + case Interval1d: + return time.Date(ts.Year(), ts.Month(), ts.Day(), 0, 0, 0, 0, ts.Location()) + case Interval3d: + return shiftDay(ts, 3) + case Interval1w: + return shiftDay(ts, 7) + case Interval2w: + return shiftDay(ts, 14) + case Interval1mo: + return time.Date(ts.Year(), ts.Month(), 0, 0, 0, 0, 0, ts.Location()) + } + return start +} + +func shiftDay(ts time.Time, shift int) time.Time { + day := ts.Day() - (ts.Day() % shift) + return time.Date(ts.Year(), ts.Month(), day, 0, 0, 0, 0, ts.Location()) +} + +func shiftHour(ts time.Time, shift int) time.Time { + hour := ts.Hour() - (ts.Hour() % shift) + return time.Date(ts.Year(), ts.Month(), ts.Day(), hour, 0, 0, 0, ts.Location()) +} + +func shiftMinute(ts time.Time, shift int) time.Time { + minute := ts.Minute() - (ts.Minute() % shift) + return time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), minute, 0, 0, ts.Location()) +} + func (i *Interval) UnmarshalJSON(b []byte) (err error) { var a string err = json.Unmarshal(b, &a) From d685579b804c8d851e281596bf15a8d6aed53358 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Thu, 2 Nov 2023 17:07:43 +0100 Subject: [PATCH 13/17] reduce PR size --- pkg/datasource/csvsource/csv_kline_decoder.go | 101 - pkg/datasource/csvsource/csv_kline_reader.go | 65 - .../csvsource/csv_kline_reader_test.go | 155 -- .../csvsource/csv_tick_converter.go | 73 - pkg/datasource/csvsource/csv_tick_decoder.go | 73 - pkg/datasource/csvsource/csv_tick_reader.go | 66 - .../csvsource/csv_tick_reader_test.go | 74 - pkg/datasource/csvsource/read_klines.go | 59 - pkg/datasource/csvsource/read_klines_test.go | 23 - pkg/datasource/csvsource/read_ticks.go | 55 - pkg/datasource/csvsource/read_ticks_test.go | 27 - .../csvsource/testdata/BTCUSDT-1h-2021-Q1.csv | 2158 ----------------- .../testdata/FXSUSDT-ticks-2023-10-29.csv | 5 - pkg/datasource/csvsource/tick_downloader.go | 171 -- .../csvsource/tick_downloader_test.go | 55 - pkg/datasource/csvsource/types.go | 16 - pkg/datasource/csvsource/write_klines.go | 39 - pkg/indicator/v2/abdx.go | 98 + pkg/indicator/v2/abdx_test.go | 46 + pkg/indicator/v2/adx.go | 56 + pkg/indicator/v2/adx_test.go | 47 + pkg/indicator/v2/drift.go | 48 + pkg/indicator/v2/drift_test.go | 46 + pkg/indicator/v2/loss_gains.go | 106 + pkg/indicator/v2/loss_gains_test.go | 159 ++ pkg/indicator/v2/volume_profile.go | 195 -- pkg/indicator/v2/volume_profile_test.go | 41 - pkg/types/beta.go | 82 + 28 files changed, 688 insertions(+), 3451 deletions(-) delete mode 100644 pkg/datasource/csvsource/csv_kline_decoder.go delete mode 100644 pkg/datasource/csvsource/csv_kline_reader.go delete mode 100644 pkg/datasource/csvsource/csv_kline_reader_test.go delete mode 100644 pkg/datasource/csvsource/csv_tick_converter.go delete mode 100644 pkg/datasource/csvsource/csv_tick_decoder.go delete mode 100644 pkg/datasource/csvsource/csv_tick_reader.go delete mode 100644 pkg/datasource/csvsource/csv_tick_reader_test.go delete mode 100644 pkg/datasource/csvsource/read_klines.go delete mode 100644 pkg/datasource/csvsource/read_klines_test.go delete mode 100644 pkg/datasource/csvsource/read_ticks.go delete mode 100644 pkg/datasource/csvsource/read_ticks_test.go delete mode 100755 pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv delete mode 100644 pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv delete mode 100644 pkg/datasource/csvsource/tick_downloader.go delete mode 100644 pkg/datasource/csvsource/tick_downloader_test.go delete mode 100644 pkg/datasource/csvsource/types.go delete mode 100644 pkg/datasource/csvsource/write_klines.go create mode 100644 pkg/indicator/v2/abdx.go create mode 100644 pkg/indicator/v2/abdx_test.go create mode 100644 pkg/indicator/v2/adx.go create mode 100644 pkg/indicator/v2/adx_test.go create mode 100644 pkg/indicator/v2/drift.go create mode 100644 pkg/indicator/v2/drift_test.go create mode 100644 pkg/indicator/v2/loss_gains.go create mode 100644 pkg/indicator/v2/loss_gains_test.go delete mode 100644 pkg/indicator/v2/volume_profile.go delete mode 100644 pkg/indicator/v2/volume_profile_test.go create mode 100644 pkg/types/beta.go diff --git a/pkg/datasource/csvsource/csv_kline_decoder.go b/pkg/datasource/csvsource/csv_kline_decoder.go deleted file mode 100644 index 66119e90f4..0000000000 --- a/pkg/datasource/csvsource/csv_kline_decoder.go +++ /dev/null @@ -1,101 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "errors" - "fmt" - "strconv" - "time" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -// MetaTraderTimeFormat is the time format expected by the MetaTrader decoder when cols [0] and [1] are used. -const MetaTraderTimeFormat = "02/01/2006 15:04" - -var ( - // ErrNotEnoughColumns is returned when the CSV price record does not have enough columns. - ErrNotEnoughColumns = errors.New("not enough columns") - - // ErrInvalidTimeFormat is returned when the CSV price record does not have a valid time unix milli format. - ErrInvalidTimeFormat = errors.New("cannot parse time string") - - // ErrInvalidPriceFormat is returned when the CSV price record does not prices in expected format. - ErrInvalidPriceFormat = errors.New("OHLC prices must be in valid decimal format") - - // ErrInvalidVolumeFormat is returned when the CSV price record does not have a valid volume format. - ErrInvalidVolumeFormat = errors.New("volume must be in valid float format") -) - -// CSVKLineDecoder is an extension point for CSVKLineReader to support custom file formats. -type CSVKLineDecoder func(record []string, interval time.Duration) (types.KLine, error) - -// NewBinanceCSVKLineReader creates a new CSVKLineReader for Binance CSV files. -func NewBinanceCSVKLineReader(csv *csv.Reader) *CSVKLineReader { - return &CSVKLineReader{ - csv: csv, - decoder: BinanceCSVKLineDecoder, - } -} - -// BinanceCSVKLineDecoder decodes a CSV record from Binance or Bybit into a KLine. -func BinanceCSVKLineDecoder(record []string, interval time.Duration) (types.KLine, error) { - var ( - k, empty types.KLine - err error - ) - - if len(record) < 5 { - return k, ErrNotEnoughColumns - } - - msec, err := strconv.ParseInt(record[0], 10, 64) - if err != nil { - return empty, ErrInvalidTimeFormat - } - k.StartTime = types.NewTimeFromUnix(time.UnixMilli(msec).Unix(), 0) - k.EndTime = types.NewTimeFromUnix(k.StartTime.Time().Add(interval).Unix(), 0) - k.Open = fixedpoint.MustNewFromString(record[1]) - k.High = fixedpoint.MustNewFromString(record[2]) - k.Low = fixedpoint.MustNewFromString(record[3]) - k.Close = fixedpoint.MustNewFromString(record[4]) - k.Volume = fixedpoint.MustNewFromString(record[5]) - return k, nil -} - -// NewMetaTraderCSVKLineReader creates a new CSVKLineReader for MetaTrader CSV files. -func NewMetaTraderCSVKLineReader(csv *csv.Reader) *CSVKLineReader { - csv.Comma = ';' - return &CSVKLineReader{ - csv: csv, - decoder: MetaTraderCSVKLineDecoder, - } -} - -// MetaTraderCSVKLineDecoder decodes a CSV record from MetaTrader into a KLine. -func MetaTraderCSVKLineDecoder(record []string, interval time.Duration) (types.KLine, error) { - var ( - k, empty types.KLine - err error - ) - - if len(record) < 6 { - return k, ErrNotEnoughColumns - } - - tStr := fmt.Sprintf("%s %s", record[0], record[1]) - t, err := time.Parse(MetaTraderTimeFormat, tStr) - if err != nil { - return empty, ErrInvalidTimeFormat - } - k.StartTime = types.NewTimeFromUnix(t.Unix(), 0) - k.EndTime = types.NewTimeFromUnix(t.Add(interval).Unix(), 0) - k.Open = fixedpoint.MustNewFromString(record[2]) - k.High = fixedpoint.MustNewFromString(record[3]) - k.Low = fixedpoint.MustNewFromString(record[4]) - k.Close = fixedpoint.MustNewFromString(record[5]) - k.Volume = fixedpoint.MustNewFromString(record[6]) - - return k, nil -} diff --git a/pkg/datasource/csvsource/csv_kline_reader.go b/pkg/datasource/csvsource/csv_kline_reader.go deleted file mode 100644 index a5d252b5c6..0000000000 --- a/pkg/datasource/csvsource/csv_kline_reader.go +++ /dev/null @@ -1,65 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "io" - "time" - - "github.com/c9s/bbgo/pkg/types" -) - -var _ KLineReader = (*CSVKLineReader)(nil) - -// CSVKLineReader is a KLineReader that reads from a CSV file. -type CSVKLineReader struct { - csv *csv.Reader - decoder CSVKLineDecoder -} - -// MakeCSVKLineReader is a factory method type that creates a new CSVKLineReader. -type MakeCSVKLineReader func(csv *csv.Reader) *CSVKLineReader - -// NewCSVKLineReader creates a new CSVKLineReader with the default Binance decoder. -func NewCSVKLineReader(csv *csv.Reader) *CSVKLineReader { - return &CSVKLineReader{ - csv: csv, - decoder: BinanceCSVKLineDecoder, - } -} - -// NewCSVKLineReaderWithDecoder creates a new CSVKLineReader with the given decoder. -func NewCSVKLineReaderWithDecoder(csv *csv.Reader, decoder CSVKLineDecoder) *CSVKLineReader { - return &CSVKLineReader{ - csv: csv, - decoder: decoder, - } -} - -// Read reads the next KLine from the underlying CSV data. -func (r *CSVKLineReader) Read(interval time.Duration) (types.KLine, error) { - var k types.KLine - - rec, err := r.csv.Read() - if err != nil { - return k, err - } - - return r.decoder(rec, interval) -} - -// ReadAll reads all the KLines from the underlying CSV data. -func (r *CSVKLineReader) ReadAll(interval time.Duration) ([]types.KLine, error) { - var ks []types.KLine - for { - k, err := r.Read(interval) - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - ks = append(ks, k) - } - - return ks, nil -} diff --git a/pkg/datasource/csvsource/csv_kline_reader_test.go b/pkg/datasource/csvsource/csv_kline_reader_test.go deleted file mode 100644 index 0779613c13..0000000000 --- a/pkg/datasource/csvsource/csv_kline_reader_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -var assertKLineEq = func(t *testing.T, exp, act types.KLine) { - assert.Equal(t, exp.StartTime, act.StartTime) - assert.True(t, exp.Open == act.Open) - assert.True(t, exp.High == act.High) - assert.True(t, exp.Low == act.Low) - assert.True(t, exp.Close == act.Close) - assert.Equal(t, exp.Volume, act.Volume) -} - -func TestCSVKLineReader_ReadWithBinanceDecoder(t *testing.T) { - tests := []struct { - name string - give string - want types.KLine - err error - }{ - { - name: "Read DOHLCV", - give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", - want: types.KLine{ - StartTime: types.NewTimeFromUnix(1609459200, 0), - Open: fixedpoint.NewFromFloat(28923.63), - High: fixedpoint.NewFromFloat(29031.34), - Low: fixedpoint.NewFromFloat(28690.17), - Close: fixedpoint.NewFromFloat(28995.13), - Volume: fixedpoint.NewFromFloat(2311.81144500)}, - err: nil, - }, - { - name: "Read DOHLC", - give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000", - want: types.KLine{ - StartTime: types.NewTimeFromUnix(1609459200, 0), - Open: fixedpoint.NewFromFloat(28923.63), - High: fixedpoint.NewFromFloat(29031.34), - Low: fixedpoint.NewFromFloat(28690.17), - Close: fixedpoint.NewFromFloat(28995.13), - Volume: fixedpoint.NewFromFloat(0)}, - err: nil, - }, - { - name: "Not enough columns", - give: "1609459200000,28923.63000000,29031.34000000", - want: types.KLine{}, - err: ErrNotEnoughColumns, - }, - { - name: "Invalid time format", - give: "23/12/2021,28923.63000000,29031.34000000,28690.17000000,28995.13000000", - want: types.KLine{}, - err: ErrInvalidTimeFormat, - }, - { - name: "Invalid price format", - give: "1609459200000,sixty,29031.34000000,28690.17000000,28995.13000000", - want: types.KLine{}, - err: ErrInvalidPriceFormat, - }, - { - name: "Invalid volume format", - give: "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,vol", - want: types.KLine{}, - err: ErrInvalidVolumeFormat, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - reader := NewBinanceCSVKLineReader(csv.NewReader(strings.NewReader(tt.give))) - kline, err := reader.Read(time.Hour) - assert.Equal(t, tt.err, err) - assertKLineEq(t, tt.want, kline) - }) - } -} - -func TestCSVKLineReader_ReadAllWithDefaultDecoder(t *testing.T) { - records := []string{ - "1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500", - "1609459300000,28928.63000000,30031.34000000,22690.17000000,28495.13000000,3000.00", - } - reader := NewCSVKLineReader(csv.NewReader(strings.NewReader(strings.Join(records, "\n")))) - klines, err := reader.ReadAll(time.Hour) - assert.NoError(t, err) - assert.Len(t, klines, 2) -} - -func TestCSVKLineReader_ReadWithMetaTraderDecoder(t *testing.T) { - - tests := []struct { - name string - give string - want types.KLine - err error - }{ - { - name: "Read DOHLCV", - give: "11/12/2008;16:00;779.527679;780.964756;777.527679;779.964756;5", - want: types.KLine{ - StartTime: types.NewTimeFromUnix(time.Date(2008, 12, 11, 16, 0, 0, 0, time.UTC).Unix(), 0), - Open: fixedpoint.NewFromFloat(779.527679), - High: fixedpoint.NewFromFloat(780.964756), - Low: fixedpoint.NewFromFloat(777.527679), - Close: fixedpoint.NewFromFloat(779.964756), - Volume: fixedpoint.NewFromFloat(5)}, - err: nil, - }, - { - name: "Not enough columns", - give: "1609459200000;28923.63000000;29031.34000000", - want: types.KLine{}, - err: ErrNotEnoughColumns, - }, - { - name: "Invalid time format", - give: "23/12/2021;t;28923.63000000;29031.34000000;28690.17000000;28995.13000000", - want: types.KLine{}, - err: ErrInvalidTimeFormat, - }, - { - name: "Invalid price format", - give: "11/12/2008;00:00;sixty;29031.34000000;28690.17000000;28995.13000000", - want: types.KLine{}, - err: ErrInvalidPriceFormat, - }, - { - name: "Invalid volume format", - give: "11/12/2008;00:00;779.527679;780.964756;777.527679;779.964756;vol", - want: types.KLine{}, - err: ErrInvalidVolumeFormat, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - reader := NewMetaTraderCSVKLineReader(csv.NewReader(strings.NewReader(tt.give))) - kline, err := reader.Read(time.Hour) - assert.Equal(t, tt.err, err) - assertKLineEq(t, tt.want, kline) - }) - } -} diff --git a/pkg/datasource/csvsource/csv_tick_converter.go b/pkg/datasource/csvsource/csv_tick_converter.go deleted file mode 100644 index df2b2be77b..0000000000 --- a/pkg/datasource/csvsource/csv_tick_converter.go +++ /dev/null @@ -1,73 +0,0 @@ -package csvsource - -import ( - "time" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -var klines []types.KLine - -// Convert ticks to KLine with interval -func ConvertCsvTickToKLines(tick *CsvTick, interval types.Interval) { - var ( - currentCandle = types.KLine{} - high = fixedpoint.Zero - low = fixedpoint.Zero - tickTimeStamp = time.Unix(tick.Timestamp, 0) - ) - isOpen, t := detCandleStart(tickTimeStamp, interval) - - if isOpen { - klines = append(klines, types.KLine{ - StartTime: types.NewTimeFromUnix(t.Unix(), 0), - EndTime: types.NewTimeFromUnix(t.Add(interval.Duration()).Unix(), 0), - Open: tick.Price, - High: tick.Price, - Low: tick.Price, - Close: tick.Price, - Volume: tick.HomeNotional, - }) - return - } - - currentCandle = klines[len(klines)-1] - - if tick.Price.Float64() > currentCandle.High.Float64() { - high = tick.Price - } else { - high = currentCandle.High - } - - if tick.Price.Float64() < currentCandle.Low.Float64() { - low = tick.Price - } else { - low = currentCandle.Low - } - - klines[len(klines)-1] = types.KLine{ - StartTime: currentCandle.StartTime, - EndTime: currentCandle.EndTime, - Open: currentCandle.Open, - High: high, - Low: low, - Close: tick.Price, - Volume: currentCandle.Volume.Add(tick.HomeNotional), - } -} - -func detCandleStart(ts time.Time, interval types.Interval) (isOpen bool, t time.Time) { - if len(klines) == 0 { - return true, interval.Convert(ts) - } - var ( - current = klines[len(klines)-1] - end = current.EndTime.Time() - ) - if ts.After(end) { - return true, end - } - - return false, t -} diff --git a/pkg/datasource/csvsource/csv_tick_decoder.go b/pkg/datasource/csvsource/csv_tick_decoder.go deleted file mode 100644 index 1877f98c3c..0000000000 --- a/pkg/datasource/csvsource/csv_tick_decoder.go +++ /dev/null @@ -1,73 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "strconv" - "strings" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -// CSVTickDecoder is an extension point for CSVTickReader to support custom file formats. -type CSVTickDecoder func(record []string, index int) (*CsvTick, error) - -// NewBinanceCSVTickReader creates a new CSVTickReader for Binance CSV files. -func NewBinanceCSVTickReader(csv *csv.Reader) *CSVTickReader { - return &CSVTickReader{ - csv: csv, - decoder: BinanceCSVTickDecoder, - } -} - -// BinanceCSVKLineDecoder decodes a CSV record from Binance into a CsvTick. -func BinanceCSVTickDecoder(row []string, intex int) (*CsvTick, error) { - if len(row) < 7 { - return nil, ErrNotEnoughColumns - } - timestamp, err := strconv.ParseInt(row[5], 10, 64) - if err != nil { - return nil, ErrInvalidTimeFormat - } - size := fixedpoint.MustNewFromString(row[2]) - price := fixedpoint.MustNewFromString(row[1]) - hn := price.Mul(size) - return &CsvTick{ - Timestamp: timestamp / 1000, - Size: size, - Price: price, - HomeNotional: hn, - }, nil -} - -// NewBinanceCSVTickReader creates a new CSVTickReader for Bybit CSV files. -func NewBybitCSVTickReader(csv *csv.Reader) *CSVTickReader { - return &CSVTickReader{ - csv: csv, - decoder: BybitCSVTickDecoder, - } -} - -// BybitCSVTickDecoder decodes a CSV record from Bybit into a CsvTick. -func BybitCSVTickDecoder(row []string, index int) (*CsvTick, error) { - if len(row) < 9 { - return nil, ErrNotEnoughColumns - } - if index == 0 { - return nil, nil - } - startTime := strings.Split(row[0], ".")[0] - timestamp, err := strconv.ParseInt(startTime, 10, 64) - if err != nil { - return nil, ErrInvalidTimeFormat - } - return &CsvTick{ - Timestamp: timestamp, - Symbol: row[1], - Side: row[2], - Size: fixedpoint.MustNewFromString(row[3]), - Price: fixedpoint.MustNewFromString(row[4]), - TickDirection: row[5], - HomeNotional: fixedpoint.MustNewFromString(row[8]), - ForeignNotional: fixedpoint.MustNewFromString(row[9]), - }, nil -} diff --git a/pkg/datasource/csvsource/csv_tick_reader.go b/pkg/datasource/csvsource/csv_tick_reader.go deleted file mode 100644 index ce06d6ed99..0000000000 --- a/pkg/datasource/csvsource/csv_tick_reader.go +++ /dev/null @@ -1,66 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "io" - - "github.com/c9s/bbgo/pkg/types" -) - -var _ TickReader = (*CSVTickReader)(nil) - -// CSVTickReader is a CSVTickReader that reads from a CSV file. -type CSVTickReader struct { - csv *csv.Reader - decoder CSVTickDecoder -} - -// MakeCSVTickReader is a factory method type that creates a new CSVTickReader. -type MakeCSVTickReader func(csv *csv.Reader) *CSVTickReader - -// NewCSVKLineReader creates a new CSVKLineReader with the default Binance decoder. -func NewCSVTickReader(csv *csv.Reader) *CSVTickReader { - return &CSVTickReader{ - csv: csv, - decoder: BinanceCSVTickDecoder, - } -} - -// NewCSVTickReaderWithDecoder creates a new CSVKLineReader with the given decoder. -func NewCSVTickReaderWithDecoder(csv *csv.Reader, decoder CSVTickDecoder) *CSVTickReader { - return &CSVTickReader{ - csv: csv, - decoder: decoder, - } -} - -// ReadAll reads all the KLines from the underlying CSV data. -func (r *CSVTickReader) ReadAll(interval types.Interval) error { - var i int - for { - tick, err := r.Read(i) - if err == io.EOF { - break - } - if err != nil { - return err - } - i++ - if tick == nil { - continue - } - ConvertCsvTickToKLines(tick, interval) - } - - return nil -} - -// Read reads the next KLine from the underlying CSV data. -func (r *CSVTickReader) Read(i int) (*CsvTick, error) { - rec, err := r.csv.Read() - if err != nil { - return nil, err - } - - return r.decoder(rec, i) -} diff --git a/pkg/datasource/csvsource/csv_tick_reader_test.go b/pkg/datasource/csvsource/csv_tick_reader_test.go deleted file mode 100644 index 8c610a6c33..0000000000 --- a/pkg/datasource/csvsource/csv_tick_reader_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -var assertTickEq = func(t *testing.T, exp, act *CsvTick) { - assert.Equal(t, exp.Timestamp, act.Timestamp) - assert.True(t, exp.Price == act.Price) - assert.True(t, exp.Size == act.Size) - assert.True(t, exp.HomeNotional == act.HomeNotional) -} - -func TestCSVTickReader_ReadWithBinanceDecoder(t *testing.T) { - tests := []struct { - name string - give string - want *CsvTick - err error - }{ - { - name: "Read Tick", - give: "11782578,6.00000000,1.00000000,14974844,14974844,1698623884463,True,True", - want: &CsvTick{ - Timestamp: 1698623884, - Size: fixedpoint.NewFromFloat(1), - Price: fixedpoint.NewFromFloat(6), - HomeNotional: fixedpoint.NewFromFloat(6), - }, - err: nil, - }, - { - name: "Not enough columns", - give: "1609459200000,28923.63000000,29031.34000000", - want: nil, - err: ErrNotEnoughColumns, - }, - { - name: "Invalid time format", - give: "11782578,6.00000000,1.00000000,14974844,14974844,23/12/2021,True,True", - want: nil, - err: ErrInvalidTimeFormat, - }, - { - name: "Invalid price format", - give: "11782578,sixty,1.00000000,14974844,14974844,1698623884463,True,True", - want: nil, - err: ErrInvalidPriceFormat, - }, - { - name: "Invalid size format", - give: "11782578,1.00000000,one,14974844,14974844,1698623884463,True,True", - want: nil, - err: ErrInvalidVolumeFormat, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - reader := NewBinanceCSVTickReader(csv.NewReader(strings.NewReader(tt.give))) - kline, err := reader.Read(0) - if err == nil { - assertTickEq(t, tt.want, kline) - } - assert.Equal(t, tt.err, err) - }) - } -} diff --git a/pkg/datasource/csvsource/read_klines.go b/pkg/datasource/csvsource/read_klines.go deleted file mode 100644 index b3ae962ea4..0000000000 --- a/pkg/datasource/csvsource/read_klines.go +++ /dev/null @@ -1,59 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "io/fs" - "os" - "path/filepath" - "time" - - "github.com/c9s/bbgo/pkg/types" -) - -// KLineReader is an interface for reading candlesticks. -type KLineReader interface { - Read(interval time.Duration) (types.KLine, error) - ReadAll(interval time.Duration) ([]types.KLine, error) -} - -// ReadKLinesFromCSV reads all the .csv files in a given directory or a single file into a slice of KLines. -// Wraps a default CSVKLineReader with Binance decoder for convenience. -// For finer grained memory management use the base kline reader. -func ReadKLinesFromCSV(path string, interval time.Duration) ([]types.KLine, error) { - return ReadKLinesFromCSVWithDecoder(path, interval, MakeCSVKLineReader(NewBinanceCSVKLineReader)) -} - -// ReadKLinesFromCSVWithDecoder permits using a custom CSVKLineReader. -func ReadKLinesFromCSVWithDecoder(path string, interval time.Duration, maker MakeCSVKLineReader) ([]types.KLine, error) { - var prices []types.KLine - - err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if d.IsDir() { - return nil - } - if filepath.Ext(path) != ".csv" { - return nil - } - file, err := os.Open(path) - if err != nil { - return err - } - //nolint:errcheck // Read ops only so safe to ignore err return - defer file.Close() - reader := maker(csv.NewReader(file)) - klines, err := reader.ReadAll(interval) - if err != nil { - return err - } - prices = append(prices, klines...) - return nil - }) - if err != nil { - return nil, err - } - - return prices, nil -} diff --git a/pkg/datasource/csvsource/read_klines_test.go b/pkg/datasource/csvsource/read_klines_test.go deleted file mode 100644 index 4968800d22..0000000000 --- a/pkg/datasource/csvsource/read_klines_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package csvsource - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestReadKLinesFromCSV(t *testing.T) { - expectedEndTime := time.Unix(1609459200, 0).Add(time.Hour) - - klines, err := ReadKLinesFromCSV("./testdata/BTCUSDT-1h-2021-Q1.csv", time.Hour) - assert.NoError(t, err) - assert.Len(t, klines, 2158) - assert.Equal(t, int64(1609459200), klines[0].StartTime.Unix(), "StartTime") - assert.Equal(t, expectedEndTime.Unix(), klines[0].EndTime.Unix(), "EndTime") - assert.Equal(t, 28923.63, klines[0].Open.Float64(), "Open") - assert.Equal(t, 29031.34, klines[0].High.Float64(), "High") - assert.Equal(t, 28690.17, klines[0].Low.Float64(), "Low") - assert.Equal(t, 28995.13, klines[0].Close.Float64(), "Close") - assert.Equal(t, 2311.81144499, klines[0].Volume.Float64(), "Volume") -} diff --git a/pkg/datasource/csvsource/read_ticks.go b/pkg/datasource/csvsource/read_ticks.go deleted file mode 100644 index dce70fb863..0000000000 --- a/pkg/datasource/csvsource/read_ticks.go +++ /dev/null @@ -1,55 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "io/fs" - "os" - "path/filepath" - - "github.com/c9s/bbgo/pkg/types" -) - -// TickReader is an interface for reading candlesticks. -type TickReader interface { - Read(i int) (*CsvTick, error) - ReadAll(interval types.Interval) error -} - -// ReadTicksFromCSV reads all the .csv files in a given directory or a single file into a slice of Ticks. -// Wraps a default CSVTickReader with Binance decoder for convenience. -// For finer grained memory management use the base kline reader. -func ReadTicksFromCSV(path string, interval types.Interval) ([]types.KLine, error) { - return ReadTicksFromCSVWithDecoder(path, interval, MakeCSVTickReader(NewBinanceCSVTickReader)) -} - -// ReadTicksFromCSVWithDecoder permits using a custom CSVTickReader. -func ReadTicksFromCSVWithDecoder(path string, interval types.Interval, maker MakeCSVTickReader) ([]types.KLine, error) { - err := filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if d.IsDir() { - return nil - } - if filepath.Ext(path) != ".csv" { - return nil - } - file, err := os.Open(path) - if err != nil { - return err - } - //nolint:errcheck // Read ops only so safe to ignore err return - defer file.Close() - reader := maker(csv.NewReader(file)) - err = reader.ReadAll(interval) - if err != nil { - return err - } - return nil - }) - if err != nil { - return nil, err - } - - return klines, nil -} diff --git a/pkg/datasource/csvsource/read_ticks_test.go b/pkg/datasource/csvsource/read_ticks_test.go deleted file mode 100644 index 73927a249d..0000000000 --- a/pkg/datasource/csvsource/read_ticks_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package csvsource - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/types" -) - -func TestReadTicksFromCSV(t *testing.T) { - expectedStartTime := time.Unix(1698623881260, 0) - expectedEndTime := expectedStartTime.Add(time.Minute) - // 11771900,6.06300000,7.70000000,14959258,14959262,1698537604628,False,True - - klines, err := ReadTicksFromCSV("./testdata/FXSUSDT-ticks-2023-10-29.csv", types.Interval1m) - assert.NoError(t, err) - assert.Len(t, klines, 1) - assert.Equal(t, expectedStartTime.Unix(), klines[0].StartTime.Unix(), "StartTime") - assert.Equal(t, expectedEndTime.Unix(), klines[0].EndTime.Unix(), "EndTime") - assert.Equal(t, 6.0, klines[0].Open.Float64(), "Open") - assert.Equal(t, 6.0, klines[0].High.Float64(), "High") - assert.Equal(t, 6.0, klines[0].Low.Float64(), "Low") - assert.Equal(t, 6.0, klines[0].Close.Float64(), "Close") - assert.Equal(t, 111.0, klines[0].Volume.Float64(), "Volume") -} diff --git a/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv b/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv deleted file mode 100755 index c61915e335..0000000000 --- a/pkg/datasource/csvsource/testdata/BTCUSDT-1h-2021-Q1.csv +++ /dev/null @@ -1,2158 +0,0 @@ -1609459200000,28923.63000000,29031.34000000,28690.17000000,28995.13000000,2311.81144500,1609462799999,66768830.34010008,58389,1215.35923800,35103542.78288276,0 -1609462800000,28995.13000000,29470.00000000,28960.35000000,29409.99000000,5403.06847100,1609466399999,158357816.81805722,103896,3160.04170100,92613991.93555293,0 -1609466400000,29410.00000000,29465.26000000,29120.03000000,29194.65000000,2384.23156000,1609469999999,69842653.67342030,57646,1203.43350600,35252749.90832606,0 -1609470000000,29195.25000000,29367.00000000,29150.02000000,29278.40000000,1461.34507700,1609473599999,42760776.72551646,42510,775.91566600,22705547.98307977,0 -1609473600000,29278.41000000,29395.00000000,29029.40000000,29220.31000000,2038.04680300,1609477199999,59614637.30352874,55414,1003.34283400,29346381.88020654,0 -1609477200000,29220.31000000,29235.28000000,29084.11000000,29187.01000000,1469.95626200,1609480799999,42864538.70435811,41800,679.84674200,19827190.29247262,0 -1609480800000,29187.01000000,29270.00000000,29077.32000000,29174.35000000,1420.72629100,1609484399999,41446013.01819005,46400,699.14267600,20398322.75992173,0 -1609484400000,29174.35000000,29191.98000000,28806.54000000,29092.83000000,2380.18091800,1609487999999,69034619.09489940,53158,1054.72099100,30598457.40248306,0 -1609488000000,29092.84000000,29178.03000000,28872.24000000,29000.01000000,2008.16573900,1609491599999,58274190.69862189,55012,1022.06617000,29662447.72598589,0 -1609491600000,29000.01000000,29307.73000000,28970.00000000,29202.21000000,2022.05602200,1609495199999,59006512.26098600,43674,1208.47757800,35272717.35224266,0 -1609495200000,29202.21000000,29344.97000000,29152.88000000,29223.82000000,1944.25584100,1609498799999,56881923.87605724,46783,1014.53831900,29683027.81899852,0 -1609498800000,29223.82000000,29402.57000000,29212.44000000,29313.49000000,2309.22771700,1609502399999,67680909.41227815,49883,1309.01281600,38371497.60008983,0 -1609502400000,29313.49000000,29600.00000000,29150.00000000,29233.49000000,4191.91516100,1609505999999,123253838.23617110,82845,2333.30675300,68649197.19260735,0 -1609506000000,29233.49000000,29470.00000000,29200.00000000,29464.79000000,2211.29829000,1609509599999,64952612.17843147,51420,1102.40410000,32385604.78507834,0 -1609509600000,29464.79000000,29530.00000000,29266.15000000,29327.84000000,2612.67217000,1609513199999,76824362.53364532,63341,1251.80870900,36813212.09859227,0 -1609513200000,29327.83000000,29391.00000000,29030.14000000,29188.67000000,2779.06389400,1609516799999,81232002.48765679,71966,1262.58015300,36922103.13134250,0 -1609516800000,29188.67000000,29360.00000000,29125.00000000,29300.57000000,1490.32948400,1609520399999,43610391.87454118,41586,774.31247700,22657543.68634492,0 -1609520400000,29300.79000000,29339.76000000,28937.00000000,29079.64000000,2504.97709900,1609523999999,73023440.33533108,58010,1019.11805100,29715488.81612700,0 -1609524000000,29077.59000000,29259.98000000,28624.57000000,29072.70000000,4226.43004100,1609527599999,122480565.74309262,88856,1801.54203200,52236804.42358850,0 -1609527600000,29072.70000000,29125.32000000,28950.00000000,29029.04000000,1629.22872100,1609531199999,47324728.28361069,49038,752.04501500,21847593.00496335,0 -1609531200000,29029.04000000,29279.72000000,28880.37000000,29200.96000000,1838.54908200,1609534799999,53590098.13888548,52949,960.22896300,27992651.84744214,0 -1609534800000,29200.97000000,29289.82000000,29130.00000000,29160.39000000,1447.22964100,1609538399999,42285361.51600605,34181,776.32409300,22684651.47220357,0 -1609538400000,29163.17000000,29326.74000000,29104.57000000,29262.32000000,1127.03589700,1609541999999,32972283.53778708,37533,552.48585500,16165226.57121833,0 -1609542000000,29262.32000000,29338.89000000,29228.14000000,29331.69000000,971.12338500,1609545599999,28443882.37070015,28620,523.74728700,15341792.07335345,0 -1609545600000,29331.70000000,29338.59000000,28946.53000000,29197.48000000,2638.15937900,1609549199999,76856531.55900287,56787,1247.24618700,36330827.26651437,0 -1609549200000,29197.93000000,29400.00000000,29100.00000000,29359.47000000,1891.99724900,1609552799999,55385402.78970417,41136,960.49200100,28127469.61077394,0 -1609552800000,29359.46000000,29469.00000000,29320.01000000,29323.82000000,1704.83013700,1609556399999,50111457.75322650,34864,919.10250700,27018817.34672662,0 -1609556400000,29323.82000000,29382.49000000,29256.85000000,29351.95000000,1158.04176100,1609559999999,33963115.16512242,33338,563.83224300,16536321.44525508,0 -1609560000000,29351.95000000,29396.00000000,29220.00000000,29349.63000000,988.71107000,1609563599999,28985783.95102539,36593,513.99851400,15069817.63238660,0 -1609563600000,29349.63000000,29590.00000000,29349.63000000,29589.99000000,2778.87823100,1609567199999,81957934.92152147,48203,1889.25015400,55722199.46021065,0 -1609567200000,29589.99000000,29745.00000000,29450.00000000,29709.07000000,3030.24082000,1609570799999,89791157.01909066,61113,1919.61728100,56884432.27238282,0 -1609570800000,29709.06000000,29820.50000000,29623.31000000,29750.00000000,3067.81272400,1609574399999,91222945.57779763,56853,1999.91714500,59479642.41147299,0 -1609574400000,29751.47000000,29849.11000000,29640.00000000,29844.51000000,2358.08824100,1609577999999,70213292.48882387,55194,1185.87901000,35308597.74347598,0 -1609578000000,29844.52000000,29899.00000000,29578.05000000,29612.87000000,3188.49737500,1609581599999,94891130.35379542,63645,1490.10338400,44368671.01529736,0 -1609581600000,29612.88000000,29829.00000000,29473.91000000,29680.99000000,2315.18233700,1609585199999,68694488.75869353,49466,1119.01804200,33209227.51330484,0 -1609585200000,29679.51000000,29780.53000000,29622.79000000,29755.00000000,1365.03665500,1609588799999,40570945.42355006,29571,598.18892600,17778425.81689583,0 -1609588800000,29754.99000000,30888.00000000,29741.39000000,30604.03000000,12772.56604400,1609592399999,387025691.68456484,200036,7693.61308900,232831158.19322058,0 -1609592400000,30604.03000000,31561.87000000,30521.00000000,31541.17000000,9182.42970300,1609595999999,284862696.67061101,155703,5000.51248100,155171075.80361159,0 -1609596000000,31546.06000000,31567.89000000,31065.00000000,31290.53000000,6447.78389700,1609599599999,201609364.53663465,115280,3104.82695800,97083027.72110683,0 -1609599600000,31290.53000000,31800.00000000,31236.37000000,31691.29000000,5626.19375500,1609603199999,177435149.22325535,97954,2936.49097300,92602951.94086850,0 -1609603200000,31691.09000000,33000.00000000,31616.42000000,32482.28000000,15432.28518600,1609606799999,500065150.69207718,243515,7704.18957300,249664588.17049993,0 -1609606800000,32484.28000000,32935.00000000,32394.77000000,32856.96000000,6402.18070100,1609610399999,209101591.46210164,106138,3400.89904700,111088781.87106785,0 -1609610400000,32856.95000000,33300.00000000,32421.00000000,32999.98000000,7170.29541200,1609613999999,235363454.12117517,107993,3731.00286900,122570325.41192683,0 -1609614000000,32999.98000000,33220.00000000,32690.00000000,33027.20000000,5844.85649900,1609617599999,192991798.29034694,100521,3074.28482400,101527404.04491779,0 -1609617600000,33027.20000000,33061.37000000,30550.00000000,30667.22000000,15733.28311200,1609621199999,504482345.09340442,213120,7147.18982200,229365443.72211530,0 -1609621200000,30669.43000000,32005.94000000,30300.00000000,31694.59000000,10395.12064200,1609624799999,326513926.94158377,161944,5285.50818400,165946681.21302372,0 -1609624800000,31693.53000000,32311.92000000,31424.96000000,32145.66000000,3879.06209400,1609628399999,124189288.57427153,91572,1766.47715100,56575341.60307028,0 -1609628400000,32143.53000000,32246.67000000,31500.00000000,32178.33000000,4622.34033800,1609631999999,147557520.62016068,85383,2194.66488100,70073494.65701959,0 -1609632000000,32176.45000000,32497.80000000,31962.99000000,32447.94000000,3346.06214100,1609635599999,108006253.42272902,63472,1758.75207800,56783635.03682368,0 -1609635600000,32447.95000000,32790.07000000,32201.00000000,32585.09000000,3401.15220700,1609639199999,110773399.69333609,70692,1770.81858900,57671008.07579552,0 -1609639200000,32583.04000000,32884.09000000,32550.00000000,32741.67000000,2017.20975900,1609642799999,66039545.22800387,48226,1010.49816300,33089617.80521227,0 -1609642800000,32741.68000000,32756.00000000,32404.00000000,32573.87000000,2125.87880000,1609646399999,69347477.45908845,46215,899.91924100,29356251.53461650,0 -1609646400000,32576.11000000,33250.00000000,32450.00000000,33192.53000000,3436.07098400,1609649999999,112792746.66880588,60917,2045.68522700,67209328.65906662,0 -1609650000000,33192.53000000,34180.00000000,33109.44000000,33758.67000000,10355.07031500,1609653599999,350167811.09683042,176812,5513.67143800,186390893.19406770,0 -1609653600000,33758.67000000,34110.05000000,33651.12000000,33967.13000000,4526.91097400,1609657199999,153551636.94704574,95086,2360.33759000,80068532.23998821,0 -1609657200000,33967.13000000,34778.11000000,33737.19000000,34452.34000000,7968.07402300,1609660799999,273877823.02471700,135337,3835.12822700,131801254.42768407,0 -1609660800000,34451.78000000,34670.41000000,33757.29000000,34367.68000000,6146.77411200,1609664399999,210713141.05225317,110795,2947.24110400,101077763.49754152,0 -1609664400000,34367.35000000,34588.88000000,33800.00000000,34190.55000000,6052.67897200,1609667999999,206713459.38775728,114590,2746.05092500,93808940.47277085,0 -1609668000000,34189.98000000,34350.00000000,33403.00000000,33877.96000000,6335.22664200,1609671599999,214615660.03475803,120518,3038.83693400,102960933.70594279,0 -1609671600000,33877.96000000,34450.00000000,33787.55000000,34413.53000000,4116.85314100,1609675199999,140535081.14537481,92262,2255.03787400,76986787.81280623,0 -1609675200000,34413.53000000,34600.00000000,33928.75000000,34103.72000000,4546.28348100,1609678799999,155830593.73039518,89900,2266.26171700,77715495.36382322,0 -1609678800000,34103.73000000,34385.02000000,33800.00000000,33880.00000000,4373.73837600,1609682399999,149031480.84569385,87957,2050.56080100,69890174.70069015,0 -1609682400000,33877.98000000,34150.00000000,33450.00000000,33811.54000000,5928.80556300,1609685999999,200638151.95697655,112757,2900.71102100,98139759.78261895,0 -1609686000000,33811.54000000,33873.45000000,32727.00000000,33506.62000000,8391.24975700,1609689599999,279582888.95484869,140091,3792.71472900,126401018.81240185,0 -1609689600000,33505.15000000,33822.69000000,32650.00000000,32676.74000000,7983.73912500,1609693199999,266031558.97452663,129178,3881.70200600,129341713.44537748,0 -1609693200000,32676.75000000,33333.33000000,32454.73000000,32909.27000000,7447.80916300,1609696799999,244812012.99385249,135756,3643.79336400,119852164.82576344,0 -1609696800000,32907.51000000,33031.57000000,32267.00000000,32769.76000000,4707.19994300,1609700399999,153750662.05561621,94512,2355.51975900,76959635.32715938,0 -1609700400000,32769.79000000,32930.00000000,32455.71000000,32772.21000000,2288.43941200,1609703999999,74825548.95742354,73266,1072.31709100,35065540.58420238,0 -1609704000000,32775.10000000,33816.00000000,32727.10000000,33726.21000000,5420.67818300,1609707599999,181382884.16276131,111426,2919.38549700,97677133.65780773,0 -1609707600000,33725.72000000,33861.92000000,33506.00000000,33558.34000000,2123.06799200,1609711199999,71508817.93767056,76216,1052.73779500,35464167.05367330,0 -1609711200000,33559.06000000,33661.10000000,33000.00000000,33119.14000000,2841.03309300,1609714799999,94606664.88271222,74965,1251.99851100,41712740.73810901,0 -1609714800000,33119.14000000,33600.00000000,32600.00000000,33000.05000000,5077.56059200,1609718399999,168463124.87883950,108752,2380.65319000,79003943.17790337,0 -1609718400000,33000.05000000,33111.44000000,32400.25000000,32843.88000000,4792.20683100,1609721999999,157090780.02866342,102303,2337.32205000,76640069.54148755,0 -1609722000000,32843.89000000,33327.00000000,32602.47000000,33191.04000000,3390.02387200,1609725599999,111723279.13155555,77232,1619.89909700,53373905.14610674,0 -1609725600000,33191.05000000,33588.00000000,32958.38000000,33454.22000000,3180.35078300,1609729199999,105765257.03035539,73174,1565.73680600,52080821.90135500,0 -1609729200000,33454.21000000,33510.71000000,33160.00000000,33505.16000000,3174.20913400,1609732799999,105885637.67106639,74546,1550.96606000,51736216.72372775,0 -1609732800000,33505.15000000,33600.00000000,33186.14000000,33257.55000000,3167.02927300,1609736399999,105695860.81390999,70718,1582.28668800,52806095.53989332,0 -1609736400000,33257.56000000,33315.90000000,32802.25000000,32813.01000000,3990.70088000,1609739999999,132098247.27391540,86995,1912.44957000,63309431.04982456,0 -1609740000000,32813.01000000,33408.00000000,32813.00000000,33100.02000000,4768.76492800,1609743599999,157679676.36409471,93791,2665.12417700,88130614.48937725,0 -1609743600000,33100.02000000,33148.69000000,31505.00000000,32068.84000000,9472.37682800,1609747199999,305928119.96734844,163230,4856.66906300,156851370.47884084,0 -1609747200000,32068.84000000,32567.88000000,31450.00000000,32045.14000000,6529.25324800,1609750799999,209132998.40311764,125127,2998.78773300,96102959.13230930,0 -1609750800000,32045.15000000,32152.15000000,30248.85000000,31038.63000000,11271.89653100,1609754399999,351321935.49618102,173055,5038.68188200,157122742.24963213,0 -1609754400000,31038.35000000,31227.33000000,28130.00000000,30270.76000000,19376.83117900,1609757999999,573629351.31642204,305630,9223.43025700,273302725.96630042,0 -1609758000000,30270.76000000,30900.20000000,29400.00000000,30743.06000000,9413.49006700,1609761599999,283733132.88333011,170181,4539.81272700,136956401.56307816,0 -1609761600000,30742.99000000,31434.07000000,30454.25000000,31219.02000000,8316.88082800,1609765199999,257727418.56933529,153242,3929.17547400,121744030.72879640,0 -1609765200000,31219.03000000,31400.00000000,30600.00000000,31400.00000000,5474.65478700,1609768799999,169692056.80846927,101540,2600.95311600,80643934.90996195,0 -1609768800000,31400.00000000,32167.93000000,31400.00000000,32113.68000000,7479.38358700,1609772399999,237746821.62135450,116397,3581.67988600,113853118.14224021,0 -1609772400000,32113.68000000,32185.67000000,31550.00000000,31745.72000000,5321.62025100,1609775999999,169560823.38397644,99381,2505.70734700,79819154.00419214,0 -1609776000000,31745.71000000,31920.00000000,30723.00000000,31320.31000000,8174.28578300,1609779599999,255043539.07925110,133682,4187.51493100,130621147.14683560,0 -1609779600000,31320.30000000,31523.01000000,30626.36000000,31024.17000000,4962.56272900,1609783199999,153975400.83942578,96732,2613.69739000,81111771.17490149,0 -1609783200000,31022.25000000,31465.44000000,31001.00000000,31165.16000000,3361.43987000,1609786799999,104948080.87133230,73391,1896.89392700,59231323.65317481,0 -1609786800000,31165.16000000,31855.75000000,31104.99000000,31665.51000000,3388.37222100,1609790399999,106758748.38653801,71762,1753.38870200,55257387.68892296,0 -1609790400000,31665.52000000,31830.95000000,31210.00000000,31244.97000000,2850.96308700,1609793999999,89770988.08670449,64911,1329.17277400,41858872.75067731,0 -1609794000000,31244.97000000,31579.00000000,30856.08000000,31014.27000000,3202.45612700,1609797599999,99727509.60811839,74424,1548.02173100,48215339.25595822,0 -1609797600000,31014.27000000,31474.78000000,30950.00000000,31332.05000000,1646.48413800,1609801199999,51480692.96027581,54923,906.95705200,28362489.62653594,0 -1609801200000,31332.05000000,32031.01000000,31150.00000000,31988.71000000,4193.64872800,1609804799999,132893993.10060339,86041,2344.14079000,74303486.15285786,0 -1609804800000,31989.75000000,32853.38000000,31989.74000000,32430.49000000,7707.64341000,1609808399999,250007916.90775211,127581,4569.48199000,148144849.10568232,0 -1609808400000,32430.69000000,32796.00000000,32224.25000000,32786.06000000,4246.96065000,1609811999999,138118302.36451834,83071,2295.49344300,74675015.21841346,0 -1609812000000,32786.05000000,32828.26000000,32221.10000000,32306.64000000,3163.43004400,1609815599999,102893990.21816806,65391,1571.90279200,51120318.98503503,0 -1609815600000,32306.64000000,32536.09000000,31130.86000000,31200.00000000,5695.04449600,1609819199999,181350412.23885364,112880,2751.73680400,87713825.89386314,0 -1609819200000,31190.04000000,31538.45000000,30418.00000000,30858.98000000,7229.48636600,1609822799999,224769397.84667815,157600,3122.03990900,97170832.72847822,0 -1609822800000,30858.98000000,31366.16000000,29900.00000000,30436.25000000,6366.97612400,1609826399999,195158786.10553854,159593,2694.13433100,82666054.53886334,0 -1609826400000,30436.26000000,31270.43000000,29900.00000000,31123.25000000,6611.21073500,1609829999999,202286248.33256154,127994,3659.29882200,111844754.48935623,0 -1609830000000,31123.25000000,31312.03000000,30759.47000000,30817.77000000,2811.38395300,1609833599999,87206069.28127892,71734,1279.15583000,39679285.44614070,0 -1609833600000,30817.78000000,31522.19000000,30817.78000000,31192.09000000,3237.12095700,1609837199999,101016094.16648097,88984,1691.74721800,52801113.11961794,0 -1609837200000,31192.16000000,31821.94000000,31157.90000000,31569.63000000,3935.59797900,1609840799999,124016625.84180410,91763,2077.94349900,65482399.52003036,0 -1609840800000,31569.63000000,31687.11000000,31088.33000000,31345.77000000,3174.76039600,1609844399999,99666137.72028313,81295,1624.61121700,51008190.21588990,0 -1609844400000,31347.73000000,31777.00000000,31284.15000000,31776.66000000,2908.12176800,1609847999999,91671919.09848990,72492,1608.73697700,50727750.80430447,0 -1609848000000,31776.66000000,32057.13000000,31563.84000000,31585.01000000,4161.55133400,1609851599999,132493096.80311255,94633,2278.18509000,72558530.75037737,0 -1609851600000,31585.00000000,31900.00000000,31416.27000000,31460.01000000,2523.02316500,1609855199999,79971740.01184837,64040,1248.02063100,39565656.12394609,0 -1609855200000,31460.11000000,32375.07000000,31111.78000000,32342.33000000,5942.10285400,1609858799999,188316129.32606876,137989,3384.55523600,107337665.44604894,0 -1609858800000,32343.61000000,32374.31000000,31929.41000000,32099.98000000,3616.59901600,1609862399999,116161069.22208343,98120,1862.74385500,59830250.35901147,0 -1609862400000,32099.97000000,32670.00000000,31763.23000000,32469.90000000,4926.17161600,1609865999999,159348378.63575512,114817,2517.10906500,81421262.10859769,0 -1609866000000,32469.90000000,32790.00000000,32254.18000000,32742.73000000,3599.64571800,1609869599999,116970729.32707121,82231,1693.39973600,55049206.49118736,0 -1609869600000,32742.73000000,33433.55000000,32650.03000000,33372.84000000,6647.00992100,1609873199999,219940103.11654606,129769,3830.69609100,126730979.20382337,0 -1609873200000,33372.83000000,34187.09000000,33098.82000000,33697.75000000,8659.33850300,1609876799999,292047625.83670093,179774,4641.04381700,156580281.19993935,0 -1609876800000,33693.80000000,34044.13000000,33318.00000000,33969.17000000,5800.65390700,1609880399999,195673767.39849565,106875,2778.60271100,93787060.66580112,0 -1609880400000,33968.66000000,33996.03000000,33471.94000000,33699.63000000,3682.07415100,1609883999999,124381906.41438341,74894,1702.31561300,57517127.96443939,0 -1609884000000,33699.63000000,34360.00000000,33695.60000000,34183.42000000,4616.40333400,1609887599999,157718468.59895870,113239,2717.78634600,92848224.48505438,0 -1609887600000,34183.43000000,34284.91000000,33650.00000000,33949.53000000,4787.68664100,1609891199999,162432229.83348370,90092,2091.01373200,70934458.77764801,0 -1609891200000,33949.53000000,34107.59000000,33288.00000000,33918.01000000,6106.35192400,1609894799999,205743581.04425707,99660,2516.25996100,84812005.34531709,0 -1609894800000,33918.01000000,34018.93000000,33513.05000000,33811.28000000,3237.65935400,1609898399999,109289337.46651398,62378,1475.38110700,49802826.13141871,0 -1609898400000,33811.28000000,34135.84000000,33768.32000000,33873.30000000,3252.25455600,1609901999999,110509015.75623268,60510,1626.42308100,55274032.44717988,0 -1609902000000,33873.30000000,34170.00000000,33652.00000000,34117.59000000,3183.08804500,1609905599999,107858643.06601506,79479,1672.00819000,56692634.90742621,0 -1609905600000,34116.76000000,35766.58000000,34109.83000000,35325.91000000,12735.41762700,1609909199999,444922768.19202013,211886,7910.03825500,275960969.40718472,0 -1609909200000,35326.82000000,35590.00000000,34510.00000000,34978.91000000,5595.78367600,1609912799999,196115940.87795285,106461,2891.38405100,101402148.66539782,0 -1609912800000,34977.27000000,35229.10000000,34782.44000000,35125.51000000,3923.02640300,1609916399999,137467483.49545430,82118,2054.11388500,71979294.60308102,0 -1609916400000,35125.49000000,35248.63000000,34350.00000000,34676.40000000,3898.73728400,1609919999999,135685914.15764905,90102,1874.10273300,65256486.63670632,0 -1609920000000,34666.80000000,34950.77000000,34015.00000000,34594.28000000,5094.75919600,1609923599999,176018487.58908296,104746,2360.74276200,81573834.44700668,0 -1609923600000,34596.08000000,34607.69000000,33357.90000000,33919.50000000,5753.91297000,1609927199999,195480943.58159614,116923,2559.39339000,86977436.94551326,0 -1609927200000,33919.50000000,34550.00000000,33834.61000000,34417.36000000,3851.57425900,1609930799999,132191268.15797724,81692,1875.01912600,64352205.86680140,0 -1609930800000,34417.37000000,35200.00000000,34342.87000000,34918.53000000,6362.80414200,1609934399999,221652511.71656262,135283,3225.56840900,112395840.12698986,0 -1609934400000,34918.54000000,35088.00000000,34415.61000000,34929.87000000,4569.51466500,1609937999999,158781299.83276104,111089,2339.06150000,81279110.68771631,0 -1609938000000,34929.87000000,35050.00000000,34300.00000000,34550.00000000,4296.27233100,1609941599999,148666291.75269622,101607,2028.18287800,70209071.06286720,0 -1609941600000,34549.99000000,34593.50000000,34052.42000000,34213.46000000,5728.36809500,1609945199999,196539271.47079065,118986,2687.80804700,92234560.97504688,0 -1609945200000,34213.58000000,34790.00000000,34150.00000000,34566.19000000,4050.15684800,1609948799999,139949954.84675728,84656,1858.52932300,64217961.06072499,0 -1609948800000,34566.18000000,35076.42000000,34372.92000000,34612.41000000,6142.98629100,1609952399999,213765663.67000848,119999,2805.93946000,97707179.71105734,0 -1609952400000,34615.98000000,35057.81000000,34562.00000000,34898.52000000,3410.29344000,1609955999999,118876311.09590797,78917,1651.60960300,57594103.95804292,0 -1609956000000,34898.52000000,35245.00000000,34894.22000000,35215.75000000,3704.00848100,1609959599999,130045690.18758426,79341,1818.20697700,63842688.84232041,0 -1609959600000,35215.75000000,35695.00000000,34652.60000000,34816.72000000,5619.20776800,1609963199999,198986931.55874261,127198,2772.62367000,98244633.93981346,0 -1609963200000,34818.95000000,36250.00000000,34280.00000000,36015.88000000,10922.41272400,1609966799999,384838155.99124447,211465,5441.59735300,192130710.80364409,0 -1609966800000,36015.16000000,36470.00000000,35650.00000000,35874.16000000,7481.32434800,1609970399999,269663315.99895945,143699,3530.87547100,127294676.33943071,0 -1609970400000,35869.97000000,36379.99000000,35700.92000000,35989.63000000,2717.84739300,1609973999999,98138204.77164020,84495,1258.44650600,45453405.34245312,0 -1609974000000,35989.64000000,36939.21000000,35949.12000000,36769.36000000,5501.43949000,1609977599999,200767262.24120768,99093,2819.59891400,102944651.96840851,0 -1609977600000,36769.36000000,37287.63000000,36422.71000000,37150.66000000,6259.57897800,1609981199999,231127540.88700173,126956,3276.04372500,121035260.46323515,0 -1609981200000,37150.66000000,37227.61000000,36615.83000000,36871.47000000,4542.03973000,1609984799999,167744153.75912638,92343,2188.22221600,80834008.77942776,0 -1609984800000,36871.47000000,37087.01000000,36456.00000000,36962.37000000,4112.98100900,1609988399999,151378625.95657551,75846,1862.59406500,68560321.70436183,0 -1609988400000,36962.37000000,37699.00000000,36926.53000000,37454.48000000,4747.64690900,1609991999999,177380063.69681458,102236,2489.39129500,93000819.42241232,0 -1609992000000,37452.62000000,37550.00000000,37056.12000000,37450.95000000,4099.95384100,1609995599999,153032050.67556983,93723,1967.84767900,73462310.91837377,0 -1609995600000,37450.95000000,37700.80000000,37100.77000000,37347.20000000,4337.60029100,1609999199999,162305184.42616053,88626,2189.33091400,81931971.65715822,0 -1609999200000,37347.20000000,37439.75000000,36710.00000000,37130.84000000,4095.35114000,1610002799999,151906540.45678327,102410,1749.23592800,64883857.26010562,0 -1610002800000,37130.85000000,37338.72000000,36720.00000000,36859.85000000,3782.27688600,1610006399999,140083390.80394544,91008,1623.22536900,60156275.89779950,0 -1610006400000,36863.04000000,37350.00000000,36300.00000000,37217.55000000,5254.61020900,1610009999999,193767393.70327787,105341,2307.40234300,85144391.17514270,0 -1610010000000,37217.55000000,37500.99000000,36905.00000000,37492.69000000,4407.04559400,1610013599999,163843785.85139342,73931,2244.72536700,83506486.68795209,0 -1610013600000,37492.70000000,37500.00000000,36920.00000000,37045.45000000,3236.82271800,1610017199999,120314344.26502907,73246,1456.95604700,54166648.01214179,0 -1610017200000,37045.45000000,37913.72000000,37038.97000000,37822.09000000,4315.49039700,1610020799999,161597115.72571475,93785,2370.94087800,88851600.37871656,0 -1610020800000,37825.64000000,38200.00000000,37518.00000000,37941.36000000,6363.35906900,1610024399999,241319458.86435367,126651,3103.65779600,117756120.27681301,0 -1610024400000,37941.37000000,38429.00000000,37900.00000000,38161.60000000,5364.34606600,1610027999999,205106242.97582551,109894,2583.94624000,98802410.05574995,0 -1610028000000,38161.60000000,38644.76000000,38079.02000000,38453.97000000,5516.63370100,1610031599999,211915217.15929497,127201,2553.52547300,98119133.15050093,0 -1610031600000,38450.51000000,38970.42000000,38062.75000000,38970.42000000,5401.36264100,1610035199999,208049947.52961345,108411,2618.40335000,100917730.45469424,0 -1610035200000,38970.41000000,39500.00000000,38921.49000000,39120.01000000,8054.61611400,1610038799999,315624646.46786094,152513,4140.22882300,162292200.88514323,0 -1610038800000,39120.01000000,39775.00000000,39101.36000000,39732.92000000,4853.72990500,1610042399999,191791634.74751861,118869,2607.77573300,103049642.73116991,0 -1610042400000,39732.92000000,40365.00000000,36500.00000000,38948.48000000,16920.67287100,1610045999999,656141657.34246253,352801,8352.78240100,324987958.80568612,0 -1610046000000,38907.58000000,39236.12000000,37493.52000000,39062.00000000,9539.54129200,1610049599999,367676058.94426181,178227,4568.73751400,176185972.74372717,0 -1610049600000,39061.99000000,39199.33000000,38352.88000000,39109.38000000,4364.13361200,1610053199999,169359110.49023060,97943,2132.34871100,82796137.61577405,0 -1610053200000,39111.34000000,39882.07000000,38908.11000000,39687.11000000,4533.61478900,1610056799999,178905952.02809147,98626,2237.72931700,88336681.65941423,0 -1610056800000,39687.11000000,39969.00000000,39150.00000000,39665.92000000,2855.62721000,1610060399999,113198084.48035602,94586,1413.94892000,56075175.26137254,0 -1610060400000,39666.00000000,39680.54000000,38541.38000000,39432.28000000,5866.66546500,1610063999999,229001742.14610960,129513,3016.10703200,117730123.85962437,0 -1610064000000,39432.48000000,39699.87000000,38793.23000000,38793.23000000,3387.17488900,1610067599999,133184446.37639539,92545,1535.35775800,60395220.31993304,0 -1610067600000,38793.24000000,39000.00000000,37800.00000000,38681.37000000,5775.38926500,1610071199999,222320078.64383120,118187,2477.23985000,95426783.89717878,0 -1610071200000,38681.38000000,38692.83000000,36500.00000000,37181.74000000,9364.24713500,1610074799999,350671968.12783984,184588,4041.02930300,151433666.58874171,0 -1610074800000,37181.74000000,38460.13000000,37068.40000000,38347.10000000,5036.74691800,1610078399999,191531646.49060035,107958,2279.00721300,86658079.51130932,0 -1610078400000,38347.11000000,38949.97000000,38155.61000000,38668.92000000,5126.66640200,1610081999999,198141885.51559744,92378,2021.91847700,78103095.87348774,0 -1610082000000,38668.92000000,38700.00000000,37895.00000000,37975.25000000,4384.15874300,1610085599999,168179267.74228120,78020,2012.30775600,77208465.01634949,0 -1610085600000,37980.53000000,38685.13000000,37563.92000000,38537.94000000,3989.76181500,1610089199999,152681589.95116749,85138,2001.85591200,76637372.69438687,0 -1610089200000,38538.99000000,39143.80000000,38280.16000000,38930.55000000,4177.46546000,1610092799999,161995711.17798650,91584,2176.84316200,84394619.63586086,0 -1610092800000,38929.56000000,38985.06000000,38414.70000000,38648.95000000,3277.73807000,1610096399999,126726366.48661977,77560,1404.58769600,54299270.78439706,0 -1610096400000,38648.96000000,39374.22000000,38222.00000000,39358.34000000,3995.80383300,1610099999999,155055524.72934390,92046,2098.95693900,81516294.63929747,0 -1610100000000,39358.99000000,41057.79000000,39220.00000000,40721.45000000,10298.22132600,1610103599999,413988645.03214855,192411,5906.62682800,237456218.24972363,0 -1610103600000,40722.71000000,41500.45000000,40345.39000000,41286.67000000,9286.54999900,1610107199999,381339340.10874931,173240,4686.87248800,192530894.29991795,0 -1610107200000,41286.67000000,41785.90000000,40857.37000000,41316.91000000,7590.27892700,1610110799999,314289402.99398151,161233,3735.09226700,154675080.03643654,0 -1610110800000,41318.03000000,41641.83000000,40700.00000000,41311.18000000,5331.45266600,1610114399999,219726996.61805144,102736,2445.95779600,100799684.72757314,0 -1610114400000,41313.24000000,41564.72000000,40970.22000000,41454.13000000,3918.18065100,1610117999999,161743369.58990013,85972,1841.48903700,76024773.29519918,0 -1610118000000,41454.13000000,41950.00000000,39777.00000000,40829.08000000,12863.95161700,1610121599999,525866974.42447445,235224,6229.06949100,254988062.90513028,0 -1610121600000,40829.07000000,41600.00000000,40359.67000000,41303.42000000,6293.05875900,1610125199999,258570569.68834122,125823,3214.27634400,132138012.65968989,0 -1610125200000,41303.41000000,41556.19000000,40888.88000000,41009.07000000,3675.20465500,1610128799999,151525080.93204277,89742,1723.71079700,71085850.10289584,0 -1610128800000,41009.08000000,41153.00000000,39800.00000000,39920.39000000,6673.74778200,1610132399999,269890839.41926600,137300,3102.08551100,125500203.58850049,0 -1610132400000,39920.67000000,40700.00000000,39900.35000000,40365.09000000,3881.07246400,1610135999999,156704308.94925451,89817,1932.09680700,78005779.48646475,0 -1610136000000,40365.09000000,40500.00000000,38888.00000000,39059.15000000,9598.07354700,1610139599999,379934389.42082304,202984,4299.54077700,170262552.06710307,0 -1610139600000,39062.88000000,40116.37000000,38652.00000000,40075.82000000,6171.36420800,1610143199999,243712568.15469437,130312,3138.47475100,124040437.03498383,0 -1610143200000,40075.82000000,40785.00000000,39740.95000000,40674.45000000,3008.04856300,1610146799999,121290642.62703400,94417,1635.90693200,66006341.65049416,0 -1610146800000,40672.02000000,40937.77000000,40465.76000000,40582.81000000,2685.59980500,1610150399999,109371595.53094099,84417,1359.85132400,55388686.91384988,0 -1610150400000,40586.96000000,40976.13000000,39980.27000000,40283.56000000,4382.25498300,1610153999999,177655228.53915624,103817,2141.19214700,86818834.61634393,0 -1610154000000,40286.09000000,40321.92000000,39710.00000000,40198.56000000,4543.73605600,1610157599999,181652860.51564185,96651,2692.28448800,107572784.19722243,0 -1610157600000,40196.51000000,40561.97000000,39500.00000000,39973.00000000,3032.04654100,1610161199999,121509932.94021643,82121,1435.85659600,57585613.15612918,0 -1610161200000,39973.00000000,40376.69000000,39709.61000000,40211.59000000,1917.78678000,1610164799999,76876333.83329589,63739,1008.92029900,40451251.06765757,0 -1610164800000,40209.91000000,40490.00000000,39805.03000000,40206.44000000,1976.48437300,1610168399999,79389762.67386835,61321,1017.80459500,40890105.65787203,0 -1610168400000,40206.43000000,40206.43000000,39154.48000000,39295.37000000,3025.04162500,1610171999999,120011440.79497736,89565,1302.19304900,51661984.99372342,0 -1610172000000,39293.41000000,39627.11000000,38888.00000000,38984.86000000,4352.60593700,1610175599999,170621480.12389127,110337,2071.80838400,81239150.25345556,0 -1610175600000,38978.46000000,39692.00000000,38720.00000000,39638.61000000,3109.88920900,1610179199999,122140688.02104703,82441,1509.83574400,59314191.04526394,0 -1610179200000,39639.21000000,40254.42000000,39290.86000000,40172.14000000,3081.99328900,1610182799999,122880599.47300186,90034,1584.08594000,63156447.14670606,0 -1610182800000,40167.54000000,40790.00000000,40164.03000000,40348.35000000,3653.41544700,1610186399999,147912608.83417118,104095,1909.70882100,77317388.90252549,0 -1610186400000,40348.36000000,40800.00000000,40105.51000000,40376.03000000,3130.35655800,1610189999999,126596569.76688394,79151,1730.68526900,70010726.83355768,0 -1610190000000,40376.03000000,41237.44000000,40256.73000000,40565.77000000,4682.99124700,1610193599999,191114775.55476880,116488,2464.97070500,100614480.25360964,0 -1610193600000,40565.77000000,40912.48000000,40410.01000000,40874.99000000,2732.20120400,1610197199999,111129222.70939649,70238,1257.34703500,51151916.78860784,0 -1610197200000,40874.99000000,41222.00000000,40679.10000000,41051.65000000,3818.65745000,1610200799999,156480184.02975569,101156,2072.39056900,84932555.31609088,0 -1610200800000,41051.66000000,41380.00000000,40700.00000000,40819.01000000,3867.78119200,1610204399999,158901525.79577861,88998,1822.97645100,74917120.30373793,0 -1610204400000,40819.01000000,40953.00000000,40200.00000000,40525.15000000,3364.43316400,1610207999999,136453850.42727688,84201,1463.88630700,59385675.97324527,0 -1610208000000,40525.16000000,40649.96000000,39869.00000000,39995.10000000,3942.09517300,1610211599999,158583517.38012921,101902,1796.07266100,72296374.56676844,0 -1610211600000,39995.09000000,40586.87000000,39985.45000000,40421.40000000,2205.65303100,1610215199999,89095373.96045112,61685,1020.70532900,41227222.26393196,0 -1610215200000,40421.40000000,40800.00000000,40417.36000000,40650.01000000,2109.16468000,1610218799999,85758517.67667532,52834,981.61560500,39911873.45195525,0 -1610218800000,40650.00000000,40880.00000000,40469.40000000,40665.91000000,1864.14249300,1610222399999,75910582.21499661,55768,872.92464400,35551251.89398528,0 -1610222400000,40665.91000000,40781.69000000,40050.00000000,40606.22000000,3330.65176500,1610225999999,134668657.46555306,86204,1391.85841300,56271189.87607031,0 -1610226000000,40610.35000000,40755.00000000,40483.17000000,40718.80000000,2433.80943000,1610229599999,98937085.11211261,74533,1240.05516100,50413543.31466746,0 -1610229600000,40718.81000000,40743.47000000,40120.00000000,40281.09000000,1973.25228700,1610233199999,79649919.17291718,63216,838.83016500,33852664.82209105,0 -1610233200000,40283.73000000,40415.01000000,39928.91000000,40088.22000000,3255.53576100,1610236799999,130848312.14581371,77661,1379.31353200,55446358.85648048,0 -1610236800000,40088.22000000,40736.76000000,40087.15000000,40581.48000000,2697.15194400,1610240399999,109155020.52709842,75975,1543.34335800,62462569.75783142,0 -1610240400000,40581.48000000,41350.00000000,40450.05000000,41141.56000000,4299.15250200,1610243999999,176409335.99983746,113141,2465.14578900,101163164.33525845,0 -1610244000000,41141.55000000,41145.21000000,40814.04000000,40945.28000000,2353.85274600,1610247599999,96509933.21078183,56820,1229.29344600,50403266.36756701,0 -1610247600000,40942.75000000,40991.20000000,40250.00000000,40316.64000000,2477.28851200,1610251199999,100527756.90546729,68596,1059.09531200,42978114.80649500,0 -1610251200000,40320.67000000,40602.29000000,40050.00000000,40342.46000000,2786.99680900,1610254799999,112516572.97811659,70179,1322.10144800,53381207.04924366,0 -1610254800000,40342.46000000,40665.23000000,40260.00000000,40451.84000000,2044.47910700,1610258399999,82813349.32221709,65702,1046.79288200,42400439.71816490,0 -1610258400000,40451.74000000,41073.26000000,40350.00000000,40904.50000000,2194.91295100,1610261999999,89548994.99182704,68652,1216.59895900,49648322.96046531,0 -1610262000000,40904.50000000,41066.62000000,40660.88000000,40978.57000000,2143.46227300,1610265599999,87593443.12207167,63012,1095.48870200,44771683.38289097,0 -1610265600000,40978.57000000,41033.00000000,40555.00000000,40798.29000000,2415.93133500,1610269199999,98459402.84023767,82913,1139.52099300,46443938.63195148,0 -1610269200000,40798.30000000,41060.00000000,40732.00000000,40768.48000000,2642.95874700,1610272799999,108097086.74610234,71415,1009.83609300,41306154.06184283,0 -1610272800000,40768.30000000,40850.00000000,40000.00000000,40429.20000000,5145.08674100,1610276399999,208070825.51832275,124172,2023.15898700,81826579.79037870,0 -1610276400000,40429.19000000,40429.56000000,38888.00000000,39181.76000000,8619.31148000,1610279999999,340819805.54859064,168941,3503.14974300,138513763.62529143,0 -1610280000000,39175.09000000,39777.77000000,38450.00000000,39538.57000000,6929.93683900,1610283599999,272139723.43016981,139744,3065.68497500,120437034.47289807,0 -1610283600000,39538.56000000,40126.00000000,39426.59000000,39800.90000000,3799.31660300,1610287199999,151386269.92626396,83841,1768.26710900,70464133.46351778,0 -1610287200000,39800.89000000,39847.26000000,39247.54000000,39431.59000000,3199.91402300,1610290799999,126603785.26782930,77289,1532.49150500,60635642.53692478,0 -1610290800000,39431.58000000,39934.76000000,39062.91000000,39671.81000000,3219.50221900,1610294399999,127407920.98714545,80993,1611.08045900,63765375.53128484,0 -1610294400000,39671.82000000,39757.55000000,39186.16000000,39234.29000000,2904.11345600,1610297999999,114524017.31947872,74323,1433.07218700,56520726.45947023,0 -1610298000000,39232.76000000,39388.20000000,37200.00000000,38571.86000000,12879.62069600,1610301599999,492818910.76509772,227163,5725.16387600,219203034.08690946,0 -1610301600000,38571.95000000,38778.00000000,37675.30000000,38109.68000000,6090.67144700,1610305199999,232738420.47658579,130643,2884.15394500,110233573.65162313,0 -1610305200000,38106.11000000,38536.65000000,37111.00000000,37456.77000000,4232.50255500,1610308799999,160518393.07414801,108389,1964.25189700,74603321.71036708,0 -1610308800000,37472.40000000,37793.50000000,35111.11000000,37718.88000000,18938.32980400,1610312399999,696190674.07068193,326195,9012.74587700,331599928.90450612,0 -1610312400000,37727.29000000,38288.17000000,37525.22000000,38055.30000000,7661.05957300,1610315999999,290757651.27777476,151403,3699.12353900,140413639.82740624,0 -1610316000000,38052.58000000,39000.00000000,37852.09000000,38428.23000000,4739.66852100,1610319599999,183000874.59129449,117221,2172.01141000,83817517.42345978,0 -1610319600000,38429.85000000,38692.79000000,37935.92000000,38150.02000000,3794.32362000,1610323199999,145426560.60992947,81328,1929.77218200,73983764.27227870,0 -1610323200000,38150.02000000,38264.74000000,36501.00000000,37192.10000000,7568.89448700,1610326799999,282133773.45771687,144478,4049.03584600,150713738.61959097,0 -1610326800000,37192.10000000,37824.00000000,36700.09000000,37237.66000000,4215.99647000,1610330399999,157446432.61687462,94031,2195.03542900,81988122.38789822,0 -1610330400000,37237.67000000,37411.00000000,36123.45000000,36363.94000000,6796.57306400,1610333999999,249081305.98087372,139390,3348.44308500,122747565.18522181,0 -1610334000000,36363.93000000,36697.97000000,33600.00000000,35438.23000000,18753.36008200,1610337599999,656910210.24701858,309583,8535.65073900,299259801.78589244,0 -1610337600000,35438.23000000,35999.95000000,34300.00000000,35544.00000000,9555.24165800,1610341199999,336898762.01782967,189085,4654.26643700,164101044.72751303,0 -1610341200000,35542.92000000,35924.19000000,34500.18000000,34904.73000000,7098.49713400,1610344799999,250190079.36343610,144659,3446.91546700,121480349.82035492,0 -1610344800000,34904.73000000,34904.73000000,32550.00000000,32872.63000000,15763.14870700,1610348399999,531586560.33268066,250357,7453.84691700,251729352.83788592,0 -1610348400000,32843.26000000,34739.98000000,32538.00000000,34375.34000000,12674.17128100,1610351999999,427189376.16139185,229890,6321.17451400,213052770.46448799,0 -1610352000000,34372.25000000,35919.86000000,34249.00000000,35430.00000000,6432.36153600,1610355599999,228082153.68068114,128300,3153.09414200,111822658.95592866,0 -1610355600000,35430.00000000,35788.06000000,34800.00000000,35765.98000000,5625.53336200,1610359199999,198581030.52970092,118919,2941.98205400,103896685.62059100,0 -1610359200000,35765.98000000,36360.00000000,35238.01000000,35367.60000000,6245.55977000,1610362799999,223540104.68064499,130986,3054.14129000,109337398.84658899,0 -1610362800000,35368.81000000,35471.00000000,34020.00000000,34198.56000000,7167.26663200,1610366399999,249203003.73990949,139115,3464.14733200,120441070.62626393,0 -1610366400000,34198.55000000,35110.00000000,33308.01000000,34275.64000000,9904.29308300,1610369999999,339316781.85416521,182659,4717.64529300,161750148.94016634,0 -1610370000000,34273.49000000,34450.00000000,32700.00000000,32813.71000000,12794.35086900,1610373599999,428304476.95230326,203687,5855.69846000,196140187.73780490,0 -1610373600000,32808.92000000,33770.11000000,31115.00000000,33299.12000000,23220.78262900,1610377199999,754881732.25507185,328807,12031.06505200,391224660.24487161,0 -1610377200000,33291.56000000,33679.74000000,31415.90000000,31580.00000000,11202.31877200,1610380799999,363657258.00175475,193457,5400.29706900,175495481.43452390,0 -1610380800000,31582.82000000,32250.00000000,30420.00000000,31777.19000000,20017.08514800,1610384399999,622713357.15522214,315778,9679.56884000,301507822.46929914,0 -1610384400000,31771.77000000,33585.17000000,30701.80000000,32839.87000000,16685.08091700,1610387999999,540672713.18962742,267122,7894.19718000,255803459.28721463,0 -1610388000000,32848.96000000,33300.00000000,32432.32000000,32562.10000000,7184.91161600,1610391599999,236361243.57798098,136615,3790.43763800,124760825.98588440,0 -1610391600000,32562.10000000,32737.40000000,31215.00000000,32254.62000000,7289.18436100,1610395199999,233109852.78429258,153369,3655.36676900,116909537.40918899,0 -1610395200000,32254.63000000,33465.48000000,31408.07000000,33409.80000000,8540.91364700,1610398799999,275831078.34556703,164613,4449.32930400,144024400.07326120,0 -1610398800000,33410.75000000,34466.00000000,33076.05000000,33968.09000000,9804.01167300,1610402399999,332651007.11123541,182255,5079.33151000,172360408.62941284,0 -1610402400000,33962.22000000,34892.74000000,33650.00000000,34359.07000000,5403.70363100,1610405999999,185939943.89889369,134198,2760.00313000,95015878.35947188,0 -1610406000000,34361.16000000,35638.55000000,34361.16000000,35404.47000000,9188.29941400,1610409599999,322597532.80513758,150098,4202.73269300,147552912.49598393,0 -1610409600000,35410.37000000,35547.19000000,34287.34000000,34929.98000000,6612.03638100,1610413199999,230807172.42598563,130795,3379.43976300,117972743.51971113,0 -1610413200000,34929.99000000,35457.00000000,33880.00000000,34289.30000000,5087.44237000,1610416799999,176294252.52681766,109515,2522.24534700,87440367.82923286,0 -1610416800000,34289.30000000,34623.87000000,33677.03000000,34399.99000000,4906.32950600,1610420399999,167606696.70177525,95087,2405.92866700,82152277.26820580,0 -1610420400000,34400.00000000,34998.94000000,34182.24000000,34984.96000000,3550.25392100,1610423999999,123057319.46903642,97055,1765.56306700,61222462.04918094,0 -1610424000000,34984.95000000,35326.42000000,34520.69000000,35287.67000000,4020.85751400,1610427599999,140466119.04782501,102515,2176.63926500,76091017.67610453,0 -1610427600000,35284.05000000,35889.00000000,34971.24000000,35882.68000000,5053.27595400,1610431199999,179047386.94075864,98637,2496.53901800,88471391.55265655,0 -1610431200000,35882.68000000,36348.00000000,35720.43000000,35993.93000000,6584.65752400,1610434799999,237381577.99770093,119516,3174.63784200,114447012.13568810,0 -1610434800000,35998.56000000,36628.00000000,35617.67000000,36413.60000000,6162.13428600,1610438399999,222671027.01391058,112864,3206.00270000,115838913.54437513,0 -1610438400000,36413.60000000,36499.98000000,35587.86000000,35773.24000000,5138.33768500,1610441999999,184973179.98963707,101155,2455.05249800,88358289.26096258,0 -1610442000000,35773.23000000,36150.67000000,35370.21000000,35925.76000000,3783.31674300,1610445599999,135595914.73912248,94262,1896.01760800,67969346.30640587,0 -1610445600000,35925.76000000,36150.71000000,34757.00000000,35085.77000000,6437.92750600,1610449199999,226777326.93409420,143080,3053.71030100,107556709.23632782,0 -1610449200000,35085.76000000,35841.01000000,35084.92000000,35410.99000000,4770.00225200,1610452799999,169178056.75008352,86550,2337.22183900,82904323.55164113,0 -1610452800000,35410.99000000,35688.82000000,34850.00000000,35014.75000000,4399.50968300,1610456399999,155060827.99845856,80069,1928.30580100,67994050.23179785,0 -1610456400000,35012.96000000,35399.70000000,33250.00000000,33291.06000000,10038.22509500,1610459999999,343775108.96552814,161263,4514.77093600,154774045.22594566,0 -1610460000000,33286.00000000,34064.25000000,32531.00000000,33426.47000000,11811.35594900,1610463599999,393694368.81381614,189971,5804.71964800,193539539.39731593,0 -1610463600000,33416.47000000,34285.71000000,33406.88000000,33829.40000000,6681.45394200,1610467199999,226445698.58107617,125863,3258.14012000,110431128.74404150,0 -1610467200000,33829.40000000,35000.00000000,33819.11000000,34998.90000000,5939.78549300,1610470799999,205218579.80101925,116044,2942.49110800,101675429.08899601,0 -1610470800000,34998.91000000,35289.67000000,34560.00000000,35012.53000000,5686.97075900,1610474399999,198481126.85605437,109149,2734.77272400,95495054.88031603,0 -1610474400000,35012.54000000,35550.00000000,34810.01000000,35040.78000000,4048.61314400,1610477999999,142422688.30968393,88596,2127.23197400,74898353.32965495,0 -1610478000000,35040.78000000,35040.79000000,34178.89000000,34685.11000000,3815.68001400,1610481599999,132021423.41342590,83351,1861.99156600,64445308.78823963,0 -1610481600000,34686.10000000,34702.22000000,33730.00000000,34287.95000000,5034.97631600,1610485199999,171715989.97505660,113254,2277.29556100,77663317.90100258,0 -1610485200000,34287.95000000,34877.28000000,33801.04000000,34719.03000000,4053.70405600,1610488799999,139157664.78739752,89121,1897.86131800,65144801.32431527,0 -1610488800000,34721.74000000,35051.02000000,33297.82000000,33743.18000000,3949.37391100,1610492399999,134851382.60556787,100050,1822.63714600,62329465.03725843,0 -1610492400000,33751.70000000,34138.84000000,33260.74000000,34051.24000000,6381.93199200,1610495999999,214601532.84028451,126383,3059.09437900,102917130.95067533,0 -1610496000000,34049.15000000,34049.15000000,32380.00000000,32526.50000000,9275.27934900,1610499599999,306711545.32513445,148548,4062.09829300,134315161.76339754,0 -1610499600000,32526.93000000,33450.00000000,32487.11000000,33124.06000000,6231.71754500,1610503199999,205116100.18111848,110099,3245.50759000,106870415.03421619,0 -1610503200000,33125.30000000,33551.55000000,32566.55000000,33035.21000000,5457.27537100,1610506799999,180313046.83527591,97536,2660.94865200,87969611.41297568,0 -1610506800000,33035.21000000,34375.51000000,32981.94000000,33818.50000000,6460.71206000,1610510399999,218830650.55841690,113365,3444.20441300,116647769.52002588,0 -1610510400000,33818.50000000,33910.00000000,33090.90000000,33183.88000000,3956.30306000,1610513999999,132358668.93296781,81338,2044.29727600,68390711.57166143,0 -1610514000000,33183.89000000,33521.96000000,32800.00000000,33321.75000000,3402.31753600,1610517599999,112789336.11601216,74376,1742.74091500,57788989.11279821,0 -1610517600000,33321.76000000,34212.87000000,33212.12000000,33780.68000000,4919.32255800,1610521199999,166187643.75213094,117208,2638.06412400,89138990.87013726,0 -1610521200000,33780.68000000,35180.67000000,33550.00000000,34986.90000000,6468.36582000,1610524799999,223311028.86666966,129033,3682.46407200,127112455.09418704,0 -1610524800000,34986.90000000,35063.59000000,34438.95000000,34519.19000000,5729.47622900,1610528399999,198712825.27925155,99962,2902.05152600,100651428.88811770,0 -1610528400000,34517.44000000,35107.47000000,34200.00000000,34343.62000000,4738.54255100,1610531999999,164370205.87977076,95053,2503.29439500,86897985.27927657,0 -1610532000000,34343.62000000,35066.64000000,34343.61000000,34923.00000000,4760.85293600,1610535599999,165510800.23160082,108046,2591.48805700,90117223.52421103,0 -1610535600000,34922.99000000,35250.00000000,34242.15000000,34385.48000000,5982.91999400,1610539199999,207938425.33048149,112096,2984.81656300,103839195.82840833,0 -1610539200000,34385.48000000,34512.00000000,34017.00000000,34266.52000000,3585.06836000,1610542799999,122779592.03370346,83868,1721.11541800,58947535.15158035,0 -1610542800000,34266.52000000,34787.24000000,34070.00000000,34575.50000000,3664.90875200,1610546399999,126544042.17738252,77740,1857.50048000,64127856.67519648,0 -1610546400000,34575.51000000,35100.00000000,34216.00000000,34260.70000000,5193.52343100,1610549999999,180511640.73806480,101193,2764.63798900,96139650.51317405,0 -1610550000000,34260.70000000,34850.00000000,34200.00000000,34673.90000000,3658.84742300,1610553599999,126337617.72096771,82393,1653.19455400,57111468.36665218,0 -1610553600000,34673.90000000,34930.00000000,34388.53000000,34783.14000000,2872.01120200,1610557199999,99506730.47508033,74086,1492.52540200,51735243.12673614,0 -1610557200000,34784.98000000,35000.00000000,34652.06000000,34821.48000000,2913.41367000,1610560799999,101556217.35535974,74641,1562.72521500,54486870.61688355,0 -1610560800000,34821.47000000,35901.00000000,34720.00000000,35719.36000000,6649.55774600,1610564399999,235681753.55135671,129664,3974.73777700,140771658.26275286,0 -1610564400000,35719.36000000,36188.00000000,35577.55000000,36002.25000000,5312.21893200,1610567999999,190903832.62323042,102457,2853.20823600,102536581.41240300,0 -1610568000000,36002.24000000,36450.01000000,35704.21000000,36222.07000000,5750.01446700,1610571599999,207658780.19389705,118490,3022.63204300,109210392.15708915,0 -1610571600000,36222.07000000,37427.00000000,36110.76000000,37299.49000000,7450.10466700,1610575199999,273979677.45851544,143713,3862.68716900,141965447.48793870,0 -1610575200000,37291.25000000,37850.00000000,36827.02000000,37203.87000000,6042.03307500,1610578799999,225941892.14352165,145104,2879.92450300,107679972.00628686,0 -1610578800000,37204.09000000,37584.73000000,37000.00000000,37371.38000000,4003.12820400,1610582399999,149324552.65971510,94280,1834.17364400,68420077.69580588,0 -1610582400000,37371.38000000,38172.22000000,37362.49000000,37762.76000000,5781.27225700,1610585999999,218752928.62470529,125605,2990.57619500,113155634.76711500,0 -1610586000000,37766.00000000,37786.62000000,37363.00000000,37451.13000000,3460.03872900,1610589599999,129846558.68611705,84578,1731.43001300,64982225.08561570,0 -1610589600000,37451.13000000,37729.62000000,37071.00000000,37439.51000000,4089.94901900,1610593199999,153050647.78838738,83406,2120.29126200,79352023.77541426,0 -1610593200000,37440.92000000,37505.00000000,37000.00000000,37045.13000000,2807.21378600,1610596799999,104630428.04802116,64054,1319.37063400,49197290.74693892,0 -1610596800000,37045.13000000,37513.58000000,36701.23000000,37504.00000000,3609.73947500,1610600399999,134038926.53281073,73363,1770.23586100,65747717.75811828,0 -1610600400000,37503.99000000,37800.00000000,37299.74000000,37529.11000000,3154.22565500,1610603999999,118466413.78490620,62636,1474.51124200,55389761.43659308,0 -1610604000000,37529.11000000,38100.00000000,37440.00000000,37837.21000000,3705.58775500,1610607599999,140121272.27361156,73541,1841.11684300,69653555.86756475,0 -1610607600000,37837.20000000,38596.92000000,37703.09000000,38198.34000000,5294.80219500,1610611199999,202886480.62769958,107847,2818.31905800,108002404.41945095,0 -1610611200000,38199.52000000,38786.10000000,38192.64000000,38370.01000000,3936.80962600,1610614799999,151677554.87020534,96897,2022.19214400,77922384.37908971,0 -1610614800000,38370.01000000,38464.13000000,37862.04000000,37938.11000000,3551.70614100,1610618399999,135677932.49465849,97054,1679.06573300,64158794.71563468,0 -1610618400000,37938.10000000,38490.49000000,37869.10000000,38487.37000000,3151.65894600,1610621999999,120334877.85367399,85937,1605.13964500,61296323.15928239,0 -1610622000000,38488.05000000,38622.60000000,38060.00000000,38365.86000000,3014.52281600,1610625599999,115498616.33443130,86329,1512.26065700,57954319.17474923,0 -1610625600000,38365.86000000,38427.11000000,37707.00000000,38257.96000000,3638.08289000,1610629199999,138468218.58411391,89563,1592.52655200,60638938.46213643,0 -1610629200000,38257.97000000,39000.00000000,38154.22000000,38977.66000000,5153.84186400,1610632799999,199046530.26004405,118766,2859.33666200,110460004.16808241,0 -1610632800000,38977.98000000,39762.70000000,38788.19000000,39577.53000000,9975.28896800,1610636399999,393260886.42277017,179862,4184.23250200,164786587.25686127,0 -1610636400000,39577.53000000,40100.00000000,39294.70000000,39546.01000000,7213.09520000,1610639999999,286463361.38157997,135839,3777.11504600,150098074.26838017,0 -1610640000000,39546.01000000,40000.00000000,39212.15000000,39286.44000000,5390.89406700,1610643599999,213864590.33463079,115830,2560.81063900,101642939.91878299,0 -1610643600000,39286.43000000,39880.00000000,39286.43000000,39429.81000000,3239.68862200,1610647199999,128303822.32233566,79395,1640.29223400,64970027.83975713,0 -1610647200000,39429.25000000,39620.00000000,39258.10000000,39344.79000000,3097.20586700,1610650799999,122149519.36041288,66716,1705.22407800,67269828.70074482,0 -1610650800000,39344.80000000,39919.11000000,39329.93000000,39876.98000000,3010.85527000,1610654399999,119401522.13828646,68361,1724.85875200,68414756.74563145,0 -1610654400000,39876.97000000,39935.10000000,39312.85000000,39312.86000000,2418.31260500,1610657999999,95797316.08700725,59910,1195.95415800,47393130.01671483,0 -1610658000000,39321.64000000,39585.00000000,38259.25000000,38780.47000000,7841.12752300,1610661599999,303612063.22343891,161031,3857.61463900,149326645.90329549,0 -1610661600000,38782.41000000,39135.17000000,38276.00000000,38988.62000000,3319.71530700,1610665199999,128584606.95524369,95798,1817.75951300,70424340.95387201,0 -1610665200000,38988.61000000,39330.92000000,38733.11000000,39144.50000000,3094.75483800,1610668799999,120891563.15599693,85148,1464.23303000,57204883.53017351,0 -1610668800000,39145.21000000,39747.76000000,39023.24000000,39452.89000000,3774.33060800,1610672399999,149015360.55895156,80654,1813.91433200,71628902.11570069,0 -1610672400000,39452.89000000,39640.00000000,39012.12000000,39175.74000000,2907.10256900,1610675999999,114488133.33169310,67692,1465.81359400,57732152.69891964,0 -1610676000000,39175.73000000,39479.65000000,38800.00000000,39267.76000000,2742.79781200,1610679599999,107593579.36330459,68144,1391.22041700,54571404.28794153,0 -1610679600000,39267.76000000,39349.58000000,38450.00000000,38700.00000000,3549.50605300,1610683199999,137776261.03885600,88794,1751.76455000,67996021.76730338,0 -1610683200000,38700.00000000,38853.09000000,38355.00000000,38425.83000000,2792.04410000,1610686799999,107691922.39219169,64920,1284.01221400,49531729.05208940,0 -1610686800000,38425.82000000,38849.99000000,37808.00000000,37808.90000000,3634.09561100,1610690399999,139288945.37497918,79527,1573.36491600,60341434.86561976,0 -1610690400000,37808.90000000,38098.00000000,37554.94000000,38043.27000000,4123.49372400,1610693999999,156128218.16931174,84166,2003.82903100,75876919.06561176,0 -1610694000000,38044.94000000,38483.82000000,37704.80000000,38473.08000000,3768.17724300,1610697599999,144144283.55090610,91002,1778.55687600,68036440.23177903,0 -1610697600000,38473.07000000,38700.00000000,38153.17000000,38280.20000000,3113.97292700,1610701199999,119590741.84337465,83493,1599.63734500,61442495.48300634,0 -1610701200000,38280.20000000,38718.02000000,38016.17000000,38679.36000000,3356.49966500,1610704799999,128916245.16560998,98018,1767.69312400,67911754.92516476,0 -1610704800000,38677.24000000,38780.00000000,38314.20000000,38441.89000000,2224.43167300,1610708399999,85760838.32974271,79176,1080.72769400,41668853.45542037,0 -1610708400000,38441.89000000,38573.84000000,37923.00000000,38108.88000000,3028.51037900,1610711999999,115607110.50743184,74800,1339.04572500,51120391.63829057,0 -1610712000000,38108.87000000,38194.04000000,37200.00000000,37770.63000000,6046.11154300,1610715599999,227455772.13223086,121039,2849.48956500,107207023.74592949,0 -1610715600000,37770.64000000,37888.88000000,37251.11000000,37683.94000000,4557.68570200,1610719199999,171183584.21508546,102938,2314.71682000,86899329.57806010,0 -1610719200000,37683.93000000,37786.74000000,36641.00000000,36939.49000000,6587.75278600,1610722799999,244381841.17567055,134091,3104.66865700,115187209.27424001,0 -1610722800000,36940.11000000,36999.00000000,35258.00000000,35610.72000000,11637.87487200,1610726399999,421633941.40375609,213976,5856.79331600,212284608.84987149,0 -1610726400000,35610.79000000,36400.00000000,34408.00000000,36151.09000000,16406.90733300,1610729999999,582299642.59025403,286255,7784.64484600,276322903.50920047,0 -1610730000000,36149.47000000,36154.75000000,35350.00000000,35947.31000000,7410.88799700,1610733599999,265150289.62610624,129446,3868.83773800,138492449.66717974,0 -1610733600000,35947.31000000,36433.51000000,34812.23000000,35421.55000000,7136.05529900,1610737199999,254109822.19889123,140400,3353.46969300,119635002.34573689,0 -1610737200000,35421.56000000,35928.69000000,35080.05000000,35217.26000000,4051.58872200,1610740799999,144088610.88903680,96389,2125.58060000,75623155.37661455,0 -1610740800000,35218.94000000,35746.24000000,34801.15000000,35605.70000000,5526.41908500,1610744399999,194574672.96517021,129250,2745.10018600,96708743.86237256,0 -1610744400000,35605.70000000,36431.75000000,35554.13000000,36234.05000000,4285.70884300,1610747999999,154450136.60542600,95751,2264.09355000,81652223.93966391,0 -1610748000000,36233.76000000,36888.00000000,35950.63000000,36600.00000000,3398.85578300,1610751599999,124165898.57420053,86901,1504.96071200,54949284.35710958,0 -1610751600000,36600.00000000,36888.00000000,36401.22000000,36742.22000000,2240.11058700,1610755199999,82093046.67945539,63979,1116.09871900,40903378.66703621,0 -1610755200000,36737.43000000,37428.05000000,36724.17000000,37159.51000000,4169.14680200,1610758799999,155099149.94530764,92947,2105.12438500,78296806.17964554,0 -1610758800000,37159.51000000,37669.00000000,36902.38000000,37005.86000000,4102.25927500,1610762399999,152987555.23908431,86508,2132.30229300,79520839.77875500,0 -1610762400000,37003.76000000,37227.16000000,36000.00000000,36224.51000000,4298.86633900,1610765999999,157512107.31706416,91436,2079.76311600,76218717.77990697,0 -1610766000000,36224.51000000,36738.43000000,35852.93000000,36532.92000000,3426.00050300,1610769599999,124459038.14279918,72075,1759.16558900,63946717.95769295,0 -1610769600000,36532.92000000,36700.00000000,36127.16000000,36574.54000000,2089.28208500,1610773199999,76042648.71232054,51540,1015.36945000,36958454.75759945,0 -1610773200000,36575.37000000,36646.43000000,35520.00000000,35854.37000000,4007.38958500,1610776799999,143871289.02981140,81056,1591.05363700,57154848.42616431,0 -1610776800000,35854.37000000,36377.54000000,35823.80000000,36112.42000000,3043.31762400,1610780399999,109946261.51207760,66774,1574.06351500,56865537.86022015,0 -1610780400000,36110.57000000,36959.61000000,36076.50000000,36574.86000000,3648.98805300,1610783999999,133766788.43464680,83125,1879.86506800,68904117.01046308,0 -1610784000000,36565.74000000,37500.00000000,36375.88000000,37464.30000000,4175.61823900,1610787599999,154678945.75854647,97079,2339.74381000,86717137.69031956,0 -1610787600000,37462.57000000,37666.66000000,37200.00000000,37448.77000000,3311.73910400,1610791199999,123784828.41268273,79132,1713.31390300,64050800.71606176,0 -1610791200000,37448.78000000,37950.00000000,37300.00000000,37410.66000000,4139.97880700,1610794799999,155846935.36351839,96097,1954.08802200,73580342.23717523,0 -1610794800000,37410.67000000,37838.23000000,37179.41000000,37680.00000000,2918.80035000,1610798399999,109448933.45229068,98264,1554.10738400,58282228.87935096,0 -1610798400000,37680.00000000,37886.00000000,36712.00000000,37357.15000000,4677.64126900,1610801999999,174585140.14249301,104964,2235.80570100,83495700.38012370,0 -1610802000000,37357.15000000,37681.99000000,37058.76000000,37143.51000000,3239.40068800,1610805599999,121224096.96841568,85259,1607.28483500,60162129.37671651,0 -1610805600000,37148.15000000,37356.26000000,36671.20000000,37232.19000000,3525.25555700,1610809199999,130637025.55110464,90082,1698.17492600,62944541.75797344,0 -1610809200000,37232.19000000,37680.00000000,36983.05000000,37461.99000000,3462.80146500,1610812799999,129390956.24186780,102346,1880.20838500,70287335.60187390,0 -1610812800000,37463.46000000,37713.94000000,36921.00000000,37231.41000000,3881.93071000,1610816399999,144688348.29183051,109582,1909.52655000,71195606.41501134,0 -1610816400000,37231.42000000,37299.99000000,36800.00000000,36860.97000000,2512.10090800,1610819999999,92955189.33630733,70046,1212.63659400,44877028.64481656,0 -1610820000000,36859.24000000,37165.90000000,36400.00000000,36484.95000000,2411.27980900,1610823599999,88899219.78650335,69608,1127.24738100,41590115.37101633,0 -1610823600000,36484.95000000,36621.30000000,36200.00000000,36376.39000000,3971.87462300,1610827199999,144665412.75847924,88832,2175.88336600,79277640.73861669,0 -1610827200000,36376.39000000,36800.00000000,36235.60000000,36711.16000000,3324.72866000,1610830799999,121573306.03804704,68829,1890.82510200,69120690.03196189,0 -1610830800000,36713.85000000,36717.00000000,35684.82000000,35924.44000000,5744.88333200,1610834399999,207415636.40443184,105481,2039.08095600,73669691.29040968,0 -1610834400000,35910.07000000,36194.53000000,35357.80000000,36121.12000000,3505.76699300,1610837999999,125545020.17201992,93386,1543.87125900,55326157.74147853,0 -1610838000000,36127.20000000,36480.00000000,35900.00000000,35994.98000000,2759.38072800,1610841599999,99816503.13763424,81915,1401.91850900,50716935.38798084,0 -1610841600000,35994.98000000,36472.72000000,35520.00000000,36396.42000000,3726.44550600,1610845199999,134085309.53711128,103985,1957.46251600,70454005.51107439,0 -1610845200000,36396.42000000,36727.26000000,36176.66000000,36715.63000000,2847.94888400,1610848799999,103572557.59243320,67933,1650.65446400,60049202.69903055,0 -1610848800000,36715.63000000,36744.05000000,36235.00000000,36419.68000000,1927.69473800,1610852399999,70310805.17210125,61836,910.16210200,33193187.34334062,0 -1610852400000,36419.68000000,36541.88000000,35978.00000000,36177.00000000,2021.33177900,1610855999999,73300672.04992026,60538,954.06954200,34599084.80359322,0 -1610856000000,36177.00000000,36382.38000000,35822.62000000,35847.46000000,2093.28909600,1610859599999,75569739.26789349,53616,861.15334000,31093493.92495674,0 -1610859600000,35848.25000000,36009.42000000,35475.14000000,35547.13000000,2900.40794500,1610863199999,103507618.16636456,68297,1292.56868700,46142665.28656242,0 -1610863200000,35547.12000000,35733.23000000,35034.96000000,35390.80000000,4077.70544400,1610866799999,144053986.81128709,84419,1762.60951800,62293524.58439225,0 -1610866800000,35390.80000000,35530.00000000,34518.04000000,34760.90000000,5014.08248500,1610870399999,175408790.13568946,99290,2124.19679000,74357513.18585806,0 -1610870400000,34760.91000000,34834.41000000,34300.00000000,34732.83000000,5641.05021700,1610873999999,194956387.86675457,112432,2733.28975600,94489103.56729384,0 -1610874000000,34732.08000000,35188.00000000,34000.00000000,34176.77000000,5570.23129700,1610877599999,192698146.55056793,108778,2619.46937500,90658661.30071936,0 -1610877600000,34176.78000000,35147.84000000,33850.00000000,34818.00000000,5718.02904900,1610881199999,197387959.52060657,106160,3011.33603700,104059630.69026929,0 -1610881200000,34816.26000000,35400.00000000,34727.85000000,35267.17000000,3861.65969400,1610884799999,135399244.37169309,79936,1736.68097000,60903773.65504362,0 -1610884800000,35270.00000000,35545.34000000,34695.46000000,35124.69000000,3962.00267900,1610888399999,139632993.37884855,79678,1847.63214800,65131007.70656315,0 -1610888400000,35124.07000000,35500.00000000,34786.76000000,34841.83000000,2919.10106400,1610891999999,102737842.55470297,71419,1428.30617900,50278587.30064365,0 -1610892000000,34841.82000000,35243.64000000,34666.00000000,34750.02000000,2849.00196600,1610895599999,99574705.54992799,70822,1445.98812800,50544082.45977569,0 -1610895600000,34750.02000000,35973.89000000,34750.01000000,35728.47000000,4341.23544900,1610899199999,154518610.30102425,98607,2360.22110200,83998148.50677575,0 -1610899200000,35728.47000000,36166.47000000,35589.35000000,35910.07000000,3578.88895100,1610902799999,128512404.66708661,85740,1947.54828200,69937489.71982178,0 -1610902800000,35914.98000000,36123.14000000,35603.01000000,35837.22000000,2191.92330500,1610906399999,78599736.12711191,60258,1152.32208700,41321755.02532894,0 -1610906400000,35837.22000000,35920.63000000,35625.40000000,35678.67000000,1484.55684200,1610909999999,53084102.72106789,47902,806.41096800,28836727.69393613,0 -1610910000000,35676.58000000,36000.00000000,35514.99000000,35633.91000000,2043.03718600,1610913599999,73207372.57995978,57800,1072.67926100,38437112.60940556,0 -1610913600000,35633.90000000,36099.00000000,35559.84000000,36072.99000000,1917.72224700,1610917199999,68718611.05380223,54608,997.57090700,35751159.67099339,0 -1610917200000,36073.88000000,36852.50000000,36073.87000000,36542.96000000,3878.40282400,1610920799999,141647926.97089063,90548,2174.17282800,79388133.99001614,0 -1610920800000,36542.97000000,36700.00000000,36000.39000000,36181.16000000,2247.45304400,1610924399999,81931988.77622475,68903,1152.19484600,42011748.13054775,0 -1610924400000,36181.16000000,36417.51000000,35506.00000000,35828.61000000,3344.52569300,1610927999999,120685528.51759374,67137,1514.93872800,54718833.48528231,0 -1610928000000,35824.99000000,36016.70000000,35551.81000000,35964.20000000,3323.90113900,1610931599999,119159712.14498531,63319,1606.90513300,57614951.95602508,0 -1610931600000,35964.19000000,36180.00000000,35605.22000000,36125.44000000,2560.95556400,1610935199999,91877670.63162021,57197,1322.13209400,47415054.10178436,0 -1610935200000,36125.43000000,36208.00000000,35681.96000000,35764.66000000,2306.02756600,1610938799999,82867811.65103600,60994,1157.29079100,41596065.11737584,0 -1610938800000,35764.60000000,35847.18000000,34842.99000000,35106.25000000,4674.31695400,1610942399999,164878873.04280485,93982,1544.60107200,54470419.47523170,0 -1610942400000,35108.27000000,35313.90000000,34908.80000000,35132.11000000,1922.62447200,1610945999999,67496976.81593762,53315,871.84668300,30612537.81032757,0 -1610946000000,35132.11000000,35477.06000000,34800.00000000,35344.50000000,2494.06315100,1610949599999,87599615.70178966,57881,1148.89187000,40354532.34420341,0 -1610949600000,35344.50000000,35464.04000000,35072.69000000,35195.45000000,1597.76843600,1610953199999,56300358.51333952,45158,759.07017700,26751405.12726972,0 -1610953200000,35195.44000000,36278.68000000,35160.30000000,36104.61000000,3917.13156200,1610956799999,140822622.63867726,86613,1950.34315700,70090823.84607675,0 -1610956800000,36100.55000000,36450.00000000,36073.13000000,36233.19000000,2494.36415100,1610960399999,90400248.17710538,66340,1332.56138600,48287025.73379767,0 -1610960400000,36233.19000000,36650.00000000,36204.15000000,36574.61000000,3077.32729200,1610963999999,112164683.74681694,73640,1632.27271800,59494150.02425426,0 -1610964000000,36574.63000000,36633.50000000,36123.53000000,36216.63000000,2686.93417000,1610967599999,97510153.01232437,69740,1357.39864400,49264228.83971603,0 -1610967600000,36216.63000000,36537.00000000,35771.60000000,36442.08000000,3460.54194700,1610971199999,124848234.70607834,79307,1736.56814900,62641263.75389621,0 -1610971200000,36443.91000000,37469.83000000,36385.00000000,36981.40000000,8243.84424300,1610974799999,305775908.81808934,144888,4863.24389000,180322426.51417220,0 -1610974800000,36981.40000000,37050.00000000,36705.00000000,36766.78000000,4234.61810100,1610978399999,156297533.65120046,82229,2534.62857800,93612565.99943434,0 -1610978400000,36764.94000000,36985.00000000,36047.89000000,36449.71000000,3586.75998600,1610981999999,130920505.91913583,84095,1736.07612800,63349921.48594530,0 -1610982000000,36449.71000000,36600.78000000,36122.00000000,36405.98000000,2041.28462400,1610985599999,74258390.05881229,77583,980.46394600,35670262.49537307,0 -1610985600000,36405.99000000,36565.00000000,35831.88000000,36184.31000000,2789.03579100,1610989199999,100823529.48199534,91494,1375.94347200,49748332.70050728,0 -1610989200000,36184.31000000,36300.00000000,35400.00000000,35675.28000000,3638.79865400,1610992799999,129994205.62275856,91631,1696.62878400,60627024.14361091,0 -1610992800000,35675.29000000,35889.99000000,35532.32000000,35755.62000000,2134.48796900,1610996399999,76289046.58898849,68693,1035.27786600,37005168.86009770,0 -1610996400000,35755.62000000,36065.00000000,35695.70000000,35956.14000000,2040.50755300,1610999999999,73280693.30042997,57131,946.07607200,33978503.11621751,0 -1611000000000,35951.83000000,36400.00000000,35755.01000000,36102.79000000,2370.49412700,1611003599999,85609502.56222758,54395,1332.89774200,48150352.06874821,0 -1611003600000,36102.79000000,36296.90000000,35960.00000000,36198.01000000,1386.55487400,1611007199999,50126918.85569934,42491,664.89071200,24040239.99928700,0 -1611007200000,36198.01000000,36529.00000000,36154.65000000,36470.06000000,1403.43502700,1611010799999,51014701.39896737,46332,820.93816000,29849178.95171802,0 -1611010800000,36472.46000000,36777.77000000,36271.18000000,36631.27000000,2312.34139700,1611014399999,84525363.48357894,59318,1214.55882400,44400752.70145878,0 -1611014400000,36622.46000000,36916.66000000,36364.43000000,36676.89000000,2733.81033300,1611017999999,100190042.59582775,70989,1346.26085000,49334299.94502281,0 -1611018000000,36676.89000000,37280.00000000,36644.70000000,36922.44000000,6704.65912700,1611021599999,247774070.39497733,129108,3846.57205200,142188203.13944053,0 -1611021600000,36922.44000000,37014.19000000,36579.94000000,36804.11000000,3367.18661300,1611025199999,123941502.60160400,78744,1744.12188300,64193813.99868738,0 -1611025200000,36804.10000000,36846.06000000,36416.52000000,36465.30000000,2526.73244200,1611028799999,92552256.07429785,61311,1298.45559000,47563786.05688627,0 -1611028800000,36468.31000000,36648.92000000,36233.00000000,36284.71000000,2229.69432800,1611032399999,81295530.87574036,51230,1010.41437500,36848451.16460083,0 -1611032400000,36284.71000000,36538.46000000,36018.09000000,36251.18000000,2305.60782700,1611035999999,83784612.18185242,56140,934.13984000,33946658.77044831,0 -1611036000000,36249.37000000,36753.31000000,36002.01000000,36599.55000000,2938.25636700,1611039599999,107273641.64034685,64862,1415.02029200,51681856.65860550,0 -1611039600000,36599.55000000,37233.87000000,36470.62000000,37168.82000000,3825.66775700,1611043199999,140889599.49682016,92154,1964.40245700,72372674.30573714,0 -1611043200000,37167.92000000,37535.27000000,36897.07000000,37197.72000000,5687.62709000,1611046799999,211869865.95048485,107619,3034.97064100,113065745.48353333,0 -1611046800000,37197.71000000,37448.41000000,37000.08000000,37040.04000000,3275.36236000,1611050399999,122030475.06305307,71236,1724.20623400,64244428.73524604,0 -1611050400000,37040.05000000,37299.51000000,36750.00000000,37110.60000000,3322.07511800,1611053999999,123049352.32166823,69834,1328.51085100,49207075.68565862,0 -1611054000000,37110.60000000,37269.00000000,36811.83000000,37266.49000000,2885.73090900,1611057599999,106901741.58528574,77599,1402.45483700,51962298.25692514,0 -1611057600000,37263.73000000,37449.00000000,36610.00000000,36782.17000000,4108.41496600,1611061199999,152278198.14634400,92100,1730.49855000,64163858.18672526,0 -1611061200000,36782.16000000,37146.87000000,36782.16000000,37082.52000000,2645.54649100,1611064799999,97792760.65281740,67581,1324.55363700,48961142.08308718,0 -1611064800000,37082.52000000,37263.49000000,36913.62000000,36992.33000000,2406.25041700,1611068399999,89277069.58574515,64703,1069.51813800,39705332.19867843,0 -1611068400000,36992.32000000,37350.00000000,36776.50000000,37329.40000000,2806.43485300,1611071999999,104106538.97294504,66943,1404.23361500,52115774.51995613,0 -1611072000000,37329.40000000,37850.00000000,37203.97000000,37366.10000000,5147.02015600,1611075599999,193314306.96778085,126543,2869.30365200,107761235.79806878,0 -1611075600000,37366.09000000,37522.80000000,37015.00000000,37162.40000000,2476.82564300,1611079199999,92216774.40900947,78320,1214.50495400,45227795.62240386,0 -1611079200000,37162.40000000,37162.40000000,36500.00000000,36500.00000000,3818.66238300,1611082799999,140689545.76037489,118795,1692.17083000,62377256.77651533,0 -1611082800000,36500.00000000,36800.00000000,36052.04000000,36279.82000000,4162.25155900,1611086399999,151554221.32889008,114988,1957.58787000,71291448.04910801,0 -1611086400000,36281.66000000,36596.17000000,36100.00000000,36436.26000000,2878.69976000,1611089999999,104712135.13559804,79424,1352.60632600,49213231.43077645,0 -1611090000000,36436.26000000,36777.88000000,36381.91000000,36452.22000000,2721.21472400,1611093599999,99532432.86427794,71077,1212.26831800,44337485.23711049,0 -1611093600000,36452.22000000,36769.23000000,36325.63000000,36632.82000000,1252.40187500,1611097199999,45792766.57334137,51288,625.76904900,22887232.37383150,0 -1611097200000,36632.82000000,36722.71000000,35844.06000000,35891.49000000,3385.17467100,1611100799999,122529058.16513122,76783,1202.13677900,43584625.37491600,0 -1611100800000,35901.94000000,36350.00000000,35610.17000000,36314.04000000,3376.90801800,1611104399999,121611981.70825795,76065,1698.15315300,61156956.22671120,0 -1611104400000,36313.94000000,36415.31000000,36000.00000000,36105.27000000,2185.60381300,1611107999999,79107661.42393211,70193,1077.48775100,39004567.83224275,0 -1611108000000,36105.27000000,36125.86000000,35708.08000000,36080.90000000,2649.68717500,1611111599999,95147817.46514127,69392,1282.47330300,46066789.90461259,0 -1611111600000,36080.90000000,36100.00000000,35000.00000000,35062.49000000,5563.39287800,1611115199999,197187021.19787029,124477,2272.89640800,80605174.15458207,0 -1611115200000,35062.49000000,35440.00000000,34737.00000000,35251.36000000,4580.64004600,1611118799999,160879898.10346283,108135,2104.06392600,73956001.12289178,0 -1611118800000,35252.03000000,35500.01000000,35192.87000000,35477.18000000,2705.03601800,1611122399999,95634099.26116358,71627,1199.81019100,42430522.42932393,0 -1611122400000,35477.18000000,35909.95000000,35133.68000000,35262.93000000,3973.87904500,1611125999999,140868658.81284165,86408,1785.62381700,63336669.13924939,0 -1611126000000,35262.92000000,35884.79000000,35200.00000000,35677.14000000,2748.94867800,1611129599999,97892499.61234258,79497,1386.64800500,49379610.93213742,0 -1611129600000,35672.86000000,35939.12000000,35350.46000000,35475.45000000,2722.80538600,1611133199999,96980265.92600699,86204,1293.43909300,46069195.51314113,0 -1611133200000,35475.46000000,35566.80000000,34500.00000000,34801.83000000,5641.77378600,1611136799999,197316362.11893461,120493,2607.87075100,91216916.63868137,0 -1611136800000,34801.46000000,34979.59000000,34345.11000000,34721.51000000,5228.27214100,1611140399999,181383448.50979843,128848,2720.33736200,94408050.83412549,0 -1611140400000,34721.50000000,34867.99000000,34000.00000000,34426.17000000,5516.47424200,1611143999999,189555636.68479760,139619,2482.03951200,85314827.40123212,0 -1611144000000,34426.17000000,34797.73000000,34020.00000000,34717.66000000,4980.58747900,1611147599999,171988282.93936077,121366,2574.47427300,88944358.51221264,0 -1611147600000,34717.66000000,34983.77000000,34210.00000000,34958.56000000,3863.83288600,1611151199999,133781075.37984111,104474,1813.88878900,62833859.54875768,0 -1611151200000,34958.56000000,35142.18000000,34800.14000000,34873.96000000,3575.82907500,1611154799999,125026667.28062037,84043,1635.95581900,57189524.59525745,0 -1611154800000,34875.87000000,35049.96000000,34067.16000000,34192.17000000,3689.93592300,1611158399999,127624139.98722324,89817,1638.37368800,56695477.13228186,0 -1611158400000,34193.11000000,34733.00000000,33400.00000000,34693.65000000,9164.62629900,1611161999999,312303193.17566532,175841,4045.27824700,137920325.77367834,0 -1611162000000,34694.65000000,35100.01000000,34558.25000000,34849.99000000,3580.94135600,1611165599999,124627004.47361672,89168,1909.51171400,66478899.60394461,0 -1611165600000,34843.52000000,35266.72000000,34765.24000000,35250.61000000,2311.69306900,1611169199999,80828379.66206621,73056,1216.49186900,42547920.77330436,0 -1611169200000,35250.39000000,35311.00000000,34851.23000000,35197.12000000,2620.95376500,1611172799999,92029638.11022864,67359,1406.95759100,49407891.56166645,0 -1611172800000,35197.12000000,35318.39000000,34734.97000000,34957.15000000,1987.73025600,1611176399999,69621129.92197612,74431,955.36540500,33465910.76386969,0 -1611176400000,34957.15000000,35110.82000000,34482.75000000,34892.89000000,2130.64840700,1611179999999,74053301.33840012,61510,1075.47654700,37388219.82147555,0 -1611180000000,34892.90000000,35100.00000000,34748.09000000,34954.86000000,1119.62218200,1611183599999,39153067.93844396,47851,568.32500200,19877160.96407081,0 -1611183600000,34955.94000000,35670.00000000,34798.39000000,35468.23000000,3448.60099500,1611187199999,122119862.48878375,84665,1795.69186100,63595137.25701945,0 -1611187200000,35468.23000000,35600.00000000,35077.35000000,35293.21000000,2017.77200300,1611190799999,71244148.51224691,62415,1021.63117800,36087350.09733232,0 -1611190800000,35293.21000000,35384.20000000,34622.50000000,34784.69000000,2831.35322600,1611194399999,98887264.92537901,74678,1262.77622800,44091985.16186371,0 -1611194400000,34784.69000000,34831.42000000,34364.75000000,34560.12000000,3087.99981800,1611197999999,106807489.54912612,69030,1554.61918500,53775405.41995120,0 -1611198000000,34560.11000000,34821.60000000,34230.76000000,34571.09000000,3058.58303700,1611201599999,105595669.67910814,70428,1473.75077400,50892519.05477928,0 -1611201600000,34572.42000000,34923.07000000,34160.05000000,34246.48000000,3255.93055700,1611205199999,112476080.02982139,76518,1539.42868300,53190056.10502087,0 -1611205200000,34247.92000000,34619.66000000,33971.41000000,34562.70000000,3522.77822700,1611208799999,120817978.88212674,92193,1599.65898900,54904740.12478541,0 -1611208800000,34562.69000000,34805.16000000,34500.36000000,34661.83000000,2361.03375100,1611212399999,81807739.72141545,75006,1199.46049800,41562588.31422136,0 -1611212400000,34661.83000000,35019.01000000,34550.00000000,34624.27000000,2505.29344900,1611215999999,87147969.00878534,63295,1228.59391200,42741599.36104081,0 -1611216000000,34624.27000000,34681.73000000,33195.00000000,33239.00000000,7574.11231900,1611219599999,256464070.98831367,156722,3171.30735400,107516947.59598245,0 -1611219600000,33237.74000000,33500.00000000,32540.00000000,32878.33000000,10141.56880600,1611223199999,334459993.10114840,203209,4561.51833100,150456181.95340321,0 -1611223200000,32880.08000000,33067.87000000,32009.68000000,32826.62000000,7957.20654900,1611226799999,259185487.08244076,168066,3798.64234100,123773284.11724001,0 -1611226800000,32826.63000000,33000.00000000,32153.16000000,32208.62000000,6499.19839800,1611230399999,211753312.32663698,125838,3204.18771100,104419502.87409633,0 -1611230400000,32206.89000000,32693.16000000,31300.00000000,32475.34000000,10991.83004600,1611233999999,351602776.61161555,210145,4995.90744800,159923479.15384346,0 -1611234000000,32474.48000000,32784.31000000,32200.00000000,32304.44000000,4837.42355100,1611237599999,157188043.77176227,111987,2473.43810100,80383165.63062022,0 -1611237600000,32306.39000000,32450.00000000,31037.00000000,31180.19000000,10854.17362800,1611241199999,343341285.95402469,195527,5307.01795700,167967184.25189701,0 -1611241200000,31181.74000000,32047.40000000,31060.81000000,31384.09000000,7812.91775300,1611244799999,246568404.98001047,160355,3964.48055700,125218094.59949896,0 -1611244800000,31384.19000000,32210.38000000,31050.00000000,31083.50000000,7922.45751300,1611248399999,251118366.34818641,152038,3639.73915500,115545814.09881622,0 -1611248400000,31084.98000000,32006.43000000,31038.51000000,31912.38000000,4587.71659700,1611251999999,144988372.99906577,108210,2374.03657900,75112391.40357297,0 -1611252000000,31912.37000000,32101.00000000,31432.64000000,31742.68000000,3560.62585300,1611255599999,113025685.87936468,83931,1872.01061300,59456743.65825674,0 -1611255600000,31744.26000000,32751.24000000,31600.00000000,32468.66000000,5995.57574200,1611259199999,194294216.97572609,130883,2972.32121000,96300929.09307729,0 -1611259200000,32468.66000000,32550.00000000,31862.69000000,31883.01000000,4446.73367500,1611262799999,143406305.30422066,92561,1814.44124300,58508525.20428002,0 -1611262800000,31880.90000000,32131.52000000,31200.00000000,31229.71000000,4096.66507900,1611266399999,129806970.95052316,79250,1825.16546300,57897971.72882060,0 -1611266400000,31224.71000000,31249.02000000,30071.00000000,30913.18000000,9566.50417200,1611269999999,293192620.80555366,198964,3536.58837400,108389286.36409143,0 -1611270000000,30913.17000000,31571.88000000,30579.48000000,30850.13000000,5518.62290900,1611273599999,171603332.11762323,120256,2865.48856400,89124771.25270078,0 -1611273600000,30851.99000000,30863.98000000,29223.03000000,29528.31000000,16556.09618500,1611277199999,494734301.86225019,257851,7490.34896700,223742028.44830141,0 -1611277200000,29524.48000000,30436.26000000,28850.00000000,30068.29000000,17679.88047700,1611280799999,523137082.67972788,257625,8588.39663800,254114235.14214405,0 -1611280800000,30068.29000000,30849.98000000,29781.20000000,30710.91000000,8224.70597000,1611284399999,250104284.40121874,153325,4154.34427500,126324892.96417764,0 -1611284400000,30710.92000000,31029.79000000,30282.97000000,30943.40000000,4353.71025500,1611287999999,133375842.77548401,94621,2257.37116100,69178850.32926977,0 -1611288000000,30943.40000000,31414.00000000,30753.27000000,30919.60000000,5349.74113100,1611291599999,166190726.32666313,103652,2433.86826000,75616126.17399213,0 -1611291600000,30919.59000000,31924.44000000,30711.66000000,31800.93000000,5843.71142700,1611295199999,184028420.51132878,97216,2954.25431800,92987757.57327702,0 -1611295200000,31814.81000000,32152.90000000,31500.26000000,31542.75000000,5707.04325300,1611298799999,181417832.95727041,101619,2327.26440200,74020366.79427423,0 -1611298800000,31542.60000000,31878.20000000,30615.22000000,30842.45000000,5871.33017100,1611302399999,182994945.92512728,113549,2627.26092500,81919904.41999024,0 -1611302400000,30846.59000000,31636.99000000,30500.00000000,31526.30000000,5959.97399200,1611305999999,184580319.09360101,148350,3123.54124000,96718684.26877291,0 -1611306000000,31526.31000000,31799.98000000,31258.94000000,31414.59000000,5197.32705000,1611309599999,163847968.57535826,105289,2724.63723100,85916580.20164027,0 -1611309600000,31412.74000000,31766.01000000,31052.44000000,31386.37000000,4556.22050700,1611313199999,142759014.01477801,96070,2228.28144400,69812436.52517869,0 -1611313200000,31386.37000000,31997.00000000,31375.49000000,31710.88000000,6197.72471400,1611316799999,196955755.04950245,103543,3508.78822400,111526297.53345808,0 -1611316800000,31712.09000000,31995.00000000,31286.00000000,31550.00000000,5176.96354800,1611320399999,163881684.27671369,95270,2748.62371400,87060695.91900743,0 -1611320400000,31550.00000000,32322.56000000,31334.02000000,32141.80000000,6045.55706900,1611323999999,193650798.12282147,111611,2975.38234300,95276300.41957483,0 -1611324000000,32141.80000000,32537.67000000,32132.59000000,32516.74000000,5791.99130300,1611327599999,187566596.45637194,112187,2664.69415800,86304086.50129477,0 -1611327600000,32516.74000000,32767.44000000,32265.66000000,32458.42000000,4727.18649900,1611331199999,153659972.96999938,111537,2339.77124900,76061260.77114846,0 -1611331200000,32462.79000000,32626.00000000,31955.67000000,32377.56000000,4665.55497100,1611334799999,150975577.63273878,93129,2398.24543500,77595982.77464377,0 -1611334800000,32377.56000000,32500.00000000,32070.70000000,32329.25000000,2777.80265900,1611338399999,89671638.37049859,61647,1315.92704100,42485374.92433076,0 -1611338400000,32329.25000000,33322.00000000,32185.44000000,33277.32000000,5488.66573200,1611341999999,179938517.21390338,103780,3001.64580800,98517818.42696697,0 -1611342000000,33275.67000000,33655.79000000,33098.86000000,33589.52000000,4699.14183300,1611345599999,156981142.73572678,97136,2220.53795100,74185015.25059314,0 -1611345600000,33589.52000000,33826.53000000,33320.22000000,33503.20000000,3725.03294500,1611349199999,125120103.06772533,99864,1687.72335500,56695170.71714831,0 -1611349200000,33501.36000000,33668.88000000,33192.13000000,33290.01000000,2586.47012100,1611352799999,86484959.34566229,57890,1214.64288800,40615109.04973645,0 -1611352800000,33290.01000000,33606.16000000,32760.00000000,32835.29000000,2591.01826000,1611356399999,85932081.85096645,63029,1339.60618300,44407872.57019493,0 -1611356400000,32835.29000000,33173.01000000,32580.00000000,32945.17000000,3198.83397700,1611359999999,105306305.80683445,68020,1825.03124500,60078722.79955450,0 -1611360000000,32950.00000000,32974.89000000,32400.00000000,32702.18000000,3359.61255400,1611363599999,109495931.14066298,86521,1596.99420000,52048849.37696274,0 -1611363600000,32702.18000000,32935.08000000,32237.39000000,32706.76000000,3198.93051300,1611367199999,104362190.54273436,75853,1719.87681600,56131036.23762754,0 -1611367200000,32706.77000000,32860.00000000,32053.33000000,32256.17000000,3543.41263800,1611370799999,114730754.32306910,73178,2009.01377100,65064337.26398425,0 -1611370800000,32256.17000000,32612.00000000,32200.00000000,32365.01000000,2109.56632500,1611374399999,68388995.24540523,50704,1124.35221300,36451025.53268562,0 -1611374400000,32365.00000000,32810.00000000,32300.00000000,32582.01000000,2171.59810500,1611377999999,70886156.14103222,61611,1152.39069900,37617353.46885036,0 -1611378000000,32582.01000000,33378.52000000,32267.07000000,33350.60000000,3432.48724800,1611381599999,112750693.87171465,82778,1815.71824000,59676789.75466644,0 -1611381600000,33357.15000000,33456.00000000,32771.99000000,32820.11000000,3459.27026200,1611385199999,114696218.50447876,86917,1632.52496900,54146912.77462088,0 -1611385200000,32820.11000000,33150.00000000,32676.15000000,32931.18000000,2401.16107600,1611388799999,78955447.93697194,64338,1225.14128300,40289472.48523587,0 -1611388800000,32931.17000000,33000.00000000,32597.76000000,32943.24000000,2294.69006100,1611392399999,75242590.24286201,65598,1181.66516100,38742287.83489750,0 -1611392400000,32943.24000000,33104.94000000,32350.00000000,32453.56000000,3494.21218400,1611395999999,114281787.75036651,86858,1682.71062300,55063934.41630740,0 -1611396000000,32453.56000000,32532.37000000,32171.00000000,32344.37000000,2788.78403400,1611399599999,90158382.55879761,90131,1407.31815800,45503163.12264036,0 -1611399600000,32344.37000000,32542.37000000,31511.24000000,31645.49000000,4876.61961600,1611403199999,155421648.79950466,114476,2366.39363100,75389154.51463057,0 -1611403200000,31643.90000000,32001.28000000,31469.25000000,31602.63000000,2832.03585600,1611406799999,89995749.36806307,82125,1482.74167000,47137095.64828731,0 -1611406800000,31604.51000000,32289.25000000,31390.16000000,31865.19000000,3721.34108400,1611410399999,118464339.62025283,95038,2026.49855300,64515115.11558662,0 -1611410400000,31865.19000000,31980.00000000,31650.00000000,31721.74000000,2196.24159200,1611413999999,69824254.71730175,65547,1033.45308100,32862885.30435583,0 -1611414000000,31719.94000000,32180.00000000,31609.05000000,31877.10000000,2104.61671700,1611417599999,67298734.35128252,61911,1092.15660800,34924429.28608447,0 -1611417600000,31877.10000000,32328.03000000,31759.65000000,32121.84000000,2518.06613900,1611421199999,80752741.53370140,79587,1329.27819800,42644211.27737038,0 -1611421200000,32120.31000000,32409.97000000,32044.77000000,32239.09000000,2251.77458200,1611424799999,72497536.19198385,69594,1186.89480500,38215766.98575053,0 -1611424800000,32238.80000000,32345.00000000,31825.00000000,32167.48000000,2438.10419100,1611428399999,78273000.74346228,57407,1114.08513700,35766365.54075967,0 -1611428400000,32169.92000000,32500.00000000,32138.24000000,32348.79000000,2045.51433100,1611431999999,66125445.50675190,51425,995.62414300,32183374.17893218,0 -1611432000000,32348.78000000,32400.00000000,32021.73000000,32191.33000000,1524.95791900,1611435599999,49086641.98185392,44347,719.01656600,23142927.32853177,0 -1611435600000,32192.93000000,32442.68000000,31812.50000000,32344.22000000,2255.05685100,1611439199999,72529349.69565234,61725,1137.58245800,36600018.68789374,0 -1611439200000,32344.21000000,32538.61000000,31966.47000000,32049.97000000,1596.25194500,1611442799999,51491464.30404120,52393,819.23978100,26441108.79739147,0 -1611442800000,32050.03000000,32122.78000000,31835.85000000,32078.00000000,1980.98185200,1611446399999,63388240.68648952,39994,830.10536400,26556559.61817374,0 -1611446400000,32078.00000000,32086.75000000,31630.00000000,31876.35000000,2459.15967200,1611449999999,78349771.12170719,62163,1188.93801600,37879936.69394955,0 -1611450000000,31876.35000000,32084.91000000,31752.81000000,31863.84000000,1404.06207100,1611453599999,44865889.76254837,41407,709.94800200,22689764.91278492,0 -1611453600000,31860.76000000,32300.00000000,31784.66000000,32096.04000000,1774.93647700,1611457199999,56950530.36653801,47793,921.97673500,29583099.90476307,0 -1611457200000,32096.04000000,32480.06000000,32020.00000000,32480.05000000,2128.03865000,1611460799999,68576072.72203130,52268,1164.64489800,37534165.61903892,0 -1611460800000,32480.06000000,32879.99000000,32346.44000000,32811.05000000,4046.60390600,1611464399999,131610409.79547078,73491,1951.99568700,63495065.95413153,0 -1611464400000,32811.77000000,32980.00000000,32720.00000000,32871.98000000,2869.47383800,1611467999999,94248893.12860491,62763,1481.37316600,48658117.69260505,0 -1611468000000,32871.98000000,33071.00000000,32571.52000000,32757.02000000,2415.52054600,1611471599999,79159830.57866500,59405,1275.17520600,41805080.48814390,0 -1611471600000,32757.03000000,32853.09000000,32511.76000000,32801.15000000,1803.94623200,1611475199999,58917815.12901980,47116,899.89054700,29396258.90373397,0 -1611475200000,32797.21000000,33030.00000000,32570.00000000,32630.48000000,2135.76327500,1611478799999,69957475.67965592,52574,1023.22071400,33521420.25830454,0 -1611478800000,32630.48000000,32758.92000000,32541.32000000,32641.58000000,1910.53862500,1611482399999,62405154.10436933,67671,924.56146100,30198367.73958076,0 -1611482400000,32641.57000000,32724.66000000,32465.00000000,32693.74000000,1565.43584300,1611485999999,51027813.77741188,59213,803.08591700,26181675.30674694,0 -1611486000000,32693.73000000,32893.93000000,32693.73000000,32833.37000000,1989.11672800,1611489599999,65191162.98986752,53700,1103.38713400,36164528.22372911,0 -1611489600000,32833.37000000,32931.59000000,32128.15000000,32362.31000000,3068.96485000,1611493199999,99682557.97741842,73034,1319.80156100,42890256.31446244,0 -1611493200000,32362.32000000,32415.37000000,32107.61000000,32227.29000000,2663.86867100,1611496799999,86059202.76695536,73644,1230.45338200,39746471.34880807,0 -1611496800000,32227.30000000,32360.02000000,31929.31000000,32055.71000000,2195.43004700,1611500399999,70638742.72395953,64689,930.90311000,29955282.40894509,0 -1611500400000,32055.72000000,32259.81000000,31858.68000000,31957.05000000,2011.06256700,1611503999999,64500082.81172732,64579,988.13913800,31692082.66396833,0 -1611504000000,31956.90000000,32139.60000000,31500.00000000,31729.07000000,3614.85602400,1611507599999,114835132.79580004,100567,1691.20895300,53752991.40277353,0 -1611507600000,31729.07000000,31986.12000000,31635.42000000,31851.60000000,2263.53497500,1611511199999,72128516.19621104,62475,1010.82686900,32212591.53995736,0 -1611511200000,31851.59000000,31941.56000000,31766.81000000,31831.67000000,1377.99650000,1611514799999,43889526.64037461,40907,657.61149500,20947293.06741376,0 -1611514800000,31831.66000000,31841.47000000,30900.00000000,31306.29000000,5345.53359600,1611518399999,167203010.02797071,112536,2064.37769800,64574402.14883323,0 -1611518400000,31306.29000000,31757.17000000,31250.26000000,31673.26000000,2860.48241700,1611521999999,89998651.57598165,63740,1376.43030200,43326371.19291900,0 -1611522000000,31673.26000000,31977.60000000,31573.31000000,31909.46000000,1744.66586500,1611525599999,55383548.29101627,67110,861.58659600,27352293.07232051,0 -1611525600000,31909.46000000,32348.40000000,31650.00000000,32127.97000000,1991.43316400,1611529199999,63829956.46422534,67277,1078.18369300,34569390.58264187,0 -1611529200000,32127.97000000,32369.59000000,32015.46000000,32259.90000000,2337.61342700,1611532799999,75199917.93817138,58165,1168.39891700,37594214.57639895,0 -1611532800000,32259.45000000,32831.07000000,32175.61000000,32574.71000000,4492.34534200,1611536399999,146277748.43817087,97899,2452.47937700,79854637.15251205,0 -1611536400000,32575.15000000,32908.98000000,32411.77000000,32864.98000000,2900.14700100,1611539999999,94677652.83307504,68427,1496.45393800,48863779.58125962,0 -1611540000000,32864.97000000,32995.00000000,32636.36000000,32768.23000000,2347.98898000,1611543599999,76958546.93813420,56638,1110.53962800,36402424.42384716,0 -1611543600000,32768.23000000,33674.48000000,32580.30000000,33568.18000000,4706.03630500,1611547199999,156151422.42674605,94675,2679.83693300,88871512.80568639,0 -1611547200000,33568.17000000,33797.96000000,33261.00000000,33378.93000000,3754.09528000,1611550799999,125816591.56082466,82214,1816.50876100,60878211.28812918,0 -1611550800000,33378.06000000,33461.53000000,33188.00000000,33331.13000000,2126.57759900,1611554399999,70898446.60639003,51073,1021.87337700,34069625.73534733,0 -1611554400000,33331.13000000,33550.00000000,33150.00000000,33496.22000000,2557.38044100,1611557999999,85283083.54695842,56356,1300.50544100,43381088.39830938,0 -1611558000000,33496.22000000,33562.04000000,33045.00000000,33346.95000000,2786.69845900,1611561599999,92697097.45934045,63322,1424.03303800,47363349.33624157,0 -1611561600000,33347.19000000,33497.88000000,33188.99000000,33448.21000000,2566.70193600,1611565199999,85591925.94627989,63474,1340.55118400,44704047.41718278,0 -1611565200000,33449.72000000,33548.00000000,32800.00000000,32979.10000000,3423.01687200,1611568799999,113489933.49232923,76269,1606.34752200,53270937.84773043,0 -1611568800000,32979.10000000,33166.00000000,32750.09000000,33117.43000000,3417.07831700,1611572399999,112905085.79654864,85289,1955.61686600,64624341.75150900,0 -1611572400000,33119.35000000,33334.57000000,33040.00000000,33185.26000000,1981.51326800,1611575999999,65739353.93602941,66341,1070.32998700,35513475.22375523,0 -1611576000000,33185.25000000,34300.00000000,33050.00000000,34180.01000000,6294.12879000,1611579599999,212886323.99642283,141672,3832.05364200,129697877.57817209,0 -1611579600000,34180.01000000,34693.93000000,34098.59000000,34544.49000000,6947.92097900,1611583199999,239075222.77008129,149518,3681.46629400,126641878.79692544,0 -1611583200000,34544.50000000,34875.00000000,34280.45000000,34467.43000000,4653.60176100,1611586799999,161201191.93781374,121711,2300.94315700,79711508.64811906,0 -1611586800000,34467.43000000,34588.88000000,34202.69000000,34458.31000000,3214.09083500,1611590399999,110499278.35623155,99800,1683.60676500,57886514.36909641,0 -1611590400000,34458.31000000,34600.00000000,33630.57000000,33910.96000000,6140.45596500,1611593999999,208743836.36417970,137781,2930.49663700,99666505.65631162,0 -1611594000000,33910.95000000,34246.66000000,33700.75000000,33784.36000000,3303.04567900,1611597599999,112062093.92618265,88854,1668.43201000,56623803.28719433,0 -1611597600000,33784.35000000,34031.56000000,33519.00000000,33672.46000000,2950.05725800,1611601199999,99735147.24005105,73313,1351.67085300,45707149.29247083,0 -1611601200000,33669.27000000,33788.38000000,33373.92000000,33411.54000000,2213.52882300,1611604799999,74418069.81680985,54008,1000.65621600,33664318.87293048,0 -1611604800000,33411.54000000,33473.92000000,33061.12000000,33470.20000000,3271.37775200,1611608399999,108861348.10978255,72794,1446.31515700,48132100.20679488,0 -1611608400000,33463.51000000,33464.21000000,32155.28000000,32718.08000000,5912.51444300,1611611999999,193088110.56224740,133539,2399.19789400,78313733.17332801,0 -1611612000000,32715.53000000,32732.99000000,31910.00000000,32462.36000000,3761.90324400,1611615599999,121568650.71200311,99590,1579.13921000,51071639.66397406,0 -1611615600000,32462.38000000,32650.00000000,32201.44000000,32254.20000000,2777.02159200,1611619199999,90133125.79093578,71991,1340.47024500,43517573.98559408,0 -1611619200000,32254.19000000,32793.01000000,31758.00000000,32474.33000000,3799.04119800,1611622799999,122995112.44859934,96323,1871.01283900,60625563.53465943,0 -1611622800000,32474.34000000,32827.33000000,32210.01000000,32758.85000000,2324.03540100,1611626399999,75505666.00678688,74824,1149.22513300,37344328.29491923,0 -1611626400000,32754.20000000,32765.41000000,32230.29000000,32307.97000000,2168.25668200,1611629999999,70355766.42979308,49095,989.98170600,32116146.86170193,0 -1611630000000,32307.96000000,32363.93000000,31458.00000000,31518.66000000,4883.73309100,1611633599999,155459040.94181935,99933,2110.30635200,67182895.72751638,0 -1611633600000,31520.25000000,32181.90000000,31424.71000000,32000.01000000,3361.24679200,1611637199999,106920577.72781471,64042,1675.57158400,53297794.59542500,0 -1611637200000,32000.01000000,32312.46000000,31784.87000000,32062.32000000,2272.54862400,1611640799999,72801492.52926790,48016,1083.96112300,34730583.23470090,0 -1611640800000,32062.32000000,32073.99000000,31311.93000000,31581.73000000,4195.64010700,1611644399999,133031257.69910644,72693,2256.37416800,71536865.56268284,0 -1611644400000,31581.72000000,31782.08000000,31100.00000000,31643.61000000,6371.29734500,1611647999999,200257957.23826182,133721,3145.84801800,98940700.72222313,0 -1611648000000,31643.61000000,31981.99000000,31527.86000000,31896.97000000,2952.73564400,1611651599999,93778498.57264109,77599,1638.24476300,52032050.42180451,0 -1611651600000,31896.97000000,32075.00000000,31373.00000000,31804.77000000,3370.06145600,1611655199999,106741240.98747532,93953,1724.66652700,54634662.34633121,0 -1611655200000,31804.78000000,32450.00000000,31804.78000000,32246.68000000,4058.11986800,1611658799999,130588141.14958126,105841,2202.45517100,70869033.88374717,0 -1611658800000,32247.20000000,32249.98000000,31650.00000000,31796.95000000,2789.97458400,1611662399999,89144115.28256051,72409,1365.48711000,43633950.49891846,0 -1611662400000,31798.65000000,31972.73000000,31229.45000000,31296.94000000,3784.60423700,1611665999999,119599343.36135748,86449,1717.09552100,54279771.19734403,0 -1611666000000,31297.76000000,31920.00000000,31201.00000000,31718.97000000,3556.69465000,1611669599999,112183332.02280718,97781,1818.98332500,57378450.80679835,0 -1611669600000,31718.96000000,31780.60000000,30837.37000000,31257.73000000,6500.21259100,1611673199999,203008820.63261017,135499,2347.97559600,73403789.93890130,0 -1611673200000,31259.29000000,31885.02000000,31252.00000000,31750.23000000,3825.06075200,1611676799999,120817179.77570862,78114,1898.18083400,59957131.00159764,0 -1611676800000,31750.24000000,32122.81000000,31300.69000000,31985.30000000,6316.90126400,1611680399999,200793919.95069850,119851,3685.14131800,117244983.40339768,0 -1611680400000,31985.29000000,32235.00000000,31895.61000000,32184.36000000,2854.44547200,1611683999999,91533624.62957267,83847,1615.95169000,51825367.61913205,0 -1611684000000,32184.36000000,32350.00000000,31861.22000000,32224.50000000,2862.28621200,1611687599999,91942478.25470840,77588,1567.97705900,50373972.28764533,0 -1611687600000,32222.88000000,32403.88000000,32035.93000000,32208.33000000,2678.41918000,1611691199999,86275160.12000351,67942,1280.81507800,41259222.84870607,0 -1611691200000,32208.33000000,32395.00000000,31855.71000000,31986.99000000,2630.68342900,1611694799999,84511924.14518184,70669,1345.47349000,43242137.56002237,0 -1611694800000,31986.98000000,32322.23000000,31900.00000000,31987.13000000,1967.18320000,1611698399999,63164405.71139185,58423,951.14259600,30551043.82136939,0 -1611698400000,31987.13000000,32733.81000000,31890.00000000,32733.81000000,2170.30170200,1611701999999,70022546.23138569,62256,1324.19642800,42754895.13901649,0 -1611702000000,32733.81000000,32921.88000000,32454.84000000,32467.77000000,3278.72342900,1611705599999,107113762.64550759,83524,1636.24548800,53462757.55776008,0 -1611705600000,32464.01000000,32557.29000000,31880.00000000,32335.70000000,3512.77489000,1611709199999,113116385.94697308,72906,1770.25696200,57019173.60195106,0 -1611709200000,32335.71000000,32457.79000000,31955.39000000,32084.60000000,2849.98627400,1611712799999,91671544.50842356,60468,1275.84325000,41033343.45955774,0 -1611712800000,32084.88000000,32263.56000000,31758.92000000,31802.36000000,1970.04962100,1611716399999,63250143.61413279,49155,892.03947200,28649765.00274336,0 -1611716400000,31802.17000000,31916.66000000,31568.28000000,31800.86000000,2041.55994100,1611719999999,64850477.88120768,50328,1007.09673400,31996378.96584142,0 -1611720000000,31801.27000000,32030.28000000,31518.19000000,31864.36000000,1767.21326600,1611723599999,56091342.52528747,47510,887.97474700,28187968.04034165,0 -1611723600000,31866.97000000,31918.71000000,31365.41000000,31503.41000000,2446.34493400,1611727199999,77252810.79085218,78238,1264.00732300,39918906.61170516,0 -1611727200000,31503.42000000,31725.00000000,31350.00000000,31669.98000000,1968.81529500,1611730799999,62202611.41267428,51026,1036.75297700,32751332.23815783,0 -1611730800000,31669.98000000,31890.19000000,31547.41000000,31743.33000000,1912.29469700,1611734399999,60688595.08070834,45948,985.90966900,31293675.10798831,0 -1611734400000,31743.33000000,31749.28000000,31142.33000000,31172.11000000,3088.05994600,1611737999999,97052704.12030284,74442,1276.13919800,40127193.29886190,0 -1611738000000,31172.11000000,31290.00000000,30755.00000000,31201.05000000,5108.52499400,1611741599999,158617441.94178951,103350,2327.34152900,72306404.54268296,0 -1611741600000,31201.06000000,31400.00000000,31080.77000000,31376.90000000,2985.39232800,1611745199999,93325548.70631928,61071,1637.11901800,51184515.34493097,0 -1611745200000,31376.89000000,31615.38000000,30578.94000000,30639.05000000,4942.27402000,1611748799999,154059980.08608101,97493,2339.21186400,72987526.79243921,0 -1611748800000,30635.74000000,30888.00000000,30336.18000000,30759.03000000,5893.37674200,1611752399999,180578478.16806915,108428,2755.26121500,84451897.61136676,0 -1611752400000,30759.02000000,31057.00000000,30245.00000000,30275.30000000,4235.13187900,1611755999999,129745802.16209073,100889,2030.89102200,62247811.72995071,0 -1611756000000,30275.30000000,30520.00000000,29241.72000000,29573.15000000,9777.52588800,1611759599999,291793511.02371413,170979,4353.54803400,129922906.22249881,0 -1611759600000,29573.98000000,30464.93000000,29390.00000000,30322.61000000,6452.91178000,1611763199999,193367167.81476704,123867,3299.96288200,98903048.55543292,0 -1611763200000,30322.59000000,30948.00000000,30216.37000000,30529.57000000,5435.25258300,1611766799999,166467704.67978587,105703,2663.67509500,81597631.48247285,0 -1611766800000,30529.56000000,30845.81000000,30101.43000000,30514.34000000,4037.44367600,1611770399999,122955580.66566653,112339,2006.01672900,61100958.32188968,0 -1611770400000,30508.51000000,30537.50000000,29500.00000000,29709.79000000,4509.67311200,1611773999999,135093736.86313464,99460,2082.04083900,62372915.77181508,0 -1611774000000,29719.93000000,30850.00000000,29712.94000000,30740.33000000,5614.82069900,1611777599999,171246692.67050478,104151,2886.28168100,88037680.83821065,0 -1611777600000,30731.57000000,31556.00000000,30512.19000000,31520.20000000,5934.23090800,1611781199999,184980691.65305210,114222,3501.03725100,109130057.95780681,0 -1611781200000,31520.20000000,31649.99000000,30735.01000000,30958.00000000,3361.40379400,1611784799999,104772762.19722421,75496,1666.01137100,51942714.87607684,0 -1611784800000,30958.01000000,31051.46000000,30325.01000000,30519.93000000,2605.66407600,1611788399999,79921344.45363453,68057,1127.33609800,34605182.16323387,0 -1611788400000,30517.37000000,30727.14000000,30084.24000000,30366.15000000,3461.23636800,1611791999999,104978362.67516341,90427,1592.62667800,48310796.58255527,0 -1611792000000,30362.19000000,30728.57000000,29842.10000000,30671.86000000,3868.31654600,1611795599999,117054689.37539712,81664,1747.83946200,52915454.00577287,0 -1611795600000,30676.28000000,30917.53000000,30370.79000000,30881.94000000,2527.68074500,1611799199999,77365697.08750051,59183,1205.58418700,36914442.79162532,0 -1611799200000,30880.57000000,31214.51000000,30788.30000000,30981.72000000,3021.34740900,1611802799999,93728146.72616530,64100,1469.43157500,45591825.05542701,0 -1611802800000,30987.85000000,31526.78000000,30902.81000000,31404.25000000,4735.03456800,1611806399999,147776428.52334001,95757,2428.21758500,75832437.04657155,0 -1611806400000,31406.90000000,31590.00000000,31045.70000000,31300.73000000,2910.72013000,1611809999999,91045847.13369675,61002,1639.73028800,51299999.47010108,0 -1611810000000,31300.72000000,31800.00000000,31057.96000000,31729.16000000,3279.91959400,1611813599999,102985645.32916172,68625,1778.59539900,55867573.92583334,0 -1611813600000,31729.16000000,31876.63000000,31521.37000000,31564.58000000,3487.71079000,1611817199999,110633373.76520400,73535,1923.99057300,61032793.83926356,0 -1611817200000,31564.75000000,31597.76000000,31080.00000000,31170.53000000,2809.48377000,1611820799999,87885465.19554526,59569,1301.11485300,40706674.33640486,0 -1611820800000,31170.20000000,31303.15000000,31001.55000000,31070.47000000,2699.22237800,1611824399999,84068402.83496546,62325,1163.08740200,36231724.59398582,0 -1611824400000,31070.47000000,31483.44000000,30812.26000000,31466.91000000,3531.47764800,1611827999999,109938694.57514089,72682,1752.03560700,54557757.94370371,0 -1611828000000,31473.33000000,31585.39000000,31030.00000000,31490.29000000,3025.90313700,1611831599999,94762331.47706407,84078,1563.88615100,48984039.72156385,0 -1611831600000,31490.29000000,31600.00000000,31178.80000000,31437.37000000,2607.58697000,1611835199999,81896616.46288308,77818,1311.48633800,41193889.20267538,0 -1611835200000,31437.37000000,31713.43000000,31273.54000000,31477.95000000,3396.26217800,1611838799999,107019921.32660812,98129,1712.41802500,53958558.19706346,0 -1611838800000,31477.95000000,31840.00000000,31161.96000000,31775.12000000,3636.18646600,1611842399999,114583718.01587223,84674,1932.72159100,60900470.42713106,0 -1611842400000,31775.12000000,32150.00000000,31612.52000000,31830.53000000,5513.94787800,1611845999999,175852428.14608458,107453,2910.14176000,92837710.28595129,0 -1611846000000,31829.74000000,32203.38000000,31680.69000000,31926.49000000,5860.37828200,1611849599999,187319000.48965448,137637,2930.27020600,93676052.34067863,0 -1611849600000,31926.49000000,32436.58000000,31650.00000000,32425.71000000,5459.95176300,1611853199999,174979094.42632400,118755,2765.68610600,88676542.00008285,0 -1611853200000,32425.71000000,32490.00000000,32160.06000000,32281.49000000,3534.23954200,1611856799999,114139227.61665858,79831,1618.83931500,52281239.28715444,0 -1611856800000,32281.50000000,32670.00000000,32103.44000000,32633.68000000,3997.53631800,1611860399999,129390876.29705323,82800,2106.13135100,68179431.72715845,0 -1611860400000,32633.69000000,32747.78000000,32458.81000000,32564.71000000,3898.14149900,1611863999999,126986355.88489445,73041,1749.66309400,56998310.43247672,0 -1611864000000,32564.71000000,32900.00000000,32392.34000000,32577.96000000,3598.00013000,1611867599999,117534541.55066396,77268,1663.73508600,54357576.37967870,0 -1611867600000,32577.97000000,33295.55000000,32577.96000000,33183.53000000,4305.94392900,1611871199999,141857003.13632579,97440,2239.11979300,73774812.24859383,0 -1611871200000,33183.53000000,33488.66000000,33126.02000000,33469.67000000,3851.03859700,1611874799999,128353179.79633502,91267,1732.40747000,57737459.77379364,0 -1611874800000,33469.67000000,33783.98000000,33026.00000000,33364.86000000,7065.11535000,1611878399999,236396528.89314326,152027,3421.64910900,114449381.45237988,0 -1611878400000,33368.18000000,34310.00000000,33330.93000000,34150.23000000,10164.38794700,1611881999999,345112507.44377908,207142,5135.00011800,174298460.27402762,0 -1611882000000,34150.23000000,34304.52000000,33666.66000000,33906.57000000,5122.46825100,1611885599999,173979318.36195852,125764,2417.60149500,82095038.73639524,0 -1611885600000,33906.56000000,34201.14000000,33770.00000000,33969.20000000,4650.64856600,1611889199999,157806808.79234403,94579,2271.82590900,77102225.48866917,0 -1611889200000,33969.21000000,34114.95000000,33501.00000000,33733.58000000,6809.20237700,1611892799999,230537722.15599612,128676,3106.65151700,105194192.07641148,0 -1611892800000,33728.99000000,33934.48000000,32750.47000000,33062.82000000,8609.93510300,1611896399999,285624020.41362311,163110,3953.49072900,131091008.23035347,0 -1611896400000,33062.81000000,33193.57000000,32755.56000000,32980.32000000,5689.53301300,1611899999999,187802687.24984144,120363,2966.04463000,97909176.58797633,0 -1611900000000,32980.31000000,32982.33000000,32330.55000000,32483.74000000,7328.13660200,1611903599999,239141992.70319997,145868,3846.76354500,125570682.19706879,0 -1611903600000,32483.74000000,32626.98000000,31915.40000000,32266.35000000,6736.55427100,1611907199999,217124621.14715226,122552,3271.97864900,105463553.25990469,0 -1611907200000,32266.36000000,36600.00000000,32006.91000000,36240.24000000,19312.82747900,1611910799999,657349614.70597752,314310,11284.72753600,384612824.48788561,0 -1611910800000,36223.22000000,37990.00000000,34591.83000000,36877.16000000,32057.76917100,1611914399999,1170981431.47062844,554876,17431.61514800,636387876.26687176,0 -1611914400000,36875.50000000,37200.00000000,35489.41000000,36617.23000000,13351.73985200,1611917999999,485592406.11867599,264211,6468.65620000,235322265.94527225,0 -1611918000000,36617.23000000,37208.94000000,36421.93000000,37025.32000000,9995.03390400,1611921599999,368826783.70134898,182894,5084.05537200,187641109.49586396,0 -1611921600000,37023.83000000,37869.00000000,36534.42000000,37840.07000000,9895.61771500,1611925199999,367797382.70437782,205392,5196.60684500,193285505.17302355,0 -1611925200000,37842.07000000,38531.90000000,36979.32000000,38250.03000000,10190.52174200,1611928799999,384835263.32981755,206694,5557.87250300,210117231.77740116,0 -1611928800000,38250.01000000,38448.39000000,36456.78000000,37058.49000000,12376.77874500,1611932399999,463253682.69542364,223669,5751.44460100,215145357.36227601,0 -1611932400000,37058.49000000,37517.80000000,36700.00000000,37129.40000000,7119.86094900,1611935999999,264499608.70012400,150952,3343.45212100,124213712.30964436,0 -1611936000000,37129.40000000,37569.00000000,35808.00000000,36039.18000000,10309.64505600,1611939599999,380518661.93210766,181421,4906.66653900,181310643.96024192,0 -1611939600000,36038.73000000,36429.00000000,35564.00000000,35741.23000000,8064.31665900,1611943199999,290408716.86866321,178297,4104.19546100,147809776.45541420,0 -1611943200000,35741.23000000,35999.99000000,34600.00000000,35202.46000000,11212.39791800,1611946799999,394534372.45788041,166071,4992.43351100,175775312.10928092,0 -1611946800000,35204.22000000,35357.14000000,33500.00000000,34318.57000000,11414.90901700,1611950399999,391476682.66882703,190951,5427.95899000,186147612.09310751,0 -1611950400000,34322.50000000,34953.87000000,33843.22000000,34574.61000000,7664.13703300,1611953999999,264479532.26727039,145519,3509.15036700,121096451.76548034,0 -1611954000000,34574.61000000,34813.00000000,34120.00000000,34635.53000000,4701.56414300,1611957599999,162228512.71159393,102055,2226.10051000,76828681.43282444,0 -1611957600000,34628.68000000,35354.94000000,34250.00000000,34485.98000000,4078.62701900,1611961199999,142225092.01062971,120324,1862.82567900,64988703.44031910,0 -1611961200000,34485.98000000,34640.19000000,33700.00000000,34252.20000000,4970.39309400,1611964799999,169455913.61722583,107659,2420.12987200,82533632.71161126,0 -1611964800000,34246.28000000,34861.56000000,34214.91000000,34250.10000000,4446.39087000,1611968399999,153652340.31386364,108002,2364.30163800,81699824.25484977,0 -1611968400000,34250.10000000,34933.00000000,33927.00000000,34123.05000000,3869.44940000,1611971999999,133177861.93823476,91508,1985.97610600,68382971.95114120,0 -1611972000000,34123.06000000,34443.96000000,33674.70000000,33862.51000000,3988.19733700,1611975599999,135885410.39249829,85158,1972.40666300,67218238.12695476,0 -1611975600000,33861.55000000,34000.00000000,32825.00000000,33273.36000000,6807.71918700,1611979199999,226871612.32579531,131311,3133.19562100,104463104.11760685,0 -1611979200000,33273.36000000,33656.08000000,33001.52000000,33503.13000000,4185.93672300,1611982799999,139795812.00459418,89067,1937.42725100,64717170.69286870,0 -1611982800000,33503.14000000,33986.40000000,33174.55000000,33503.72000000,3638.46455700,1611986399999,122187543.51567719,99237,1855.85789100,62336044.68677898,0 -1611986400000,33503.72000000,33850.00000000,33137.80000000,33809.79000000,3684.99384300,1611989999999,123147576.69048441,108504,1828.75987900,61128398.26324755,0 -1611990000000,33809.79000000,34200.00000000,33400.00000000,34046.80000000,3867.91882500,1611993599999,130607799.65151298,107115,1995.22358400,67389101.16798405,0 -1611993600000,34046.82000000,34358.97000000,33775.44000000,33887.50000000,4900.02089400,1611997199999,167229239.26552966,89241,2351.89074300,80258089.04546266,0 -1611997200000,33883.85000000,34424.70000000,33809.39000000,34253.18000000,3386.81273500,1612000799999,115712942.60375289,79768,1685.20636400,57574926.30557272,0 -1612000800000,34253.17000000,34392.00000000,33870.95000000,34299.82000000,3971.80079200,1612004399999,135598002.40291819,97114,1900.18351600,64880317.76623992,0 -1612004400000,34299.82000000,34328.59000000,33510.00000000,33660.40000000,3646.87237900,1612007999999,123663790.64396261,87720,1728.40181800,58605167.08020547,0 -1612008000000,33660.40000000,33832.78000000,33410.63000000,33751.77000000,3003.42375300,1612011599999,101034454.78274613,78627,1589.95115000,53492405.44195036,0 -1612011600000,33751.77000000,34349.63000000,33666.67000000,34237.69000000,3019.37515900,1612015199999,102524279.83412895,80155,1641.17662500,55754425.62086473,0 -1612015200000,34237.69000000,34400.00000000,34000.00000000,34234.73000000,2997.76987400,1612018799999,102418819.17762771,91670,1599.60347400,54654070.77868259,0 -1612018800000,34234.73000000,34500.00000000,34057.22000000,34210.20000000,2959.94267800,1612022399999,101381388.78716153,83146,1570.31052800,53798757.52340426,0 -1612022400000,34210.18000000,34262.35000000,33520.00000000,33956.70000000,5589.95477700,1612025999999,189129789.50111192,162431,2668.91398100,90307049.67197864,0 -1612026000000,33956.70000000,34290.44000000,33943.00000000,34253.67000000,3332.80790500,1612029599999,113757762.40424967,115663,1737.18038300,59292355.51246802,0 -1612029600000,34252.02000000,34351.00000000,34110.12000000,34340.00000000,2258.74787800,1612033199999,77330554.26582136,70939,1185.85715800,40602779.26883419,0 -1612033200000,34340.00000000,34400.02000000,34028.87000000,34286.50000000,2047.94488100,1612036799999,70129136.65266194,63075,1027.61323600,35193610.38665192,0 -1612036800000,34286.50000000,34449.69000000,34080.00000000,34154.63000000,2018.49347200,1612040399999,69243326.64227957,62882,1013.15066700,34758584.21722212,0 -1612040400000,34157.50000000,34690.00000000,33966.40000000,34675.53000000,2087.95795500,1612043999999,71593702.94556996,62418,1155.23465400,39650016.31621405,0 -1612044000000,34675.53000000,34800.00000000,34516.78000000,34526.13000000,2094.79261100,1612047599999,72560499.44122176,82322,1041.79435600,36091461.55313465,0 -1612047600000,34525.88000000,34553.51000000,34164.78000000,34262.88000000,3083.89285500,1612051199999,105866416.75467381,73967,1448.84981300,49732530.90332009,0 -1612051200000,34262.89000000,34342.69000000,33850.00000000,34066.84000000,2644.82454900,1612054799999,90175038.25134254,78953,1255.21886900,42806497.69141891,0 -1612054800000,34066.84000000,34249.99000000,33940.00000000,34194.00000000,1867.10397600,1612058399999,63655356.52616395,55965,901.56706500,30735495.27642211,0 -1612058400000,34193.29000000,34238.00000000,33681.00000000,33750.00000000,2644.01293500,1612061999999,89553777.53771814,60467,1206.13579700,40854036.82787826,0 -1612062000000,33748.69000000,34042.00000000,33655.00000000,33930.21000000,1980.01672200,1612065599999,67158112.67791061,52167,1019.47386200,34583012.46039532,0 -1612065600000,33930.22000000,34127.65000000,33794.27000000,34034.31000000,1805.95175100,1612069199999,61338223.41763807,47859,901.53663300,30622644.98494255,0 -1612069200000,34034.30000000,34056.64000000,33678.46000000,33756.39000000,1919.90662400,1612072799999,64929411.25863169,63877,901.74071800,30495524.95514881,0 -1612072800000,33757.17000000,33857.88000000,33571.42000000,33655.86000000,1945.82559400,1612076399999,65600207.94435328,47790,930.32602000,31366164.26940287,0 -1612076400000,33655.85000000,33846.27000000,33450.00000000,33607.98000000,2065.00471500,1612079999999,69515828.35365876,52990,986.38347400,33218178.43936213,0 -1612080000000,33607.68000000,33832.94000000,33312.12000000,33596.72000000,2711.80689800,1612083599999,91112581.94067643,62435,1392.43016500,46799966.82858392,0 -1612083600000,33596.72000000,33769.93000000,33270.00000000,33301.70000000,2439.99427700,1612087199999,81773282.46528828,61860,1149.48063500,38531385.05985345,0 -1612087200000,33300.01000000,33744.88000000,33205.00000000,33653.68000000,2544.01392700,1612090799999,85311143.11480684,66211,1289.51975600,43255464.17454825,0 -1612090800000,33652.23000000,33784.40000000,33469.38000000,33563.23000000,1965.17830200,1612094399999,66078553.26019094,56862,996.18671100,33496992.17475449,0 -1612094400000,33563.24000000,34220.00000000,33366.29000000,33974.05000000,4152.45212000,1612097999999,140704742.42162135,89675,2244.35105400,76054246.78438007,0 -1612098000000,33974.05000000,34050.00000000,33607.95000000,33692.92000000,2291.02209100,1612101599999,77417451.86772917,67210,1058.56889400,35773756.47719697,0 -1612101600000,33691.49000000,33735.54000000,33318.02000000,33330.71000000,2924.24989400,1612105199999,98028927.06121184,71653,1316.14808200,44130251.32737339,0 -1612105200000,33330.72000000,33470.00000000,32554.00000000,32862.66000000,6617.93451100,1612108799999,218037468.51139443,133310,2887.50033900,95114203.83659416,0 -1612108800000,32862.65000000,33073.55000000,32555.00000000,32891.86000000,3707.19492000,1612112399999,121964680.76611902,82287,1714.22150800,56423575.18170762,0 -1612112400000,32891.86000000,33077.90000000,32200.00000000,32302.31000000,4790.61473300,1612115999999,156494910.95577298,101275,2143.45840500,70054838.61757502,0 -1612116000000,32302.32000000,32849.71000000,32171.67000000,32450.30000000,3929.77849000,1612119599999,127769211.17755456,95100,1914.82971200,62262815.18062214,0 -1612119600000,32449.53000000,32926.25000000,32400.27000000,32808.80000000,3396.97812500,1612123199999,111186671.44357629,79192,1617.39626500,52940950.71833745,0 -1612123200000,32807.29000000,32931.55000000,32461.23000000,32853.73000000,2968.31519700,1612126799999,97119658.90147466,72031,1330.33925900,43546588.71877033,0 -1612126800000,32853.73000000,32899.39000000,32515.00000000,32560.73000000,2336.55316500,1612130399999,76465178.41548618,79137,1108.39197200,36275448.49838342,0 -1612130400000,32561.35000000,33088.88000000,32559.85000000,32974.10000000,1874.80796500,1612133999999,61632662.65925331,60768,888.21922300,29205489.37903717,0 -1612134000000,32974.10000000,33255.49000000,32933.54000000,33092.98000000,3218.73890300,1612137599999,106617964.82843901,67990,1327.02294000,43955023.65788233,0 -1612137600000,33092.97000000,33106.33000000,32296.16000000,32546.27000000,4383.92612200,1612141199999,142737162.71050398,98763,2074.60006900,67502334.30717597,0 -1612141200000,32546.32000000,33560.90000000,32476.34000000,33430.29000000,3713.64949200,1612144799999,122901565.64866951,76863,1958.69177400,64820477.07485389,0 -1612144800000,33425.19000000,33830.00000000,33222.88000000,33649.73000000,3694.93162900,1612148399999,124101642.97642446,70196,2026.27061300,68048628.28106551,0 -1612148400000,33646.37000000,33776.81000000,33470.00000000,33573.97000000,2882.14179500,1612151999999,96898863.58231833,65467,1502.16471600,50506662.36382209,0 -1612152000000,33573.25000000,33943.55000000,33423.43000000,33558.25000000,3206.05432800,1612155599999,107985187.41969644,82376,1739.63260100,58612443.43947073,0 -1612155600000,33560.91000000,33888.33000000,33429.36000000,33755.40000000,2593.02037900,1612159199999,87162686.10827070,77102,1429.27879800,48049426.93847586,0 -1612159200000,33753.59000000,34427.00000000,33284.24000000,33518.89000000,6222.25895500,1612162799999,210377110.91915361,128607,3252.07960100,110039887.36561705,0 -1612162800000,33518.88000000,33885.39000000,33390.12000000,33803.97000000,3328.87882900,1612166399999,111983571.65304035,82926,1639.38870500,55169920.19953022,0 -1612166400000,33802.60000000,34500.00000000,33589.23000000,34477.31000000,5058.23727000,1612169999999,171793699.65688623,114044,2658.75611900,90308550.73893042,0 -1612170000000,34475.57000000,34717.27000000,34268.62000000,34354.47000000,5654.14105500,1612173599999,195106370.41513305,116712,2909.97244600,100421427.90252032,0 -1612173600000,34354.46000000,34539.94000000,34012.41000000,34163.28000000,4235.26065700,1612177199999,145043190.37158130,102798,2138.94071500,73268266.30953945,0 -1612177200000,34163.28000000,34400.00000000,33935.47000000,34183.33000000,4573.86889000,1612180799999,156247039.91294781,110371,2411.24058200,82367159.94215582,0 -1612180800000,34183.33000000,34460.00000000,33590.00000000,33770.23000000,5761.08894000,1612184399999,196167710.12255972,94637,2842.24857600,96774325.81179573,0 -1612184400000,33770.23000000,34050.00000000,33655.00000000,33702.25000000,4848.93435600,1612187999999,164142743.39168623,95479,2501.54189600,84685143.75421217,0 -1612188000000,33702.25000000,33866.49000000,33400.00000000,33532.81000000,4147.49669800,1612191599999,139437968.36318677,70535,1956.32836600,65799272.08513261,0 -1612191600000,33535.51000000,33638.99000000,33160.00000000,33160.17000000,2721.18660300,1612195199999,91002423.81062862,60911,1153.35365200,38584199.50053891,0 -1612195200000,33160.00000000,33603.91000000,33133.26000000,33460.83000000,2419.87278000,1612198799999,80761974.58769844,50309,1133.40766000,37826860.75130885,0 -1612198800000,33460.83000000,34100.00000000,33380.00000000,33978.31000000,3038.66868500,1612202399999,102352703.97211269,76303,1455.47781900,49063257.86370151,0 -1612202400000,33979.94000000,34032.93000000,33655.01000000,33731.52000000,1872.63065600,1612205999999,63366430.46922832,53060,843.16582300,28529194.50917199,0 -1612206000000,33739.52000000,34072.54000000,33700.30000000,33838.13000000,1802.34725300,1612209599999,61103749.87479555,40254,955.42222900,32392586.45573624,0 -1612209600000,33838.13000000,34039.00000000,33722.04000000,33831.55000000,1718.93123500,1612213199999,58254258.51752635,36267,986.74705500,33438414.96058199,0 -1612213200000,33831.54000000,33848.95000000,33549.00000000,33658.67000000,1451.01626700,1612216799999,48922604.53882721,32918,717.17428800,24184331.91016902,0 -1612216800000,33661.79000000,33789.73000000,33511.00000000,33539.39000000,1538.15262500,1612220399999,51750348.05666541,37352,647.50595400,21786987.24340813,0 -1612220400000,33542.12000000,33768.00000000,33430.76000000,33526.37000000,1851.58138300,1612223999999,62175650.92606452,36242,922.45142900,30979207.01918344,0 -1612224000000,33517.09000000,34161.39000000,33418.00000000,33763.07000000,3418.17893300,1612227599999,115729706.33114230,63969,1834.01032400,62119675.06646612,0 -1612227600000,33763.06000000,33800.96000000,33509.00000000,33744.71000000,1866.75345600,1612231199999,62792661.73073772,52952,881.33041000,29646228.26125995,0 -1612231200000,33742.99000000,33876.73000000,33555.49000000,33646.00000000,2079.71725000,1612234799999,70054606.83642168,56184,1032.14771700,34765415.66222445,0 -1612234800000,33646.00000000,33700.00000000,33501.25000000,33550.32000000,1739.29358600,1612238399999,58463810.05230950,46143,762.90747200,25643101.38073138,0 -1612238400000,33554.08000000,33963.29000000,33500.00000000,33876.37000000,2126.28743500,1612241999999,71835719.93835479,43360,1006.42534400,34007577.10022674,0 -1612242000000,33876.36000000,34100.00000000,33770.00000000,33992.83000000,2064.00040900,1612245599999,70038448.05485895,60017,1051.64973300,35695177.95958224,0 -1612245600000,33992.83000000,34321.61000000,33924.73000000,34295.01000000,3127.06324200,1612249199999,106640407.46283040,82974,1864.24443700,63593360.71907737,0 -1612249200000,34295.01000000,34400.00000000,34136.02000000,34223.38000000,3112.03491100,1612252799999,106630733.57998358,66027,1360.28784800,46612659.85584861,0 -1612252800000,34223.38000000,34683.63000000,34080.00000000,34663.87000000,4957.22423300,1612256399999,170397234.01661507,84147,2572.90613200,88458694.69105036,0 -1612256400000,34663.87000000,35668.10000000,34663.87000000,35334.04000000,8817.04469900,1612259999999,310915131.05624431,158364,4715.61287300,166220299.63782661,0 -1612260000000,35334.03000000,35434.70000000,34910.48000000,35160.24000000,3910.05383200,1612263599999,137638713.26559870,81936,1969.64299400,69336306.75180312,0 -1612263600000,35160.24000000,35284.49000000,34601.00000000,34720.15000000,4384.33598400,1612267199999,153356161.25391537,84105,2322.49346000,81237513.90743492,0 -1612267200000,34722.97000000,35000.00000000,34524.20000000,34779.91000000,2883.95498700,1612270799999,100377726.68791107,61033,1527.53948300,53167842.80168389,0 -1612270800000,34779.90000000,35200.00000000,34731.70000000,34844.73000000,3086.32433400,1612274399999,107830810.18705080,68712,1563.54779800,54629422.78110823,0 -1612274400000,34844.06000000,34932.50000000,34333.00000000,34793.99000000,3325.55569500,1612277999999,115350800.34527094,77765,1464.98036700,50826272.19172544,0 -1612278000000,34795.72000000,35151.00000000,34548.26000000,34708.47000000,3413.59949100,1612281599999,118797411.48827525,91425,1673.84486800,58273351.05906327,0 -1612281600000,34708.47000000,35175.31000000,34556.85000000,34964.52000000,4344.34360500,1612285199999,151529824.86205332,107598,2102.94280600,73357443.61602877,0 -1612285200000,34964.52000000,35021.85000000,34738.00000000,34851.47000000,2262.62325500,1612288799999,78878997.20662456,63282,1079.40325900,37634210.25001854,0 -1612288800000,34851.47000000,35308.23000000,34790.00000000,35264.21000000,2743.26236400,1612292399999,96146404.38965027,66654,1456.82234100,51080321.11312637,0 -1612292400000,35264.66000000,35800.00000000,35090.91000000,35762.03000000,4111.44241800,1612295999999,145781142.12603605,93057,2163.66700400,76735932.20940161,0 -1612296000000,35762.05000000,35984.33000000,35525.10000000,35786.51000000,4024.74000800,1612299599999,143903400.12762671,92961,2000.29360800,71524851.86595844,0 -1612299600000,35788.30000000,35896.49000000,35558.90000000,35653.07000000,2723.87766400,1612303199999,97346782.21912855,68418,1183.55344900,42304056.00682402,0 -1612303200000,35653.03000000,35812.49000000,35530.00000000,35572.36000000,1588.32591600,1612306799999,56638743.09164516,60824,723.20399600,25793701.52793158,0 -1612306800000,35576.49000000,35699.38000000,35466.00000000,35466.24000000,1946.62217300,1612310399999,69246520.00732346,57765,903.10538300,32127548.22049756,0 -1612310400000,35472.71000000,36240.00000000,35362.38000000,36135.01000000,4260.42510600,1612313999999,153185534.44129433,86243,2203.09281300,79227037.81705352,0 -1612314000000,36139.74000000,36349.64000000,35843.21000000,35879.27000000,3464.39918300,1612317599999,124916962.68756605,66965,1653.08112200,59598074.16722305,0 -1612317600000,35879.26000000,36125.93000000,35816.74000000,35889.37000000,2828.48526800,1612321199999,101621495.81154046,54021,1324.44941100,47583575.26033304,0 -1612321200000,35889.37000000,36500.00000000,35878.11000000,36403.47000000,3006.03753600,1612324799999,108745191.30919389,55259,1432.54751000,51837707.53058516,0 -1612324800000,36403.47000000,36845.00000000,36403.47000000,36628.85000000,4488.05451800,1612328399999,164545262.50417447,108221,2400.78299900,88008701.12544991,0 -1612328400000,36628.86000000,36690.14000000,36377.10000000,36460.12000000,2188.76658000,1612331999999,79870230.17375060,62274,1139.80547900,41586730.04582903,0 -1612332000000,36462.63000000,36789.00000000,36435.96000000,36535.90000000,2417.77068400,1612335599999,88535810.28662406,55099,1346.49868100,49309644.81198082,0 -1612335600000,36533.94000000,36590.08000000,36231.66000000,36297.57000000,2827.28406700,1612339199999,102996893.41242375,53205,1277.00218500,46524149.46095999,0 -1612339200000,36297.58000000,36299.98000000,35640.93000000,36010.09000000,4414.92098600,1612342799999,158931388.68529092,82881,2039.10271600,73397144.18563155,0 -1612342800000,36011.01000000,36036.00000000,35511.00000000,35851.19000000,3634.75184200,1612346399999,130021296.18955165,72725,1963.61532100,70243609.17911803,0 -1612346400000,35851.19000000,36040.00000000,35657.69000000,35985.27000000,2271.00839000,1612349999999,81400262.48087777,54106,1250.01216100,44809168.90517665,0 -1612350000000,35985.27000000,36238.38000000,35855.31000000,35969.41000000,2702.52792900,1612353599999,97455671.35949739,62958,1234.33109500,44512176.33707880,0 -1612353600000,35969.41000000,36322.96000000,35810.90000000,36178.86000000,2932.29172400,1612357199999,105997784.07411489,75668,1462.93130700,52880945.50975140,0 -1612357200000,36179.62000000,36720.56000000,35944.51000000,36537.42000000,4542.42642200,1612360799999,165607888.09043088,108797,2106.04437400,76774909.81866128,0 -1612360800000,36537.42000000,36760.53000000,36369.56000000,36548.60000000,3658.66180400,1612364399999,133734783.41610500,82802,1652.42268100,60404716.13487960,0 -1612364400000,36548.59000000,36917.27000000,36540.79000000,36850.00000000,4080.22547600,1612367999999,149926004.80378024,89781,2038.01231000,74886177.18525864,0 -1612368000000,36850.00000000,37221.42000000,36643.07000000,37146.67000000,5690.30451000,1612371599999,210149745.28047698,128478,3114.07008200,115033725.72814644,0 -1612371600000,37146.67000000,37179.69000000,36929.00000000,37176.86000000,3489.54181000,1612375199999,129297550.90680523,87386,1753.00959900,64945347.84804888,0 -1612375200000,37176.87000000,37200.00000000,36688.00000000,37114.14000000,3606.78845700,1612378799999,133452803.73988869,94525,1785.80943800,66092068.23989953,0 -1612378800000,37116.47000000,37136.00000000,36788.88000000,36788.89000000,2430.82486900,1612382399999,89721003.60116466,72957,1101.98836900,40677504.75242853,0 -1612382400000,36788.89000000,37075.70000000,36644.44000000,37039.88000000,2729.99998500,1612385999999,100654510.98253434,77912,1303.46058400,48066791.14988422,0 -1612386000000,37039.88000000,37420.51000000,36965.52000000,37256.97000000,3713.74998200,1612389599999,138078449.71433311,94908,1780.08801500,66197164.04526289,0 -1612389600000,37256.97000000,37509.74000000,37232.72000000,37276.31000000,2590.42054700,1612393199999,96836739.62843673,77051,1138.23533000,42549937.54073131,0 -1612393200000,37276.30000000,37662.63000000,37267.02000000,37618.87000000,2814.66598800,1612396799999,105549524.60444919,77518,1362.68147800,51101039.36254488,0 -1612396800000,37620.26000000,38128.00000000,37615.93000000,38063.15000000,4961.19259900,1612400399999,187977973.17526249,117944,3061.91068900,116029439.75396000,0 -1612400400000,38065.00000000,38288.00000000,37861.83000000,38147.35000000,4294.87765600,1612403999999,163643128.68714705,92293,2203.02853500,83962739.55237745,0 -1612404000000,38147.36000000,38215.40000000,37505.51000000,37896.36000000,3775.56313000,1612407599999,142792275.77206093,81556,1829.97626400,69199475.74376775,0 -1612407600000,37896.36000000,38015.50000000,37363.17000000,37498.78000000,3017.09742300,1612411199999,113590846.05870777,64132,1354.76592900,51021670.96465612,0 -1612411200000,37498.78000000,37788.76000000,37326.83000000,37678.39000000,2283.22218800,1612414799999,85875459.99277110,66721,1012.22829600,38070204.87406065,0 -1612414800000,37678.40000000,37924.35000000,37479.03000000,37578.23000000,2687.63416100,1612418399999,101354654.40364460,55759,1199.57788700,45251175.88198284,0 -1612418400000,37577.31000000,38195.00000000,37530.95000000,38076.43000000,3405.71067700,1612421999999,129186885.66333964,89003,1797.58701100,68202617.61705715,0 -1612422000000,38076.43000000,38175.69000000,37800.00000000,37843.40000000,3290.32831400,1612425599999,124899917.36988243,81512,1709.94375700,64917523.56638815,0 -1612425600000,37843.40000000,38708.27000000,37015.00000000,37338.19000000,9587.95413600,1612429199999,366242945.92388063,191071,5060.19562000,193523169.32141441,0 -1612429200000,37339.11000000,37604.07000000,36662.45000000,37509.22000000,7567.33806800,1612432799999,281563628.35227136,185306,3731.19218000,138879883.45744725,0 -1612432800000,37509.22000000,37772.43000000,37206.20000000,37611.63000000,3331.24284900,1612436399999,124958513.58251474,84501,1660.32241100,62288639.09505894,0 -1612436400000,37612.90000000,37922.78000000,37306.12000000,37321.75000000,3250.63072000,1612439999999,122447003.14992986,82299,1575.70367600,59379233.80206839,0 -1612440000000,37319.43000000,37763.57000000,37021.80000000,37618.69000000,3402.20962400,1612443599999,127500327.07817100,85938,1639.67822300,61461903.60544999,0 -1612443600000,37618.68000000,37690.00000000,37268.03000000,37587.58000000,2729.71393000,1612447199999,102291632.65196248,75618,1178.04694100,44158825.48738725,0 -1612447200000,37587.58000000,37705.00000000,36626.86000000,36795.15000000,4883.79355700,1612450799999,181710552.43222282,107485,2150.47386200,80066225.29988460,0 -1612450800000,36795.15000000,36965.34000000,36161.95000000,36564.23000000,5975.27268200,1612454399999,218390088.61388537,126393,3210.41416400,117331751.49171108,0 -1612454400000,36564.23000000,36989.99000000,36399.79000000,36929.36000000,3826.18916300,1612457999999,140423708.51856383,86263,1929.22354400,70810966.36637297,0 -1612458000000,36929.53000000,37070.00000000,36780.00000000,36884.34000000,3095.31990500,1612461599999,114258715.03809118,87277,1340.55860200,49492340.65480582,0 -1612461600000,36884.34000000,37422.37000000,36761.89000000,37141.96000000,2972.45142600,1612465199999,110379893.67350746,80261,1528.26404400,56771212.21425576,0 -1612465200000,37143.44000000,37499.99000000,36980.00000000,37467.18000000,2969.28167600,1612468799999,110544242.29106592,75098,1335.24969300,49718533.36209310,0 -1612468800000,37467.18000000,37783.83000000,37366.00000000,37613.31000000,3154.23804600,1612472399999,118507575.50112123,79887,1529.58809400,57462912.05821626,0 -1612472400000,37613.32000000,37729.82000000,37302.00000000,37643.00000000,2384.69396100,1612475999999,89503771.03270257,74675,1111.65352100,41720592.51664071,0 -1612476000000,37643.00000000,37698.73000000,36964.03000000,37240.00000000,2533.48052000,1612479599999,94359816.25785984,79029,1148.75691600,42780272.54525439,0 -1612479600000,37240.00000000,37382.34000000,36841.77000000,36936.66000000,2701.29948700,1612483199999,100265466.93272621,61845,1217.87383100,45208704.65722741,0 -1612483200000,36936.65000000,37227.22000000,36795.72000000,36993.25000000,2538.98242500,1612486799999,94060540.82816912,66150,1370.47502500,50781072.55362958,0 -1612486800000,36993.25000000,37300.00000000,36570.00000000,36632.38000000,2618.34989800,1612490399999,96919235.86880108,65505,1214.69936000,44986589.95702002,0 -1612490400000,36632.38000000,36990.00000000,36570.00000000,36958.28000000,2861.36000100,1612493999999,105221638.22311394,66191,1351.23382600,49686787.80852069,0 -1612494000000,36958.33000000,37400.00000000,36909.71000000,37366.02000000,2614.23721000,1612497599999,97331762.32062225,68270,1382.64503900,51483483.61294185,0 -1612497600000,37366.01000000,37499.00000000,37187.81000000,37266.78000000,1902.89073900,1612501199999,70991732.29723368,54835,998.86660700,37264472.34248572,0 -1612501200000,37266.79000000,37350.33000000,36995.27000000,37065.97000000,1730.40606500,1612504799999,64358448.18172280,49929,824.66968800,30670842.63141629,0 -1612504800000,37065.98000000,37658.00000000,37021.80000000,37375.52000000,2965.59287000,1612508399999,110836113.57500378,76786,1668.63744500,62377233.66280996,0 -1612508400000,37374.39000000,37727.22000000,37374.38000000,37653.98000000,2722.54939900,1612511999999,102258856.11144493,74145,1405.51437900,52789937.13927410,0 -1612512000000,37659.64000000,37800.00000000,37392.71000000,37705.27000000,3404.58685900,1612515599999,128051636.94025258,85797,1728.19622500,65008576.01249925,0 -1612515600000,37705.27000000,37769.85000000,37211.85000000,37251.07000000,2526.09904400,1612519199999,94847506.17347487,70845,1167.10109800,43835634.94429535,0 -1612519200000,37251.07000000,37655.44000000,37200.00000000,37395.91000000,2315.26181600,1612522799999,86736898.08353802,70360,1122.58134400,42057910.15909118,0 -1612522800000,37395.92000000,37733.75000000,37395.78000000,37691.32000000,2165.14946300,1612526399999,81402029.34160568,63507,1010.10163900,37972029.61722899,0 -1612526400000,37691.32000000,38151.69000000,37527.14000000,37850.36000000,4197.95733600,1612529999999,159155783.62946250,104275,2317.12911900,87866670.67919380,0 -1612530000000,37850.36000000,38298.00000000,37767.09000000,38272.32000000,3967.77305800,1612533599999,150813327.15355556,127525,2099.61640800,79831159.32397812,0 -1612533600000,38272.33000000,38310.12000000,37960.73000000,38095.02000000,4108.05694300,1612537199999,156744958.72791620,99933,1866.70509400,71218889.68443885,0 -1612537200000,38095.14000000,38288.19000000,37871.42000000,37960.76000000,3833.87290000,1612540799999,145986174.46799004,114481,1710.61808300,65151398.33083216,0 -1612540800000,37960.76000000,38163.34000000,37655.17000000,37809.55000000,4270.39593400,1612544399999,162066461.07501361,130627,1847.41596500,70111024.53628700,0 -1612544400000,37813.19000000,37950.00000000,37733.00000000,37894.61000000,2229.58176300,1612547999999,84391751.86856290,68440,1069.02714800,40465805.16053230,0 -1612548000000,37894.61000000,37922.44000000,37312.25000000,37406.23000000,2936.18453000,1612551599999,110607646.49013193,73073,1329.27869900,50085592.08049400,0 -1612551600000,37405.63000000,37676.13000000,37230.00000000,37608.92000000,3067.36093300,1612555199999,115005347.28495289,77422,1344.85113300,50427638.18365530,0 -1612555200000,37608.91000000,37790.00000000,37485.94000000,37740.39000000,2177.90475900,1612558799999,82020586.16573915,69036,1082.11254000,40757143.58772434,0 -1612558800000,37740.40000000,37920.00000000,37656.29000000,37819.67000000,1692.32032700,1612562399999,63941297.17713087,60169,821.26085200,31034094.15883675,0 -1612562400000,37819.67000000,37971.61000000,37652.79000000,37784.12000000,1587.73281200,1612565999999,60092643.60543921,53710,718.65661900,27201604.72468686,0 -1612566000000,37782.98000000,38309.00000000,37743.81000000,38290.24000000,2246.72719100,1612569599999,85435916.16070902,62242,1304.99169600,49648288.94626587,0 -1612569600000,38289.32000000,38879.00000000,38215.94000000,38740.92000000,5397.48355200,1612573199999,208053475.66680662,147707,3406.47525700,131322910.58625497,0 -1612573200000,38740.92000000,39482.18000000,38275.86000000,38806.45000000,10003.94637800,1612576799999,390200018.23093633,197361,5676.12679700,221449716.55407816,0 -1612576800000,38806.45000000,39535.36000000,38612.00000000,39382.10000000,5911.87452700,1612580399999,231361842.13340831,128272,3115.93829000,122001548.96890421,0 -1612580400000,39383.26000000,39666.00000000,39200.00000000,39384.74000000,4116.76235500,1612583999999,162350846.58796715,91721,2220.03890000,87582967.52244492,0 -1612584000000,39386.92000000,39386.93000000,38933.00000000,39179.56000000,2678.75088500,1612587599999,104992043.77130752,60522,1391.05886300,54518857.13771583,0 -1612587600000,39179.56000000,39238.00000000,38600.00000000,39014.73000000,2895.91239600,1612591199999,112848792.63929416,64210,1441.67270800,56201285.53642504,0 -1612591200000,39015.08000000,39458.37000000,38989.90000000,39267.47000000,2778.74063400,1612594799999,109086522.14959429,58879,1398.43575600,54896197.02950555,0 -1612594800000,39267.47000000,39488.62000000,39156.16000000,39359.12000000,2344.52768700,1612598399999,92210146.02486588,55905,1187.52056100,46709229.45616234,0 -1612598400000,39362.27000000,39699.69000000,39297.75000000,39425.02000000,3300.46687200,1612601999999,130441380.93142371,74577,1752.72083500,69278540.91525593,0 -1612602000000,39427.00000000,39900.00000000,39400.00000000,39887.91000000,3983.37562300,1612605599999,158139448.06879191,92083,2259.81137600,89736312.59180295,0 -1612605600000,39887.91000000,40000.00000000,39516.17000000,39998.63000000,4327.83615600,1612609199999,172331537.28403555,89421,2465.75916600,98241913.39500154,0 -1612609200000,39998.63000000,40479.86000000,39992.64000000,40199.99000000,6837.07743600,1612612799999,275033964.19394919,143363,3673.13335200,147725671.45858567,0 -1612612800000,40199.52000000,40445.55000000,39836.72000000,39902.49000000,4298.29820900,1612616399999,172657675.33101562,92646,2161.80091700,86855747.22067142,0 -1612616400000,39902.50000000,40255.08000000,39900.00000000,40130.47000000,2914.83720400,1612619999999,116904231.22820420,79449,1450.02169800,58146130.51888595,0 -1612620000000,40127.07000000,40574.85000000,40125.30000000,40268.44000000,3508.67471100,1612623599999,141595861.06674717,93559,1875.19658100,75682835.58260766,0 -1612623600000,40268.44000000,40866.66000000,40134.80000000,40864.73000000,4850.41533800,1612627199999,196738399.90669565,125084,2635.63599800,106912802.55464475,0 -1612627200000,40865.12000000,40955.51000000,40478.19000000,40608.76000000,4533.51779900,1612630799999,184552299.88860376,95758,2349.01142000,95629949.47079209,0 -1612630800000,40608.77000000,40662.01000000,40163.67000000,40197.01000000,3400.92676500,1612634399999,137684308.85395985,100225,1623.59211800,65744658.43377461,0 -1612634400000,40197.01000000,40444.44000000,40052.39000000,40276.41000000,3152.89187200,1612637999999,126882405.86077563,99367,1621.15080000,65251328.98528318,0 -1612638000000,40276.41000000,40420.00000000,39940.44000000,40179.42000000,3188.91142100,1612641599999,128046935.90480729,66350,1673.80400000,67202217.40755716,0 -1612641600000,40179.42000000,40179.42000000,39572.74000000,40087.40000000,4169.92339700,1612645199999,166198712.66538587,85476,2118.90035900,84468998.23157547,0 -1612645200000,40087.40000000,40250.00000000,40026.98000000,40028.19000000,2506.70206700,1612648799999,100621883.58426316,78962,1135.88883000,45596660.88473547,0 -1612648800000,40028.91000000,40469.19000000,39869.00000000,39992.77000000,2057.03210500,1612652399999,82644937.35575857,64952,1038.37131000,41738352.71705292,0 -1612652400000,39992.77000000,40083.86000000,39035.33000000,39186.94000000,5598.42579400,1612655999999,220517479.59955308,105797,2343.44747000,92285914.18750626,0 -1612656000000,39181.01000000,39611.04000000,38701.00000000,39564.17000000,4552.18409900,1612659599999,178542407.33143695,93465,1976.99804200,77615459.49756957,0 -1612659600000,39564.16000000,39588.90000000,38500.00000000,38627.36000000,4822.67221800,1612663199999,188375499.80254731,101064,2112.28431200,82610946.92491478,0 -1612663200000,38627.36000000,38820.00000000,38344.00000000,38747.31000000,4332.43097600,1612666799999,167276556.58820521,98932,2003.81349700,77383388.60306319,0 -1612666800000,38747.31000000,38926.58000000,38554.63000000,38841.46000000,2453.33738000,1612670399999,95079047.20114498,84838,1205.41446900,46718949.65173031,0 -1612670400000,38839.52000000,38839.52000000,37923.00000000,38312.99000000,4918.02111900,1612673999999,188621927.55185316,121762,2224.93175500,85416326.01581226,0 -1612674000000,38312.99000000,38692.04000000,38175.02000000,38511.00000000,2441.37048500,1612677599999,93822676.60161684,60173,1244.28011400,47824960.17905836,0 -1612677600000,38511.01000000,38700.00000000,38282.44000000,38531.35000000,2092.40306000,1612681199999,80635761.10435173,50410,1035.78810100,39915086.52709731,0 -1612681200000,38531.35000000,39094.36000000,38410.63000000,39030.00000000,3441.57032400,1612684799999,133713437.10999375,72600,1648.17198200,64043236.24602802,0 -1612684800000,39030.00000000,39529.00000000,39021.22000000,39496.96000000,3816.58070600,1612688399999,150114213.35314617,78481,2057.54242000,80939443.85233719,0 -1612688400000,39496.96000000,39700.00000000,39304.18000000,39513.92000000,2546.25168700,1612691999999,100566318.01428217,60075,1279.97857700,50558052.51961604,0 -1612692000000,39513.92000000,39658.04000000,39124.39000000,39331.42000000,3239.67694100,1612695599999,127508580.30409017,72901,1911.25912700,75210340.15890308,0 -1612695600000,39331.43000000,39358.00000000,38762.16000000,39046.60000000,3207.01430500,1612699199999,125201209.09617050,80558,1672.26608500,65284270.30592733,0 -1612699200000,39044.37000000,39272.69000000,38530.25000000,38820.87000000,3546.26063300,1612702799999,137643917.64609149,84468,1788.32781400,69429076.28582462,0 -1612702800000,38820.87000000,39119.47000000,38381.62000000,38629.26000000,3723.03824100,1612706399999,144194292.25096896,82493,1789.60439700,69307989.63849768,0 -1612706400000,38629.26000000,38700.00000000,38162.87000000,38214.98000000,3836.98198500,1612709999999,147453531.70169341,89438,1853.70646900,71253242.19345469,0 -1612710000000,38215.01000000,38395.26000000,37580.00000000,37921.11000000,6376.15806600,1612713599999,242026048.33180534,139577,2773.44817900,105268386.92469764,0 -1612713600000,37921.12000000,38244.50000000,37351.00000000,38185.72000000,6459.78356200,1612717199999,244040363.26502659,133648,3115.32024100,117743789.16913083,0 -1612717200000,38179.78000000,38208.60000000,37685.96000000,37870.62000000,2902.65676900,1612720799999,110346883.99433824,71482,1405.96995700,53447579.23303858,0 -1612720800000,37870.63000000,38342.88000000,37846.66000000,38239.10000000,2631.35331500,1612724399999,100278110.80744342,68332,1295.44204500,49365879.51053074,0 -1612724400000,38239.37000000,38444.00000000,37976.00000000,38050.00000000,2671.24633600,1612727999999,102309356.48609894,65691,1179.36978500,45180735.78622704,0 -1612728000000,38050.00000000,38492.82000000,37660.97000000,38471.95000000,2745.74401700,1612731599999,104501767.56806792,68446,1387.67585000,52833061.93097086,0 -1612731600000,38471.96000000,38635.42000000,38355.45000000,38530.33000000,2282.27472500,1612735199999,87851831.46733939,55575,1200.31639400,46205951.31578641,0 -1612735200000,38530.37000000,38832.99000000,38285.10000000,38797.02000000,2286.31583500,1612738799999,88111847.41554566,76519,1064.79476800,41051399.96729534,0 -1612738800000,38797.02000000,39080.00000000,38715.66000000,38795.69000000,3038.35297900,1612742399999,118305799.24735263,65429,1537.68457900,59875355.12639038,0 -1612742400000,38795.69000000,39130.00000000,38650.76000000,38725.40000000,3030.91878000,1612745999999,117791949.79313795,65167,1405.32997800,54617947.61118808,0 -1612746000000,38725.40000000,38909.95000000,38430.48000000,38521.72000000,2492.17365300,1612749599999,96312458.87905944,56830,1270.62993100,49106010.59596674,0 -1612749600000,38521.72000000,38650.00000000,38149.00000000,38249.00000000,2220.46382100,1612753199999,85280341.98126883,52010,1078.11386600,41407195.82047728,0 -1612753200000,38249.00000000,38497.50000000,37988.89000000,38076.06000000,2798.66060900,1612756799999,107131637.01042387,55513,1285.08646600,49207822.45467370,0 -1612756800000,38073.02000000,38684.21000000,37992.39000000,38584.70000000,2611.81627200,1612760399999,100519036.16207770,54037,1250.48586300,48124048.95702886,0 -1612760400000,38584.92000000,38872.00000000,38440.68000000,38677.47000000,2411.12876500,1612763999999,93241978.54774997,52341,1143.79146300,44227267.02963788,0 -1612764000000,38677.84000000,39233.39000000,38620.00000000,39012.69000000,2829.47296400,1612767599999,110342777.22582950,63244,1538.22857700,59996368.11071210,0 -1612767600000,39012.69000000,39391.78000000,38874.63000000,39269.95000000,2414.80194400,1612771199999,94595602.60556947,61747,1300.89253400,50966390.98282920,0 -1612771200000,39269.78000000,39349.56000000,39040.17000000,39175.38000000,2258.26449200,1612774799999,88500049.48902812,62080,1007.98681000,39500241.71163902,0 -1612774800000,39175.38000000,39364.77000000,38888.00000000,38954.27000000,2762.90216000,1612778399999,108076786.29721453,75447,1383.59556900,54126699.41096542,0 -1612778400000,38954.28000000,39450.10000000,38844.75000000,39418.71000000,3105.50345500,1612781999999,121624026.58701947,78008,1718.24311700,67305407.08201280,0 -1612782000000,39418.71000000,39498.99000000,39301.01000000,39423.08000000,2769.79507600,1612785599999,109144775.45251031,97377,1484.98658000,58517565.03905303,0 -1612785600000,39423.08000000,43231.10000000,39094.01000000,42984.07000000,13971.32848000,1612789199999,572303859.09169724,281022,8934.79634000,365535713.95395129,0 -1612789200000,42984.07000000,44918.00000000,41906.70000000,42897.12000000,21921.23645700,1612792799999,951254145.42218917,457654,11816.01984300,513017816.11132060,0 -1612792800000,42907.14000000,44057.94000000,42767.63000000,43558.73000000,11977.05863900,1612796399999,521038272.71814902,217634,6496.48940400,282657161.46136651,0 -1612796400000,43560.93000000,44164.74000000,43345.27000000,43716.32000000,9038.40695600,1612799999999,394966646.10916701,195838,4745.24468800,207432113.54493147,0 -1612800000000,43703.23000000,44280.00000000,43051.00000000,43170.24000000,8148.28728200,1612803599999,356060320.08012214,203787,3716.89390300,162371709.27085316,0 -1612803600000,43184.74000000,43418.39000000,42521.62000000,43079.07000000,5094.63397200,1612807199999,218820296.72776131,162393,2484.82238500,106741803.24217564,0 -1612807200000,43079.08000000,43397.02000000,42554.71000000,42673.49000000,3721.17821400,1612810799999,159805467.36965493,121696,1779.31882600,76420277.18409947,0 -1612810800000,42673.49000000,43140.29000000,42644.49000000,43051.95000000,2979.57181700,1612814399999,127868659.74062607,102328,1388.60700800,59603412.90703731,0 -1612814400000,43049.98000000,44350.00000000,42905.29000000,44151.07000000,6270.11109400,1612817999999,273096814.28266604,135972,2952.18884100,128686340.41412909,0 -1612818000000,44151.08000000,44799.58000000,43898.01000000,44632.41000000,6150.11080700,1612821599999,272426547.58067972,184914,3065.72219700,135879874.50597368,0 -1612821600000,44632.41000000,45034.48000000,44255.31000000,44682.76000000,5824.20366400,1612825199999,260330653.55861259,159797,3019.84577000,135105545.36924606,0 -1612825200000,44682.76000000,46794.45000000,44595.97000000,46374.87000000,11795.50754100,1612828799999,541003873.92348507,234125,6078.57160900,278759106.66986738,0 -1612828800000,46374.86000000,47498.00000000,46233.95000000,46768.22000000,10775.23109500,1612832399999,505274026.19963943,213817,5529.29043500,259330365.73344783,0 -1612832400000,46768.22000000,46770.61000000,45816.98000000,46158.97000000,7858.70160000,1612835999999,363311935.08453492,173087,3972.34052200,183578877.33859870,0 -1612836000000,46158.97000000,46348.96000000,45567.00000000,45707.38000000,4175.58615200,1612839599999,192023821.51698209,126347,2033.82809200,93527518.41809928,0 -1612839600000,45707.39000000,46750.00000000,45500.00000000,46599.51000000,4064.72925900,1612843199999,187934698.90951716,115209,2024.16391000,93590329.67704448,0 -1612843200000,46599.51000000,46888.00000000,46198.76000000,46837.57000000,3699.74339500,1612846799999,171897463.38680134,95864,1987.67055500,92367874.95742521,0 -1612846800000,46837.57000000,47219.13000000,46455.70000000,46850.12000000,4005.59749300,1612850399999,187582327.82090888,101403,2011.65750200,94230595.17602203,0 -1612850400000,46852.68000000,48140.90000000,46563.31000000,48111.18000000,6952.35579500,1612853999999,329510651.06549870,144340,4079.49401700,193431658.64145623,0 -1612854000000,48111.46000000,48142.19000000,47370.75000000,47505.40000000,5503.63622200,1612857599999,262512962.43176997,134510,2643.67907500,126098785.09148344,0 -1612857600000,47505.39000000,47928.23000000,46624.84000000,47109.51000000,6591.01341800,1612861199999,310754894.97243355,168396,3284.95261300,154951405.93493237,0 -1612861200000,47106.59000000,47160.00000000,46000.00000000,46401.30000000,4989.13460200,1612864799999,232243943.70862709,120413,2251.05362500,104878165.37866938,0 -1612864800000,46401.30000000,46588.00000000,45560.97000000,45641.77000000,4844.88605900,1612868399999,223420555.94472194,121039,2326.91117600,107370395.82193574,0 -1612868400000,45641.77000000,46683.18000000,45601.01000000,46380.92000000,3819.42801300,1612871999999,176260337.92535215,138954,2058.15398800,94979754.14789256,0 -1612872000000,46390.95000000,46806.41000000,45128.70000000,45300.17000000,5558.60425000,1612875599999,255693991.46305083,149422,2336.06912800,107407930.62631562,0 -1612875600000,45300.17000000,46425.00000000,44961.09000000,46285.14000000,6234.47110300,1612879199999,284785343.20588035,160509,2955.16842800,135015662.92702425,0 -1612879200000,46282.88000000,46700.00000000,46051.42000000,46624.44000000,3978.74752600,1612882799999,184275768.33181201,138195,1954.22864000,90517689.74133678,0 -1612882800000,46624.33000000,47083.84000000,46300.00000000,46773.63000000,5240.74903500,1612886399999,245141766.85935935,128932,2615.78801400,122361687.60946770,0 -1612886400000,46773.63000000,47110.72000000,46011.00000000,46470.85000000,4941.37082500,1612889999999,230199072.60440069,151285,2534.08989600,118083599.93105195,0 -1612890000000,46470.85000000,46940.91000000,46180.00000000,46483.67000000,3342.61264800,1612893599999,155501851.86611672,111222,1647.91334400,76675037.82333734,0 -1612893600000,46484.23000000,47433.78000000,46254.02000000,47012.77000000,4549.47911600,1612897199999,213785907.55947327,126534,2415.68949000,113522798.87660305,0 -1612897200000,47012.77000000,47289.28000000,46743.15000000,47060.18000000,2849.52535700,1612900799999,133860890.58155883,102956,1235.97484300,58082444.21378054,0 -1612900800000,47060.38000000,47499.43000000,46668.48000000,47084.17000000,3254.70271400,1612904399999,153225097.12674644,100788,1614.44070500,76019942.80397932,0 -1612904400000,47084.16000000,47461.06000000,46995.92000000,47231.03000000,2564.52493900,1612907999999,121109049.80527570,77433,1355.08328300,63994284.82557085,0 -1612908000000,47241.92000000,47241.92000000,46440.52000000,46839.01000000,2914.61431100,1612911599999,136314971.82543424,105273,1282.12154800,59976197.15951714,0 -1612911600000,46839.99000000,46860.00000000,46201.37000000,46420.42000000,2790.41678500,1612915199999,129634067.82129161,113106,1279.80151800,59458033.63681170,0 -1612915200000,46420.42000000,46900.00000000,46052.52000000,46517.64000000,3108.22494200,1612918799999,144725522.01661322,112724,1542.87810600,71867000.01282311,0 -1612918800000,46517.64000000,46533.52000000,45979.58000000,46259.97000000,3406.34784100,1612922399999,157491628.44145226,120124,1719.19236000,79491804.56903536,0 -1612922400000,46259.97000000,46800.00000000,46250.00000000,46276.51000000,3428.35059200,1612925999999,159414024.28492220,109913,1845.63178100,85821883.66758124,0 -1612926000000,46276.52000000,46743.87000000,46140.73000000,46221.07000000,3072.21766700,1612929599999,142503680.27006616,82996,1520.52985000,70536121.02378193,0 -1612929600000,46225.71000000,46319.03000000,45589.98000000,46020.40000000,4212.23625700,1612933199999,193184808.92330566,92361,2197.98082200,100796533.47325694,0 -1612933200000,46020.40000000,46424.93000000,45826.85000000,46131.99000000,2960.18055700,1612936799999,136653923.65983346,107677,1564.68467300,72237136.44424584,0 -1612936800000,46132.00000000,46650.00000000,46106.04000000,46510.25000000,2853.33957900,1612940399999,132540701.74792469,77526,1555.67686000,72262630.86099723,0 -1612940400000,46510.26000000,46944.07000000,46400.17000000,46563.69000000,3525.20422800,1612943999999,164394158.86926745,122297,1909.59152300,89062223.41210388,0 -1612944000000,46565.11000000,46844.59000000,46262.22000000,46668.89000000,3612.18762000,1612947599999,168046442.39707710,106493,2006.55363000,93370302.94057853,0 -1612947600000,46668.89000000,46900.00000000,46451.12000000,46550.00000000,3035.30548800,1612951199999,141776623.44097430,92272,1682.15254200,78565820.44870791,0 -1612951200000,46549.99000000,47310.00000000,46401.00000000,46630.17000000,4890.23204000,1612954799999,229342420.95511850,158998,2630.31290800,123370028.14241119,0 -1612954800000,46630.17000000,46691.94000000,46277.31000000,46586.56000000,2517.19374100,1612958399999,116999072.96833033,89683,1254.29354400,58304527.72301069,0 -1612958400000,46586.55000000,46593.34000000,44500.00000000,45652.34000000,9491.10542400,1612961999999,432642241.14381962,263732,4074.05066900,185753917.01434405,0 -1612962000000,45655.13000000,45969.28000000,45314.32000000,45626.32000000,5201.63471400,1612965599999,237517282.99456999,194463,2349.74776400,107321228.71241677,0 -1612965600000,45626.32000000,45988.20000000,44800.00000000,44954.12000000,5933.22736600,1612969199999,269001701.01912217,175733,2548.21964900,115623932.20685685,0 -1612969200000,44954.13000000,45227.27000000,43727.00000000,44353.04000000,9617.54060300,1612972799999,427486353.98836603,221857,4388.63303100,195152081.04264996,0 -1612972800000,44354.50000000,44900.00000000,43800.00000000,44746.66000000,5766.03991500,1612976399999,256477173.20488165,151805,2880.80272100,128170383.52477059,0 -1612976400000,44746.65000000,45071.45000000,44446.12000000,44963.31000000,3576.59790300,1612979999999,160245092.08724017,98294,1757.53643000,78745423.38097770,0 -1612980000000,44963.32000000,45200.00000000,44731.74000000,45088.17000000,3335.95103300,1612983599999,150232868.90680044,88939,1705.41583300,76814403.81694472,0 -1612983600000,45088.16000000,45239.98000000,44450.10000000,45190.05000000,3638.89731700,1612987199999,163302568.75371586,98852,1867.24189600,83813850.26899005,0 -1612987200000,45190.05000000,45240.70000000,44400.00000000,44555.59000000,2929.85296300,1612990799999,131336678.83683750,96105,1473.61305600,66060274.38136047,0 -1612990800000,44555.59000000,45028.15000000,44355.00000000,44999.09000000,2811.10407300,1612994399999,125539701.96718489,92892,1460.22626400,65229667.60533560,0 -1612994400000,44999.09000000,45216.49000000,44880.00000000,45199.99000000,1698.33418500,1612997999999,76570446.67516731,64905,851.45837300,38392700.75485535,0 -1612998000000,45200.00000000,45322.09000000,44769.88000000,44807.58000000,2532.87615200,1613001599999,114225012.69851429,70951,1185.56144600,53467363.38955074,0 -1613001600000,44807.58000000,45051.27000000,43994.02000000,44250.00000000,4145.40034300,1613005199999,184540982.07683789,117432,1904.41791700,84814761.28277238,0 -1613005200000,44250.00000000,44554.91000000,44010.88000000,44180.86000000,2791.70519700,1613008799999,123757289.11946866,78789,1479.85382600,65613379.02573939,0 -1613008800000,44180.08000000,44698.15000000,44172.57000000,44582.07000000,825.57125600,1613012399999,36756000.90767989,26744,451.86218000,20120073.75826733,0 -1613012400000,44582.07000000,44582.07000000,44582.07000000,44582.07000000,0.00000000,1613014854773,0.00000000,0,0.00000000,0.00000000,0 -1613019600000,44583.71000000,44999.00000000,44507.00000000,44641.72000000,2359.40984600,1613023199999,105586295.71125404,86586,1214.65927000,54364467.84916051,0 -1613023200000,44641.71000000,44918.19000000,44397.62000000,44559.99000000,2121.32005100,1613026799999,94729253.67138495,79025,1003.91767600,44836209.59223975,0 -1613026800000,44559.98000000,45129.59000000,44559.98000000,44700.01000000,2885.69503200,1613030399999,129648498.38039203,89906,1407.53347700,63245537.87999281,0 -1613030400000,44700.00000000,45095.49000000,44500.00000000,45017.02000000,2819.24106000,1613033999999,126257309.41883641,92734,1326.30392500,59424263.51177562,0 -1613034000000,45017.01000000,45609.16000000,44789.11000000,45500.98000000,3446.63083900,1613037599999,155601476.56576339,110310,1918.32236700,86632857.71743990,0 -1613037600000,45500.98000000,46377.44000000,45351.00000000,46279.80000000,4555.92155500,1613041199999,208521388.03699547,126846,2348.48315000,107573294.34162350,0 -1613041200000,46279.81000000,46546.47000000,45864.40000000,46061.49000000,4197.20832600,1613044799999,194027754.66724067,114423,2146.81190300,99264614.59968872,0 -1613044800000,46061.48000000,46625.83000000,46060.03000000,46516.39000000,3578.10764600,1613048399999,166014983.80997793,107617,1911.35190000,88689856.29531453,0 -1613048400000,46516.39000000,48399.00000000,46516.39000000,47555.46000000,13364.20517400,1613051999999,637152612.73289668,324269,7688.28214100,366593968.29226558,0 -1613052000000,47555.46000000,48100.00000000,47233.00000000,47864.81000000,5336.00574200,1613055599999,254515475.14724918,123624,2975.85510800,142002750.77037891,0 -1613055600000,47864.81000000,48185.26000000,47576.58000000,47960.85000000,4946.07776600,1613059199999,236862476.03094766,119640,2504.23152600,119978280.81114286,0 -1613059200000,47960.86000000,48298.00000000,47337.18000000,47590.53000000,4852.40756700,1613062799999,231886502.35895781,141567,2439.47310500,116635147.37799019,0 -1613062800000,47590.52000000,47666.97000000,46900.00000000,47366.42000000,3618.16439500,1613066399999,171070096.78908613,135155,1838.15493600,86918626.85669068,0 -1613066400000,47366.43000000,48010.54000000,47311.01000000,47653.14000000,3425.20414100,1613069999999,163336518.84669500,99995,1817.68629600,86691755.25250974,0 -1613070000000,47653.15000000,48050.00000000,47526.28000000,47754.03000000,3150.42137400,1613073599999,150798893.31631415,117847,1697.15669100,81247929.12738847,0 -1613073600000,47754.02000000,48678.90000000,47000.00000000,47027.49000000,6204.93255600,1613077199999,297302565.32965942,158483,3139.16955400,150593641.83827483,0 -1613077200000,47027.49000000,47360.00000000,46542.29000000,46884.84000000,5079.47740900,1613080799999,238541749.49237101,120266,2142.97912700,100644373.61292273,0 -1613080800000,46885.07000000,47727.37000000,46864.32000000,47712.94000000,2820.02394000,1613084399999,133425727.90695118,93877,1198.92751600,56726849.65012410,0 -1613084400000,47716.44000000,48125.58000000,47588.65000000,47969.51000000,3037.95023900,1613087999999,145297084.09393544,105814,1582.90314900,75723283.24862085,0 -1613088000000,47968.66000000,48985.80000000,47770.58000000,47990.00000000,6786.70764900,1613091599999,329105189.36083577,175069,3930.51515200,190667676.28566924,0 -1613091600000,47990.01000000,48550.00000000,47721.00000000,48477.50000000,2957.11592700,1613095199999,142466595.59612409,105150,1480.42190600,71327147.29041160,0 -1613095200000,48477.51000000,48477.51000000,47729.68000000,47935.66000000,3206.02141300,1613098799999,154268952.43159719,74731,1822.37443500,87715348.27697328,0 -1613098800000,47935.66000000,47988.49000000,47338.35000000,47587.31000000,2471.16246300,1613102399999,117791339.87269018,63708,1208.91740300,57630517.38636812,0 -1613102400000,47587.31000000,47587.31000000,46888.00000000,47271.55000000,4724.62151100,1613105999999,222878560.54100781,107423,1903.44237500,89819256.58668268,0 -1613106000000,47271.54000000,47506.44000000,47086.30000000,47257.09000000,3397.95599300,1613109599999,160812548.46313150,106915,1574.90293200,74536014.38939227,0 -1613109600000,47257.09000000,47551.02000000,46789.00000000,47380.16000000,3483.71169900,1613113199999,164362658.90442514,76561,1608.66549000,75927489.29698522,0 -1613113200000,47380.15000000,47475.00000000,46903.48000000,47318.81000000,2921.00849600,1613116799999,137891961.65193392,91205,1393.99899500,65806393.93410295,0 -1613116800000,47318.02000000,47700.00000000,47080.00000000,47117.86000000,3406.82443700,1613120399999,161434280.11324426,117079,1710.78602000,81083052.15607194,0 -1613120400000,47117.86000000,47400.00000000,47027.03000000,47337.00000000,2666.71850100,1613123999999,125893980.83818209,81497,1408.75366400,66512693.47278401,0 -1613124000000,47337.01000000,47711.00000000,47300.00000000,47381.16000000,2710.45776600,1613127599999,128709097.20287873,80154,1401.97785500,66577186.87763223,0 -1613127600000,47371.80000000,47999.00000000,47280.26000000,47562.42000000,2966.76718800,1613131199999,141273408.13448735,94784,1618.78663200,77094280.58199452,0 -1613131200000,47560.06000000,47957.87000000,47323.61000000,47669.82000000,2999.82626000,1613134799999,142971083.26918040,86565,1467.96618900,69950703.40792844,0 -1613134800000,47669.82000000,48140.00000000,47646.00000000,47871.40000000,3795.08650900,1613138399999,181852482.15911031,84014,1925.30539400,92274673.39796593,0 -1613138400000,47871.40000000,47878.74000000,46125.00000000,46547.50000000,8109.95056100,1613141999999,380438580.18828964,168342,3066.37777800,143817140.78583088,0 -1613142000000,46542.60000000,47163.83000000,46525.25000000,47021.05000000,4791.74044800,1613145599999,224732107.80397928,115458,1965.07758000,92158450.76053785,0 -1613145600000,47021.05000000,47980.00000000,47008.40000000,47614.40000000,4632.35856400,1613149199999,220200748.80202655,129365,2507.52307800,119186545.04986801,0 -1613149200000,47612.52000000,47905.00000000,47459.78000000,47713.82000000,3375.04444900,1613152799999,160965420.00114915,108069,1770.45632500,84446523.78661901,0 -1613152800000,47713.83000000,47800.00000000,46915.32000000,47269.25000000,3866.28210200,1613156399999,183170674.50725803,113771,1898.85694800,89979243.50280463,0 -1613156400000,47268.27000000,47453.99000000,47086.32000000,47272.95000000,2344.98428900,1613159999999,110886680.18908771,82297,1039.97103000,49174105.69542646,0 -1613160000000,47272.96000000,47653.24000000,47140.26000000,47577.49000000,2591.14661000,1613163599999,122865293.60086744,77868,1176.03708800,55773960.77881402,0 -1613163600000,47577.49000000,48150.00000000,47560.01000000,47860.54000000,3556.84785500,1613167199999,170105117.73034401,106653,2100.01068700,100478479.98683872,0 -1613167200000,47860.75000000,47930.00000000,47602.71000000,47841.17000000,1481.56351100,1613170799999,70786383.61192161,82449,719.21218600,34362470.58815187,0 -1613170800000,47841.16000000,47870.00000000,47155.00000000,47287.60000000,2626.13149600,1613174399999,124708763.99390937,89714,1140.70199300,54173564.65273099,0 -1613174400000,47298.15000000,47587.29000000,47200.00000000,47459.54000000,2749.95842900,1613177999999,130278520.79639110,77928,1566.45178000,74203799.38910789,0 -1613178000000,47459.53000000,47799.61000000,47412.40000000,47626.98000000,2409.97375700,1613181599999,114842069.79136774,71635,1311.32682200,62494134.92434280,0 -1613181600000,47629.76000000,47944.84000000,47503.57000000,47839.77000000,2036.99045900,1613185199999,97207665.40260089,68481,1087.68647100,51913065.01987237,0 -1613185200000,47839.77000000,48150.00000000,47693.44000000,47829.22000000,2448.08022500,1613188799999,117199433.02362883,82095,1285.27154500,61544937.37874067,0 -1613188800000,47829.21000000,47924.86000000,47598.89000000,47904.70000000,1983.56289600,1613192399999,94728852.94530847,55291,965.42736900,46111202.15620792,0 -1613192400000,47904.69000000,47934.14000000,47397.71000000,47888.00000000,2604.32470700,1613195999999,124213425.66935890,72837,1212.44352100,57843107.35586879,0 -1613196000000,47887.99000000,47922.22000000,47483.88000000,47728.26000000,2058.77855700,1613199599999,98127246.97414455,93121,984.58164000,46924695.75272914,0 -1613199600000,47728.25000000,47794.36000000,46990.00000000,46995.72000000,3084.23424400,1613203199999,146077668.02093981,117815,1287.87213300,61025205.75170483,0 -1613203200000,46995.01000000,47499.93000000,46618.00000000,47429.93000000,3749.61188800,1613206799999,176778974.61905360,124648,1694.46254100,79890639.41544427,0 -1613206800000,47429.92000000,47569.03000000,47061.00000000,47205.53000000,2095.84243100,1613210399999,99205007.00637642,74304,1002.36347400,47448456.22309443,0 -1613210400000,47205.52000000,47266.05000000,46660.44000000,46709.17000000,4954.58299000,1613213999999,233121108.64482687,121839,2391.40789300,112553293.58607895,0 -1613214000000,46700.77000000,46990.00000000,46251.00000000,46589.20000000,5399.86052400,1613217599999,251729345.47012649,162522,2340.43296000,109125918.11598543,0 -1613217600000,46586.23000000,47209.25000000,46202.53000000,46879.81000000,3800.32361700,1613221199999,178158136.50656325,104894,1841.05206600,86339763.83543092,0 -1613221200000,46879.81000000,47150.22000000,46557.56000000,46971.43000000,3446.30427500,1613224799999,161654009.80683459,89740,1598.69823200,74991594.07773369,0 -1613224800000,46971.43000000,47044.04000000,46596.37000000,46946.90000000,2508.59132200,1613228399999,117432469.88562899,77718,1205.10570800,56417225.26116503,0 -1613228400000,46946.67000000,47300.00000000,46883.03000000,47076.01000000,2933.38704900,1613231999999,138289031.88103748,91046,1488.39878900,70165043.71039798,0 -1613232000000,47076.02000000,47400.14000000,46864.48000000,47136.89000000,2729.09808200,1613235599999,128649056.46212938,95531,1340.14111000,63181395.35727337,0 -1613235600000,47136.90000000,47190.00000000,46735.83000000,46855.24000000,2308.46806600,1613239199999,108463214.98842457,88653,1097.42261900,51564386.74235221,0 -1613239200000,46855.23000000,47022.26000000,46738.24000000,46792.05000000,1858.54608200,1613242799999,87151435.42899831,64903,868.04645200,40703558.81344678,0 -1613242800000,46790.39000000,47086.92000000,46708.94000000,46870.15000000,1771.33522700,1613246399999,83072851.52190488,60723,890.09556700,41744449.53535929,0 -1613246400000,46871.95000000,46967.07000000,46653.58000000,46934.06000000,1644.41918400,1613249999999,76962780.36939968,67842,788.68050300,36916583.01501596,0 -1613250000000,46934.07000000,47397.36000000,46700.38000000,47130.82000000,2224.29458700,1613253599999,104527195.39377084,75907,1206.90256000,56721826.58286662,0 -1613253600000,47132.94000000,47280.26000000,46863.63000000,47058.88000000,1292.72461900,1613257199999,60850363.11643882,59844,658.48701600,30999765.17969414,0 -1613257200000,47058.88000000,47300.00000000,47001.01000000,47153.69000000,1674.80418200,1613260799999,78990283.69290518,59506,883.55108800,41671352.81289809,0 -1613260800000,47156.78000000,47695.18000000,47014.17000000,47594.52000000,3370.18172200,1613264399999,160032955.65323055,95072,1734.65904500,82366268.62512580,0 -1613264400000,47594.52000000,47730.00000000,47244.88000000,47471.23000000,2800.47480100,1613267999999,132999504.11235503,67516,1710.55626200,81204830.58789642,0 -1613268000000,47475.25000000,47630.00000000,47291.13000000,47378.87000000,2140.96333100,1613271599999,101622478.66020674,57822,1211.58630600,57492350.30306380,0 -1613271600000,47378.87000000,47498.74000000,47204.98000000,47267.21000000,1924.99107300,1613275199999,91249019.54804192,58965,927.09967600,43945003.00081581,0 -1613275200000,47267.20000000,47650.62000000,47220.42000000,47551.25000000,2140.73755600,1613278799999,101552135.18153622,52242,1074.74995400,50989392.76741221,0 -1613278800000,47551.25000000,48948.00000000,47497.39000000,48929.18000000,6249.80455200,1613282399999,301375915.99620004,131926,3706.82603800,178767898.79206442,0 -1613282400000,48929.18000000,49404.94000000,48505.69000000,48745.29000000,7730.20751900,1613285999999,378819096.25902371,160941,4662.70506500,228584464.44144215,0 -1613286000000,48745.28000000,49082.33000000,48520.00000000,48725.18000000,2672.89422700,1613289599999,130304315.88334336,69579,1434.03799200,69918747.44310697,0 -1613289600000,48725.18000000,49018.37000000,48389.55000000,48710.17000000,2764.14148200,1613293199999,134723038.64918590,72737,1302.98777200,63516711.13205439,0 -1613293200000,48710.17000000,49190.00000000,48610.86000000,49134.33000000,2619.21635100,1613296799999,128149093.37750377,77494,1396.10610700,68307128.74014529,0 -1613296800000,49133.33000000,49349.76000000,48956.26000000,49024.21000000,3537.81887900,1613300399999,173925503.24158430,95745,1723.57184000,84747677.06129399,0 -1613300400000,49024.22000000,49139.38000000,48750.59000000,49055.16000000,2377.25319500,1613303999999,116408121.81640217,82683,1258.21308700,61615133.62091801,0 -1613304000000,49055.17000000,49707.43000000,48999.57000000,49436.86000000,5146.83708100,1613307599999,254304722.44098076,151305,2837.71034800,140208067.90938001,0 -1613307600000,49434.05000000,49578.67000000,48550.00000000,48759.63000000,4143.32885900,1613311199999,203312553.42023441,131420,2040.23217900,100115403.51998615,0 -1613311200000,48759.62000000,49069.37000000,48449.76000000,48757.38000000,3279.61955400,1613314799999,160075756.54762092,107053,1583.16150000,77293478.27289885,0 -1613314800000,48757.39000000,48943.47000000,48101.38000000,48541.18000000,3668.24824000,1613318399999,177837037.04234682,112627,1709.34223800,82874968.43423887,0 -1613318400000,48537.96000000,49075.43000000,48424.66000000,49006.74000000,3211.72195400,1613321999999,156577943.29069835,93272,1530.41261100,74629271.28910978,0 -1613322000000,49005.01000000,49100.00000000,48587.00000000,48619.19000000,2166.34239900,1613325599999,105859597.96267876,68456,1094.63271900,53494133.23952528,0 -1613325600000,48619.20000000,48819.29000000,48400.31000000,48739.99000000,2031.32711600,1613329199999,98756144.55389657,62016,907.81514100,44137657.01786330,0 -1613329200000,48739.99000000,48919.86000000,48479.80000000,48693.39000000,1647.87755700,1613332799999,80279379.08039663,72367,807.65119300,39354820.47381999,0 -1613332800000,48693.38000000,49000.00000000,48600.00000000,48929.50000000,1775.36510500,1613336399999,86734312.94108836,63113,894.33528500,43699748.92437283,0 -1613336400000,48929.50000000,49058.74000000,48755.47000000,48822.66000000,1772.35823100,1613339999999,86671621.44494648,54000,883.63964700,43214284.61624973,0 -1613340000000,48822.67000000,49300.00000000,48706.53000000,49012.94000000,1875.45012600,1613343599999,91999378.96832099,85508,1060.56203400,52031437.88633010,0 -1613343600000,49012.94000000,49094.71000000,48505.79000000,48577.79000000,2688.31462300,1613347199999,131238722.76290996,66211,1259.56264200,61501042.96374648,0 -1613347200000,48580.47000000,49010.92000000,48428.00000000,48763.62000000,2016.44349500,1613350799999,98237902.75557831,81903,970.97984000,47312216.92817248,0 -1613350800000,48763.79000000,48816.62000000,47700.00000000,48011.44000000,4889.30019600,1613354399999,235426059.12818572,137267,2002.07846900,96414045.04540308,0 -1613354400000,48011.45000000,48213.83000000,45570.79000000,46874.02000000,11217.85149100,1613357999999,524402408.59355430,293802,4766.42986400,222833708.12581665,0 -1613358000000,46874.01000000,47269.09000000,46540.67000000,47120.30000000,4188.45200300,1613361599999,196816109.46067822,130430,1999.77789900,93986906.83760872,0 -1613361600000,47120.31000000,47136.02000000,46174.78000000,46866.57000000,4963.73452400,1613365199999,231640212.72911710,117265,2555.71418300,119198071.11229076,0 -1613365200000,46866.56000000,47000.00000000,46400.00000000,46722.49000000,2939.43039800,1613368799999,137310368.09635524,80552,1310.16549500,61211676.80102441,0 -1613368800000,46722.48000000,47140.00000000,46683.02000000,46887.36000000,2622.53921200,1613372399999,123158432.47353344,89824,1244.34040700,58439504.94655495,0 -1613372400000,46887.36000000,47441.02000000,46831.61000000,47267.06000000,2861.55980200,1613375999999,135181501.07298136,82240,1418.34999000,66996900.89167774,0 -1613376000000,47270.50000000,47772.00000000,47112.38000000,47599.99000000,2821.99134500,1613379599999,133918267.12457979,77978,1474.81929500,69985910.06565023,0 -1613379600000,47600.00000000,47724.64000000,47201.27000000,47505.66000000,3001.82932500,1613383199999,142576622.11924442,70082,1336.05093400,63455178.90359955,0 -1613383200000,47505.67000000,47888.00000000,47306.02000000,47849.99000000,2326.61287800,1613386799999,110656982.90530200,66156,1225.88465300,58304856.58190226,0 -1613386800000,47849.99000000,47999.00000000,47606.86000000,47802.66000000,2660.67096300,1613390399999,127203238.52893592,74332,1418.00170400,67791449.65179393,0 -1613390400000,47802.67000000,48070.00000000,47423.99000000,47951.01000000,3213.28005900,1613393999999,153304036.36698223,104794,1786.62064300,85274876.78427529,0 -1613394000000,47951.01000000,48219.23000000,47800.00000000,47960.73000000,3089.86453000,1613397599999,148366647.54025140,85788,1552.52546000,74543834.55454221,0 -1613397600000,47963.69000000,48150.62000000,47472.92000000,47564.16000000,3063.76672800,1613401199999,146519643.89369118,95741,1404.41439300,67177057.01943177,0 -1613401200000,47563.58000000,48000.00000000,47536.15000000,47938.83000000,2186.45038100,1613404799999,104527719.43185056,85613,1123.12360200,53693402.18585358,0 -1613404800000,47938.84000000,48570.75000000,47938.83000000,48494.96000000,3853.34875200,1613408399999,186222808.78934653,103731,1884.57664300,91076615.48945923,0 -1613408400000,48494.97000000,48800.00000000,48399.23000000,48562.31000000,2723.91403300,1613411999999,132525799.34526871,76332,1428.76456100,69514104.07326134,0 -1613412000000,48562.31000000,48698.52000000,48342.22000000,48358.99000000,2040.89843400,1613415599999,99038423.24332974,61154,989.97802200,48044410.01409379,0 -1613415600000,48361.00000000,48742.52000000,48354.78000000,48657.31000000,1945.42837200,1613419199999,94501180.34830712,59582,916.64489600,44527266.70598173,0 -1613419200000,48657.31000000,48801.00000000,48453.87000000,48580.99000000,3063.15339900,1613422799999,149075816.14749957,63704,1527.09219800,74328482.70080645,0 -1613422800000,48581.00000000,48750.00000000,48111.11000000,48207.54000000,2767.08275300,1613426399999,134028984.37812317,92043,1369.70711600,66345240.81797496,0 -1613426400000,48201.18000000,48334.23000000,47643.00000000,48284.89000000,2835.28984100,1613429999999,136203912.55939989,121233,1430.73997500,68737085.23889682,0 -1613430000000,48284.90000000,48432.73000000,47809.99000000,47911.10000000,2105.26387000,1613433599999,101375983.63262613,61609,1039.58441900,50058854.30535513,0 -1613433600000,47911.10000000,47958.40000000,47003.62000000,47669.02000000,4446.88263000,1613437199999,211520110.56438769,108138,2122.75194600,100966633.97327281,0 -1613437200000,47669.03000000,48319.33000000,47605.96000000,48305.28000000,2586.10856200,1613440799999,124140059.17193203,67535,1216.07506400,58379943.95026175,0 -1613440800000,48305.28000000,48689.25000000,48160.12000000,48442.06000000,2292.25947100,1613444399999,110969746.49352592,63661,1089.98428200,52782871.21542479,0 -1613444400000,48442.05000000,49670.00000000,48405.11000000,49624.03000000,5795.63915500,1613447999999,285488361.36382928,137535,3567.26065500,175740321.90302698,0 -1613448000000,49624.02000000,49998.00000000,49068.41000000,49350.01000000,5457.71299300,1613451599999,270563379.05828514,122195,3072.70896700,152415970.66421239,0 -1613451600000,49350.01000000,49500.00000000,48969.00000000,49179.03000000,2937.10233400,1613455199999,144638880.08477047,68720,1646.53586000,81086283.97363601,0 -1613455200000,49179.04000000,49234.70000000,48550.00000000,49023.74000000,3291.76102900,1613458799999,160999597.65167020,75160,1568.79066800,76747021.12143053,0 -1613458800000,49020.91000000,49281.81000000,48609.90000000,49163.46000000,2651.26426400,1613462399999,129833533.79377934,69430,1286.37114400,63015986.21663588,0 -1613462400000,49161.75000000,49300.00000000,48871.20000000,49293.26000000,2651.81617900,1613465999999,130244759.29780029,70945,1542.70007700,75782998.80271560,0 -1613466000000,49289.75000000,49318.47000000,48900.00000000,49283.30000000,2177.75779000,1613469599999,106976494.62458385,59616,1187.27631800,58344890.18167947,0 -1613469600000,49283.30000000,49318.47000000,48750.09000000,49020.00000000,2241.00369300,1613473199999,109964695.63731140,59947,1066.06133300,52317017.13588433,0 -1613473200000,49020.00000000,49114.68000000,48700.00000000,48915.48000000,2048.97807800,1613476799999,100241550.94394563,63385,988.91973900,48385685.98339005,0 -1613476800000,48915.49000000,50689.18000000,48403.21000000,49650.01000000,14737.10386500,1613480399999,732384592.48279260,309032,8496.06546800,422705966.11879982,0 -1613480400000,49650.00000000,49826.12000000,48862.99000000,48950.89000000,5108.59246500,1613483999999,251611466.30664461,114976,2372.89496000,116899397.76024331,0 -1613484000000,48950.89000000,49457.00000000,48700.00000000,49289.40000000,4348.89993700,1613487599999,213452078.27008461,110414,2002.83939900,98336603.68360024,0 -1613487600000,49286.80000000,49509.84000000,48935.70000000,48956.91000000,3296.49630900,1613491199999,162347104.02420421,79948,1553.28754100,76503999.81067586,0 -1613491200000,48956.91000000,49291.00000000,48073.00000000,48167.68000000,4643.95192900,1613494799999,226315620.09887102,123288,2097.96977400,102287785.73942366,0 -1613494800000,48165.07000000,48618.60000000,48128.81000000,48230.50000000,3626.44968800,1613498399999,175494885.18182849,91405,1834.78778100,88797433.14423107,0 -1613498400000,48230.63000000,48692.10000000,47750.00000000,48616.79000000,4046.88939600,1613501999999,195127956.52220223,104643,1798.04174900,86746114.81986579,0 -1613502000000,48616.79000000,48800.42000000,48340.14000000,48537.39000000,1898.84599200,1613505599999,92258235.99179017,57825,939.27966900,45638140.85655053,0 -1613505600000,48536.35000000,48784.29000000,48173.81000000,48769.27000000,2584.41782600,1613509199999,125224973.58411438,72638,1170.40579800,56713941.58012348,0 -1613509200000,48769.28000000,48809.09000000,48355.80000000,48575.07000000,2220.45870700,1613512799999,107864262.87435384,59586,983.15925800,47748809.49058261,0 -1613512800000,48575.06000000,49180.00000000,48524.65000000,49108.68000000,1763.41221300,1613516399999,86066130.65612859,55227,976.92044400,47698669.49893138,0 -1613516400000,49113.91000000,49290.00000000,48933.33000000,49133.45000000,1959.46179300,1613519999999,96255303.01353128,54600,1027.51594400,50482117.36375763,0 -1613520000000,49133.45000000,49566.66000000,49034.35000000,49079.99000000,2890.37085800,1613523599999,142739155.81647983,71248,1555.49541700,76827486.69299600,0 -1613523600000,49079.99000000,49417.25000000,48947.00000000,49282.80000000,1693.38424600,1613527199999,83381268.34242158,50936,894.15892400,44030913.38943179,0 -1613527200000,49283.14000000,50274.88000000,49268.42000000,49654.89000000,4959.60353500,1613530799999,247368994.85793249,115010,2814.90641900,140400743.28110094,0 -1613530800000,49657.54000000,49759.46000000,49231.09000000,49657.38000000,2563.13435700,1613534399999,126902933.72016300,71106,1306.00954100,64665779.25825580,0 -1613534400000,49657.84000000,49963.40000000,49106.75000000,49345.38000000,3012.37512700,1613537999999,149086045.25660271,77807,1468.62868400,72710985.70366317,0 -1613538000000,49345.39000000,49731.03000000,49227.68000000,49706.80000000,2239.28153900,1613541599999,110753762.97523999,64527,1004.11886300,49672597.69420271,0 -1613541600000,49706.80000000,50677.58000000,49624.06000000,50556.05000000,6397.97406700,1613545199999,321370364.39629328,147819,3592.32335300,180474031.33095040,0 -1613545200000,50556.15000000,51266.09000000,50200.00000000,51112.39000000,6735.57496700,1613548799999,342035834.26117668,193718,3793.02344700,192682135.76784413,0 -1613548800000,51116.77000000,51300.00000000,50628.58000000,51031.71000000,4279.62119300,1613552399999,217886860.01050137,149891,2251.72981700,114644447.26451840,0 -1613552400000,51031.71000000,51678.36000000,50991.69000000,51431.04000000,5578.73201700,1613555999999,286611008.96667963,162052,3286.03457000,168840616.15725178,0 -1613556000000,51436.11000000,51612.80000000,50995.00000000,51192.00000000,3569.37083300,1613559599999,183265198.81630454,131463,1754.58633900,90096143.57606315,0 -1613559600000,51192.00000000,51675.55000000,51101.07000000,51273.46000000,3178.17850300,1613563199999,163389326.95798126,140591,1725.82996200,88728208.71586878,0 -1613563200000,51270.86000000,51530.00000000,50777.20000000,51039.56000000,4448.57671200,1613566799999,227775681.68139399,137066,2205.98423700,112968102.53606598,0 -1613566800000,51039.56000000,51234.00000000,50542.30000000,51149.96000000,4231.90257000,1613570399999,215340528.89268039,100049,2143.90030700,109100848.01972300,0 -1613570400000,51149.97000000,51284.78000000,50770.82000000,51262.00000000,4229.88726300,1613573999999,215714255.19115635,99421,2185.30842600,111440510.05745384,0 -1613574000000,51262.01000000,51633.17000000,50968.87000000,51169.97000000,3226.68134900,1613577599999,165434598.21261716,90598,1673.88891600,85838931.40725455,0 -1613577600000,51169.97000000,51435.09000000,50780.00000000,51241.35000000,3213.60820100,1613581199999,164123126.33986162,87698,1432.19251200,73147635.88257750,0 -1613581200000,51241.35000000,51436.00000000,51085.95000000,51376.85000000,2383.38491000,1613584799999,122173286.38895154,70006,1248.79755800,64017785.26346042,0 -1613584800000,51380.78000000,51780.00000000,51304.96000000,51430.59000000,2455.34674600,1613588399999,126498176.77004941,73853,1417.98176100,73061493.41716664,0 -1613588400000,51430.59000000,52395.00000000,51374.56000000,52142.35000000,4887.84160900,1613591999999,254172782.78805094,119808,2674.02247500,139072940.34043922,0 -1613592000000,52142.36000000,52546.00000000,51956.82000000,52240.00000000,3160.98879700,1613595599999,165159364.15775175,101344,1673.49947700,87431344.98006769,0 -1613595600000,52239.99000000,52618.74000000,52021.37000000,52349.99000000,2544.38664700,1613599199999,133129592.23551998,111942,1217.13865500,63694297.65795707,0 -1613599200000,52349.99000000,52381.20000000,51893.34000000,52104.43000000,1961.28032700,1613602799999,102283994.68977260,66116,794.14230000,41419168.94664244,0 -1613602800000,52104.44000000,52397.84000000,51899.64000000,52119.71000000,1902.15144500,1613606399999,99235373.08971611,80305,941.74428100,49132087.93906716,0 -1613606400000,52117.67000000,52530.00000000,52104.69000000,52267.32000000,2415.71188100,1613609999999,126462808.59351453,68990,1184.67427600,62020150.22809579,0 -1613610000000,52263.85000000,52383.42000000,52026.06000000,52132.46000000,3038.62669900,1613613599999,158563091.46887272,83050,1497.39017600,78141903.88477890,0 -1613613600000,52132.47000000,52340.01000000,51933.24000000,52318.89000000,2290.19600500,1613617199999,119421691.26987759,79558,1076.65023200,56149947.94241353,0 -1613617200000,52318.89000000,52399.73000000,51951.00000000,52032.64000000,1876.43842400,1613620799999,97826861.30463848,70318,795.66203000,41494969.72859426,0 -1613620800000,52032.64000000,52180.00000000,51712.50000000,52153.36000000,2402.28846800,1613624399999,124762052.22122244,96640,1167.56278400,60643202.97179693,0 -1613624400000,52153.36000000,52298.00000000,52015.68000000,52170.01000000,1777.76259300,1613627999999,92719155.23415250,66549,833.81447800,43490476.29551979,0 -1613628000000,52170.02000000,52237.45000000,51862.78000000,51905.66000000,1952.33030800,1613631599999,101615004.47725443,53661,921.28408400,47950239.42759454,0 -1613631600000,51905.65000000,52085.85000000,51295.00000000,51901.96000000,4482.23840700,1613635199999,231492219.32012465,104998,2082.11648600,107551721.11270122,0 -1613635200000,51901.95000000,52168.75000000,51542.32000000,51706.88000000,2314.54402300,1613638799999,119941863.11582020,102125,1221.34767500,63298289.53003857,0 -1613638800000,51706.87000000,51873.41000000,51459.82000000,51770.99000000,2754.16149000,1613642399999,142340212.09189810,72873,1209.01340100,62464981.94171498,0 -1613642400000,51772.82000000,52000.00000000,51529.20000000,51643.50000000,2180.56772900,1613645999999,112913519.80171945,62181,1050.33611300,54397716.66662668,0 -1613646000000,51643.49000000,51720.32000000,51133.00000000,51374.07000000,3329.97338200,1613649599999,171274319.05293026,87957,1690.23063800,86927479.69519652,0 -1613649600000,51375.12000000,51623.37000000,50901.90000000,51464.66000000,3689.59965300,1613653199999,189054669.44080802,139022,1548.14890500,79378801.25721558,0 -1613653200000,51464.67000000,52025.00000000,51262.43000000,51796.24000000,3004.84490300,1613656799999,155300530.92317071,101151,1397.34176400,72231807.92522654,0 -1613656800000,51796.24000000,52285.00000000,51613.23000000,52233.43000000,2980.96917900,1613660399999,154938085.17949990,97995,1450.31815300,75397809.46952058,0 -1613660400000,52233.43000000,52260.00000000,51450.00000000,51585.29000000,3418.73399100,1613663999999,176937329.82928261,87026,1656.39480100,85726936.09436358,0 -1613664000000,51585.29000000,52099.00000000,51450.00000000,52091.02000000,2524.31891600,1613667599999,130884579.77739727,73116,1296.25971200,67212387.09674489,0 -1613667600000,52091.03000000,52100.00000000,51777.00000000,51839.55000000,2163.57531900,1613671199999,112371921.92356896,67551,1053.74030700,54728472.25750906,0 -1613671200000,51839.56000000,52177.75000000,51764.16000000,51862.85000000,2028.77431800,1613674799999,105496043.67767959,63518,1060.93505400,55166552.56671546,0 -1613674800000,51860.40000000,52070.68000000,51685.00000000,51760.01000000,1593.36591800,1613678399999,82699893.18919559,55280,784.05700800,40700741.13264565,0 -1613678400000,51760.01000000,52115.92000000,51514.26000000,52111.89000000,2609.19452600,1613681999999,135456895.07548493,72923,1178.50074600,61185198.08094893,0 -1613682000000,52111.89000000,52195.12000000,51892.20000000,52007.21000000,2176.64281700,1613685599999,113327558.51274466,64911,1055.36463900,54943569.74469788,0 -1613685600000,52005.08000000,52075.07000000,51615.01000000,51837.19000000,1724.94218000,1613689199999,89417272.03740988,59893,738.00623000,38254993.28968866,0 -1613689200000,51837.18000000,51920.51000000,51510.00000000,51552.60000000,2028.24582500,1613692799999,104755499.96919844,60306,944.20893100,48773287.50356038,0 -1613692800000,51552.61000000,51943.99000000,51452.00000000,51511.33000000,2713.99459100,1613696399999,140325236.14208726,73812,1277.91639000,66079407.67949208,0 -1613696400000,51512.62000000,51700.99000000,51165.88000000,51325.44000000,2620.93680300,1613699999999,134749623.27586721,77935,1180.17216100,60691482.33635172,0 -1613700000000,51325.44000000,51339.05000000,50710.20000000,51248.52000000,3846.48439000,1613703599999,196444482.96142958,99919,1697.42806300,86704110.90889451,0 -1613703600000,51248.53000000,51500.15000000,51200.00000000,51245.00000000,1787.93614700,1613707199999,91806401.12800927,51393,884.10881500,45394334.76811912,0 -1613707200000,51247.86000000,51530.56000000,50918.00000000,51166.30000000,1969.38099200,1613710799999,100815563.36062377,55063,964.02333400,49359592.08224309,0 -1613710800000,51166.29000000,51567.26000000,51166.29000000,51524.05000000,2079.78925000,1613714399999,106871810.17193274,58451,1079.43239300,55471459.87239495,0 -1613714400000,51524.06000000,51822.96000000,51517.16000000,51734.88000000,2693.88085800,1613717999999,139210203.26247520,98332,1411.00572300,72920017.03868398,0 -1613718000000,51734.87000000,51894.77000000,51654.57000000,51727.08000000,2224.77573300,1613721599999,115164269.58954758,90363,1170.60600200,60593865.41858441,0 -1613721600000,51727.09000000,52293.77000000,51649.82000000,52236.31000000,2775.40234700,1613725199999,144118630.72947438,112827,1599.56171400,83091994.11254978,0 -1613725200000,52236.31000000,52965.31000000,52218.62000000,52690.70000000,5901.16645800,1613728799999,310796784.20453511,149725,3320.32334000,174853654.51923500,0 -1613728800000,52690.75000000,52984.99000000,52625.00000000,52687.60000000,2635.22912700,1613732399999,139156643.20101719,89427,1364.59362200,72066017.08383998,0 -1613732400000,52685.98000000,52863.19000000,52485.95000000,52710.00000000,2380.09901500,1613735999999,125517764.46963318,77057,1208.92392000,63759654.75650406,0 -1613736000000,52709.99000000,52729.75000000,52400.09000000,52534.75000000,2360.66813300,1613739599999,124206180.92702526,103686,1155.50898000,60803591.81707465,0 -1613739600000,52534.76000000,52850.00000000,52315.37000000,52800.04000000,2831.21696500,1613743199999,148967037.12173166,85835,1444.86362700,76032822.29639958,0 -1613743200000,52800.03000000,53280.00000000,52653.93000000,52890.00000000,3789.65655000,1613746799999,200676344.41197990,104574,1912.94928500,101312292.85425075,0 -1613746800000,52877.10000000,53886.07000000,52810.11000000,53863.19000000,5187.73271900,1613750399999,277195452.06437244,123877,2656.18740200,141945314.86494440,0 -1613750400000,53863.82000000,54850.00000000,53605.58000000,54368.65000000,6521.08734300,1613753999999,353986874.90433082,156593,3288.78566800,178412524.08597555,0 -1613754000000,54368.61000000,54766.34000000,54054.00000000,54765.49000000,2446.44460700,1613757599999,133286273.95126311,75913,1177.15246600,64134875.67038222,0 -1613757600000,54765.50000000,55435.96000000,54525.11000000,55384.46000000,2849.83242300,1613761199999,156724151.03477345,69618,1641.45848500,90288653.98634405,0 -1613761200000,55384.46000000,55843.78000000,54583.95000000,54990.01000000,5529.09411400,1613764799999,304068964.59181108,146628,3009.86819600,165517149.87116405,0 -1613764800000,54994.85000000,55698.16000000,54800.00000000,55348.33000000,3733.04848500,1613768399999,206292559.74413172,115558,1851.22754800,102289448.68597726,0 -1613768400000,55345.17000000,56368.00000000,55304.52000000,55651.16000000,5011.99036400,1613771999999,280151757.43058394,146559,2540.36048100,142019526.27173952,0 -1613772000000,55651.16000000,55767.29000000,55130.00000000,55426.40000000,3226.95406900,1613775599999,178971150.41723793,99522,1480.46710800,82104873.17686108,0 -1613775600000,55426.40000000,55950.00000000,55330.00000000,55906.00000000,2542.97653700,1613779199999,141663668.58837266,76548,1239.09552300,69024646.06593565,0 -1613779200000,55906.00000000,56500.00000000,55322.00000000,56226.73000000,5639.85206300,1613782799999,315580909.79922147,139690,2957.74432200,165522858.02641096,0 -1613782800000,56223.44000000,56609.14000000,55946.27000000,56179.17000000,3867.21968100,1613786399999,217600207.67930692,110107,1956.80718900,110112112.46941631,0 -1613786400000,56179.16000000,56395.00000000,55959.41000000,56143.46000000,2927.80920200,1613789999999,164594593.35020089,101379,1367.09183000,76865833.70079412,0 -1613790000000,56143.46000000,56250.00000000,55481.38000000,55706.07000000,2837.35212900,1613793599999,158565110.54746008,107593,1399.96603400,78247337.88213564,0 -1613793600000,55711.90000000,56144.87000000,55511.00000000,55815.19000000,1943.94171300,1613797199999,108608963.33222419,61115,971.01848200,54257440.03207530,0 -1613797200000,55815.19000000,55952.18000000,55555.55000000,55675.43000000,1876.99088600,1613800799999,104616251.66430172,94387,842.85798600,46985070.93292468,0 -1613800800000,55675.44000000,55952.88000000,55580.00000000,55937.12000000,1688.23270000,1613804399999,94196751.80932634,60030,858.00379800,47874150.83791051,0 -1613804400000,55937.02000000,55967.14000000,55185.98000000,55207.92000000,3179.75022900,1613807999999,176654915.35822290,83321,1482.63226400,82383749.90358093,0 -1613808000000,55207.93000000,55674.68000000,55185.16000000,55236.53000000,2266.72007200,1613811599999,125623432.56659793,123216,1109.72949900,61506912.30132833,0 -1613811600000,55236.54000000,55525.00000000,55030.00000000,55252.40000000,2534.56658600,1613815199999,140183539.19055306,115629,1267.49834900,70106264.42073112,0 -1613815200000,55252.40000000,55929.23000000,55210.53000000,55895.31000000,2330.74195200,1613818799999,129723444.86482127,71009,1196.60800300,66591499.28420447,0 -1613818800000,55895.31000000,56388.37000000,55752.77000000,56355.91000000,2787.34971200,1613822399999,155931507.43980731,77103,1370.90644100,76720072.86851603,0 -1613822400000,56355.94000000,57700.46000000,56268.01000000,57291.92000000,6646.36125500,1613825999999,379343463.92682278,167002,2945.25839000,167994072.82411004,0 -1613826000000,57291.93000000,57550.00000000,56923.04000000,57274.34000000,3515.23980700,1613829599999,201257726.46089098,129782,1745.62097000,99946792.89291828,0 -1613829600000,57274.35000000,57426.57000000,56080.00000000,56280.83000000,4268.77802300,1613833199999,243081284.26698700,121978,2083.74691900,118700258.45525395,0 -1613833200000,56280.83000000,56759.99000000,55722.11000000,56145.97000000,5099.63497900,1613836799999,286778901.86173186,170299,2379.84257000,133831357.21577137,0 -1613836800000,56136.55000000,56943.60000000,56136.55000000,56720.16000000,3717.38436700,1613840399999,210031148.92345144,144866,1722.49894600,97326270.53841969,0 -1613840400000,56720.17000000,57425.00000000,56713.79000000,57048.35000000,4217.72333900,1613843999999,240931598.98318140,134869,1947.70969500,111267847.46584215,0 -1613844000000,57048.35000000,57152.33000000,56800.01000000,57115.24000000,1840.03131000,1613847599999,104893005.61052269,73385,954.07713100,54389820.50943438,0 -1613847600000,57118.09000000,57234.48000000,56709.23000000,56975.12000000,1864.07048000,1613851199999,106178555.91371001,79787,919.41331500,52370693.25698575,0 -1613851200000,56975.12000000,57050.00000000,56562.51000000,56719.52000000,2039.86527000,1613854799999,115803725.90370444,66950,980.29465800,55654794.27561605,0 -1613854800000,56719.52000000,56878.28000000,56250.66000000,56472.13000000,2361.84010600,1613858399999,133665925.43983636,70121,1178.71298000,66716850.38525542,0 -1613858400000,56472.13000000,56495.33000000,53863.93000000,55423.99000000,7721.82236500,1613861999999,427670179.98369899,229383,3261.29413700,180656146.92911081,0 -1613862000000,55424.00000000,56191.43000000,55378.02000000,55841.19000000,3774.92708800,1613865599999,210375714.97469261,109845,1736.73236600,96805671.03221858,0 -1613865600000,55841.19000000,56061.64000000,55477.59000000,55834.95000000,2949.77756100,1613869199999,164492362.88754974,84284,1567.96922000,87449093.15253602,0 -1613869200000,55834.95000000,56351.08000000,55717.87000000,56347.69000000,2125.26328800,1613872799999,119014770.77697408,70496,1075.38780300,60228584.99549423,0 -1613872800000,56347.70000000,56660.94000000,56253.77000000,56318.08000000,2201.03164900,1613876399999,124306784.48488625,60339,1103.50273900,62317358.21959931,0 -1613876400000,56318.08000000,56900.00000000,56311.40000000,56505.22000000,2027.22019700,1613879999999,114735892.16174038,58188,1149.97872000,65093136.83821802,0 -1613880000000,56505.22000000,56725.12000000,56040.31000000,56701.08000000,2060.64233700,1613883599999,116297497.07284269,58464,1062.28469700,59954099.29038342,0 -1613883600000,56701.08000000,56959.71000000,56511.54000000,56545.13000000,2041.76479100,1613887199999,115814774.95798891,52225,917.48546300,52041831.40677734,0 -1613887200000,56545.12000000,56609.46000000,56250.00000000,56493.23000000,1604.42588500,1613890799999,90577328.06397415,56614,752.11336700,42463469.43576441,0 -1613890800000,56493.22000000,56594.23000000,55863.54000000,56091.76000000,2600.75351900,1613894399999,146223148.22796013,72120,1269.80374400,71395366.24749209,0 -1613894400000,56092.02000000,56676.70000000,55821.03000000,56513.22000000,2357.26255600,1613897999999,132614264.62652807,68592,1197.62047500,67393178.59409487,0 -1613898000000,56513.21000000,56845.90000000,56364.65000000,56795.81000000,1801.28886800,1613901599999,101801688.89236490,61188,939.18785100,53077127.37936225,0 -1613901600000,56795.81000000,57827.00000000,56657.96000000,57560.00000000,4162.46381100,1613905199999,239049955.88924410,119544,2387.90028500,137110975.22207403,0 -1613905200000,57560.00000000,57570.94000000,57200.00000000,57284.79000000,2690.83005000,1613908799999,154331132.25970184,75626,1599.03421000,91702070.55597467,0 -1613908800000,57284.78000000,57440.82000000,56589.00000000,56888.80000000,2904.91437000,1613912399999,165858686.62890997,85031,1712.70506900,97820928.28773681,0 -1613912400000,56888.81000000,57220.00000000,56888.79000000,57154.19000000,1979.23846400,1613915999999,112975449.21178608,89259,891.56690100,50893748.72844281,0 -1613916000000,57154.19000000,57449.00000000,56783.33000000,57381.13000000,2751.79923100,1613919599999,157416712.46221265,80003,1276.31932100,73018095.70725041,0 -1613919600000,57381.12000000,57555.00000000,57165.40000000,57313.99000000,2657.73107500,1613923199999,152476065.18503597,124088,1300.65590200,74627514.63854968,0 -1613923200000,57313.99000000,57782.00000000,57006.16000000,57733.96000000,2772.77107900,1613926799999,159262145.61400902,116379,1338.48329200,76890547.27388531,0 -1613926800000,57733.95000000,57749.82000000,57356.53000000,57499.01000000,1895.34702700,1613930399999,109165561.47905982,71673,899.25412700,51792489.75834086,0 -1613930400000,57499.02000000,58300.00000000,57333.79000000,58183.69000000,2708.74612400,1613933999999,156704543.25729914,119447,1533.09588400,88720683.24901281,0 -1613934000000,58183.69000000,58352.80000000,57916.66000000,58072.62000000,2656.04312300,1613937599999,154497112.99673591,80188,1256.41617400,73085956.47884253,0 -1613937600000,58072.62000000,58247.84000000,57458.15000000,57654.80000000,2454.89171800,1613941199999,142135184.40035702,89127,1154.67616300,66858169.40086438,0 -1613941200000,57657.10000000,57900.00000000,57180.00000000,57293.53000000,2438.14225000,1613944799999,140356109.44497323,84682,1122.74916100,64646612.45708931,0 -1613944800000,57293.52000000,57616.34000000,56935.03000000,57328.47000000,2198.42742300,1613948399999,125844765.70797286,113697,1043.31190500,59724900.74080561,0 -1613948400000,57328.46000000,57590.05000000,57100.00000000,57408.57000000,2125.93211500,1613951999999,122046326.65778230,59279,954.58661200,54801150.09877834,0 -1613952000000,57412.35000000,57508.47000000,56230.84000000,56235.15000000,4513.74034200,1613955599999,256206476.92647041,101603,2052.93015500,116527941.85630910,0 -1613955600000,56235.15000000,57000.00000000,56013.13000000,56860.04000000,3425.03640300,1613959199999,194048532.20100081,131706,1687.57100000,95610108.82367427,0 -1613959200000,56860.04000000,57277.99000000,55351.15000000,56855.12000000,4511.02871100,1613962799999,254949389.91415914,102202,2217.52420900,125342467.22338429,0 -1613962800000,56855.13000000,57078.50000000,55757.58000000,55860.12000000,2876.05652800,1613966399999,162014342.49408319,107178,1400.27272900,78908418.38414442,0 -1613966400000,55858.99000000,56258.49000000,55102.77000000,55786.36000000,4117.07045800,1613969999999,229089676.70647494,107816,1812.86382600,100869406.52186817,0 -1613970000000,55785.61000000,56372.01000000,55625.11000000,55869.15000000,2634.16909100,1613973599999,147463057.07817703,83020,1185.58001100,66366349.12047309,0 -1613973600000,55869.16000000,56377.00000000,55684.74000000,55989.36000000,2101.70438100,1613977199999,117982728.62770379,73328,1086.16914200,60976053.84114737,0 -1613977200000,55989.35000000,56550.00000000,55652.45000000,56422.92000000,2595.91051900,1613980799999,145788942.68097489,72550,1247.08029300,70045210.06757610,0 -1613980800000,56422.23000000,56623.69000000,55408.92000000,55480.80000000,4285.43355200,1613984399999,239939231.56158729,85723,1844.93513200,103362861.28565440,0 -1613984400000,55480.80000000,55800.00000000,54355.00000000,54766.39000000,5226.54351400,1613987999999,288464821.34418318,122713,2507.17848000,138510621.77047116,0 -1613988000000,54747.23000000,55101.69000000,53505.70000000,54847.72000000,8059.54495200,1613991599999,438974088.46219304,184557,3812.06418000,207693324.36044736,0 -1613991600000,54847.72000000,55251.79000000,54403.11000000,54524.94000000,4098.26864800,1613995199999,225014641.37038058,111831,1937.00577200,106318273.85508172,0 -1613995200000,54515.00000000,54695.66000000,52628.90000000,53781.12000000,10930.65063700,1613998799999,585168995.14976690,238630,5133.96507200,274790620.59419257,0 -1613998800000,53784.14000000,54062.77000000,52050.00000000,52070.47000000,8203.24906400,1614002399999,434668374.13266490,185091,4008.41171000,212584375.41294594,0 -1614002400000,52066.99000000,53654.37000000,47622.00000000,53478.83000000,24477.79279200,1614005999999,1252120246.31738026,508500,11859.23979000,606836411.55804317,0 -1614006000000,53472.69000000,53993.00000000,52483.39000000,53236.69000000,11024.95969200,1614009599999,588440597.71152324,267399,4644.85426600,247758483.42495487,0 -1614009600000,53236.69000000,53847.56000000,52730.00000000,53180.05000000,5464.14551800,1614013199999,291577112.37865897,153293,2558.14367500,136554777.21755541,0 -1614013200000,53177.82000000,53302.59000000,51955.65000000,52100.00000000,4675.17425200,1614016799999,246033067.08975183,124241,2258.17834000,118830414.26901206,0 -1614016800000,52100.00000000,53490.00000000,51570.00000000,53227.23000000,5492.27131500,1614020399999,288540225.07433704,138584,2571.49882000,135020716.48823552,0 -1614020400000,53227.23000000,53746.29000000,52942.33000000,53581.69000000,2709.39250800,1614023999999,144745202.52390016,81259,1240.42562800,66276641.32370668,0 -1614024000000,53587.41000000,54364.00000000,53452.51000000,53771.34000000,3461.08948600,1614027599999,187077759.39328225,93144,1743.12562700,94207575.36040389,0 -1614027600000,53779.38000000,54900.00000000,53667.72000000,54883.16000000,2928.49419700,1614031199999,159285168.52561068,81059,1528.69787400,83133656.64893852,0 -1614031200000,54883.16000000,54989.46000000,53782.09000000,54084.97000000,2862.15708100,1614034799999,155579306.49037132,85407,1491.61936500,81048353.69973041,0 -1614034800000,54084.97000000,54373.32000000,53279.02000000,54087.67000000,3345.55130300,1614038399999,180214736.28216198,72249,1848.32688300,99644091.41302238,0 -1614038400000,54087.67000000,54183.59000000,53018.54000000,53440.66000000,2943.36896500,1614041999999,157532202.95411356,107377,1463.66931400,78334979.37420292,0 -1614042000000,53431.44000000,53925.86000000,52281.88000000,52546.18000000,3132.59441600,1614045599999,165831902.16947045,83399,1571.23029700,83164230.74900639,0 -1614045600000,52546.59000000,52887.66000000,50901.00000000,51218.63000000,5963.50597500,1614049199999,309284577.51721979,157353,2965.01472600,153869619.32416301,0 -1614049200000,51218.75000000,52496.90000000,51153.33000000,51906.36000000,5642.99707000,1614052799999,292785084.71039049,139770,2790.72713500,144781100.80713279,0 -1614052800000,51900.73000000,52311.71000000,49600.00000000,50754.50000000,6698.05728500,1614056399999,340983951.87896339,150863,2904.19675200,148035992.07803085,0 -1614056400000,50754.50000000,50755.48000000,48615.00000000,49950.00000000,10951.85598400,1614059999999,544401197.91319265,229947,4974.20165700,247273966.34705154,0 -1614060000000,49952.49000000,51241.99000000,49380.14000000,49547.02000000,6064.54940400,1614063599999,305207167.88787803,133354,3082.08275600,155117465.41686265,0 -1614063600000,49544.58000000,50547.30000000,49288.94000000,49640.33000000,4936.85373500,1614067199999,246714261.69089670,109379,2392.57052700,119574223.45067150,0 -1614067200000,49642.92000000,50027.01000000,46560.00000000,46565.18000000,15751.17067700,1614070799999,758815141.17923971,312940,6948.96769600,334957181.75485304,0 -1614070800000,46562.33000000,48695.75000000,45000.00000000,48075.45000000,17379.42280400,1614074399999,821119205.83081268,368112,8358.22422300,395536539.20981648,0 -1614074400000,48072.01000000,48979.17000000,46568.00000000,47546.01000000,8447.62229800,1614077999999,402870433.97213644,193960,4140.71415200,197483399.16148375,0 -1614078000000,47531.15000000,48275.74000000,44892.56000000,46369.29000000,12372.25443300,1614081599999,572863947.25727364,242476,5839.99678400,270527141.22070734,0 -1614081600000,46359.14000000,49455.53000000,45788.10000000,48670.21000000,13248.95882000,1614085199999,629347433.60642503,259976,6898.84650700,327806976.86841776,0 -1614085200000,48670.54000000,49600.00000000,48032.17000000,48750.00000000,7741.58941200,1614088799999,377614079.11806758,172266,4023.14235200,196254720.55646505,0 -1614088800000,48754.47000000,49141.89000000,45838.84000000,46978.18000000,7605.54125100,1614092399999,360869163.70869394,191730,3632.63684400,172532576.02962880,0 -1614092400000,46977.89000000,49350.00000000,46635.00000000,48602.03000000,7893.56502000,1614095999999,381359810.37807281,186256,4125.87428200,199476492.49976093,0 -1614096000000,48602.02000000,49247.69000000,47230.01000000,47365.61000000,5789.95500800,1614099599999,278323778.57237520,127453,2681.22027300,129036576.21017609,0 -1614099600000,47361.41000000,48197.74000000,46888.00000000,47175.27000000,3541.70158500,1614103199999,168002549.47439544,94047,1758.35548200,83426686.47410004,0 -1614103200000,47163.74000000,47777.00000000,46501.34000000,46881.49000000,3767.75261800,1614106799999,177599282.14800305,100101,1842.67491100,86936002.82502872,0 -1614106800000,46872.77000000,47291.03000000,45500.00000000,45523.00000000,4845.94891300,1614110399999,224281371.84178197,120852,2209.35751900,102293371.28860546,0 -1614110400000,45523.02000000,47820.00000000,45251.00000000,47814.50000000,4719.43409900,1614113999999,220303390.69267214,113735,2429.29030800,113559842.78994764,0 -1614114000000,47812.80000000,48474.31000000,47400.70000000,47937.33000000,4237.63139600,1614117599999,203749279.92999366,95017,2468.49531300,118729321.24352526,0 -1614117600000,47930.44000000,48756.00000000,47738.82000000,48589.69000000,3213.00765300,1614121199999,155350590.03150539,74216,1710.03929700,82702263.28772867,0 -1614121200000,48597.19000000,48938.85000000,48124.51000000,48891.00000000,2485.68623000,1614124799999,120629326.77981200,60617,1252.61388500,60784623.12998936,0 -1614124800000,48891.00000000,49100.00000000,46988.69000000,48456.58000000,4847.53073600,1614128399999,232076690.35418094,113148,2353.74857500,112801918.33755374,0 -1614128400000,48456.58000000,50225.22000000,48419.48000000,50191.60000000,5367.92410400,1614131999999,264734974.10829012,116620,2863.56549200,141251223.84913265,0 -1614132000000,50191.68000000,50553.33000000,49803.00000000,50160.42000000,3962.03444500,1614135599999,198889484.54245099,101287,1961.74069800,98491365.70161724,0 -1614135600000,50160.21000000,50993.57000000,50025.01000000,50874.99000000,3145.82980800,1614139199999,158803323.04548693,79857,1666.77630900,84155964.55322895,0 -1614139200000,50869.77000000,51357.00000000,50327.35000000,50617.29000000,4569.37934100,1614142799999,232438416.79339211,109519,2570.52035500,130768549.11077603,0 -1614142800000,50619.83000000,51044.22000000,50000.00000000,50247.40000000,3407.58076900,1614146399999,171886820.25996955,84827,1810.31364600,91331452.56812189,0 -1614146400000,50247.61000000,50719.78000000,49456.00000000,50109.21000000,4666.11847000,1614149999999,233390526.45703587,109361,2366.15574100,118348580.97282154,0 -1614150000000,50109.20000000,50368.40000000,49530.43000000,50090.57000000,3036.97920300,1614153599999,151776782.27984239,78641,1584.03485200,79184469.31195800,0 -1614153600000,50090.61000000,50886.20000000,49799.29000000,50634.36000000,3931.00620100,1614157199999,198647202.83939082,102253,1954.68993800,98774033.09842807,0 -1614157200000,50634.32000000,51374.99000000,50306.12000000,50847.51000000,4804.82076900,1614160799999,244207904.89909110,115218,2495.37209800,126760609.55484541,0 -1614160800000,50847.50000000,51000.00000000,50033.52000000,50075.00000000,3196.21238900,1614164399999,161464416.54413845,92558,1504.95120500,76053703.29705312,0 -1614164400000,50075.00000000,50875.00000000,50049.15000000,50360.02000000,2831.80462200,1614167999999,142887063.44259436,82887,1430.93015000,72212300.17751500,0 -1614168000000,50360.02000000,51294.00000000,50326.81000000,50739.94000000,4538.97781000,1614171599999,230946348.07511860,102495,2106.56547500,107201169.34209975,0 -1614171600000,50738.27000000,51060.00000000,49056.33000000,49481.61000000,7310.45414800,1614175199999,363938756.12032670,152980,3406.18825800,169502557.32618663,0 -1614175200000,49469.19000000,49777.00000000,48758.00000000,49404.04000000,4794.06506400,1614178799999,236323203.72922684,99104,2365.99498000,116665506.76388923,0 -1614178800000,49404.62000000,49850.00000000,48450.00000000,49819.50000000,4685.05192800,1614182399999,230450785.30372679,105383,2398.34043600,118032165.63465616,0 -1614182400000,49819.49000000,50150.00000000,49160.00000000,49308.28000000,3788.49869500,1614185999999,188185982.84580416,80231,1918.82606000,95330349.09763051,0 -1614186000000,49308.29000000,50060.31000000,49303.56000000,50041.80000000,2368.46736800,1614189599999,117885039.87187039,62024,1207.15248900,60083975.40984697,0 -1614189600000,50046.03000000,50052.18000000,49465.15000000,49570.00000000,2338.30656600,1614193199999,116311162.40909255,55934,1071.79336200,53314935.44764492,0 -1614193200000,49570.00000000,49690.15000000,48811.26000000,48959.93000000,2856.47685000,1614196799999,140540872.27822315,63481,1377.77991800,67775581.68214042,0 -1614196800000,48959.93000000,49266.39000000,48581.26000000,49101.18000000,2532.66408700,1614200399999,123860543.18299560,65161,1201.33183700,58743856.60865807,0 -1614200400000,49101.18000000,49150.00000000,48090.00000000,48707.72000000,3651.36623600,1614203999999,176954151.28704662,82126,1747.74613500,84724951.63964196,0 -1614204000000,48715.97000000,48950.00000000,48028.18000000,48811.63000000,2341.05845900,1614207599999,113682228.47331085,69019,1035.68505500,50305302.55720192,0 -1614207600000,48811.63000000,49747.49000000,48722.71000000,49676.20000000,2908.60118400,1614211199999,143750322.23693025,70418,1350.51176700,66752084.09569870,0 -1614211200000,49676.21000000,50865.00000000,49517.01000000,50507.25000000,3530.40346200,1614214799999,177315058.26818629,87157,1865.29052100,93677845.27793823,0 -1614214800000,50507.24000000,50884.88000000,50357.14000000,50504.71000000,2197.13675300,1614218399999,111268572.08912711,53310,1189.00936000,60218195.43755632,0 -1614218400000,50505.26000000,50834.43000000,50421.36000000,50650.95000000,1895.03724200,1614221999999,96020905.95990301,47719,975.19348400,49414002.72529453,0 -1614222000000,50650.95000000,50659.77000000,50033.94000000,50206.97000000,1947.21850800,1614225599999,97997520.78394554,52519,973.23221100,48974935.56632615,0 -1614225600000,50206.97000000,50366.67000000,49567.89000000,49627.34000000,2531.01652400,1614229199999,126596464.51532776,55577,1271.09020400,63579920.34369894,0 -1614229200000,49626.90000000,50449.07000000,49533.44000000,50388.60000000,2489.27614500,1614232799999,124308971.42079986,63601,1312.36198100,65532875.49801985,0 -1614232800000,50391.10000000,50568.97000000,50212.79000000,50453.54000000,1878.14184600,1614236399999,94672068.91718432,71321,936.38339600,47201518.69036245,0 -1614236400000,50453.54000000,50559.51000000,50105.71000000,50395.99000000,1945.51267000,1614239999999,98085710.90143531,55250,987.33240300,49783416.60237040,0 -1614240000000,50395.58000000,50513.35000000,49534.90000000,49700.00000000,2853.46848600,1614243599999,142708611.69016401,73044,1442.17472000,72134777.56929014,0 -1614243600000,49700.01000000,49840.60000000,48581.71000000,48977.03000000,4454.01146200,1614247199999,218864240.01879811,109551,2159.84100800,106137032.63691128,0 -1614247200000,48977.03000000,49729.52000000,48812.92000000,49551.51000000,2744.27976000,1614250799999,135270333.22223811,108491,1409.13453800,69471930.39275963,0 -1614250800000,49551.51000000,50403.14000000,49551.51000000,50294.80000000,3076.06333800,1614254399999,153555644.49355980,104662,1581.69123500,78976835.05466704,0 -1614254400000,50299.00000000,51500.00000000,50077.00000000,51487.06000000,5006.69196500,1614257999999,253928753.62570436,142209,2750.04184000,139510873.31588941,0 -1614258000000,51497.98000000,52041.73000000,51060.27000000,51347.60000000,6437.20928400,1614261599999,331813816.68325372,156703,3305.41176100,170455329.85337949,0 -1614261600000,51351.93000000,51530.00000000,50599.00000000,50830.88000000,3602.68247200,1614265199999,184076620.86842276,96270,1629.94566600,83315760.62943449,0 -1614265200000,50830.60000000,51367.61000000,50480.00000000,50849.99000000,3311.82255800,1614268799999,168638000.41787461,102306,1540.15706900,78411652.12854003,0 -1614268800000,50850.00000000,51370.18000000,50563.82000000,50630.66000000,3186.56373600,1614272399999,162452252.98783745,100933,1528.30413100,77914098.04088617,0 -1614272400000,50632.85000000,50665.78000000,49306.91000000,49550.95000000,4625.13316200,1614275999999,231011634.46842033,109813,2024.93443000,101143499.45406222,0 -1614276000000,49550.96000000,50086.28000000,49226.09000000,49544.14000000,3513.02183800,1614279599999,174509030.04080191,96606,1739.77401000,86434357.97169301,0 -1614279600000,49543.04000000,50000.00000000,49262.29000000,49443.86000000,2583.92601300,1614283199999,128220155.52403962,110202,1288.11088100,63926257.90612366,0 -1614283200000,49442.20000000,49550.01000000,48529.47000000,49152.75000000,4249.67515800,1614286799999,208126020.37474209,123297,1950.51150400,95521642.40626772,0 -1614286800000,49151.36000000,49300.00000000,48051.00000000,48101.99000000,3634.64330500,1614290399999,177026810.91773268,101460,1592.40149400,77619066.20353466,0 -1614290400000,48102.01000000,48900.00000000,47471.00000000,48235.85000000,5670.50516700,1614293999999,272928468.09759038,152785,2249.08470900,108297095.79279770,0 -1614294000000,48229.63000000,48463.27000000,46674.34000000,47073.73000000,5947.23226700,1614297599999,282793061.85452555,130893,2909.25220300,138415598.14855837,0 -1614297600000,47073.73000000,47613.50000000,46000.00000000,46801.05000000,8103.39317700,1614301199999,377831011.56882769,172768,3825.35259500,178444800.91619932,0 -1614301200000,46807.84000000,47479.06000000,46240.84000000,46480.48000000,6203.21910400,1614304799999,290755125.08169801,136879,2797.08898300,131130552.04979824,0 -1614304800000,46480.48000000,47800.00000000,46124.74000000,47343.51000000,5240.30775400,1614308399999,246801657.25005068,113885,2727.86834900,128587722.42657518,0 -1614308400000,47343.50000000,47695.77000000,46639.24000000,47330.24000000,3512.63530400,1614311999999,165764356.62534804,74188,1678.73869200,79268414.42883371,0 -1614312000000,47331.34000000,47786.50000000,46806.49000000,47025.06000000,2839.21943900,1614315599999,134360235.86143333,67187,1404.24721700,66455661.80800747,0 -1614315600000,47028.80000000,47207.40000000,45502.69000000,45517.53000000,5228.38820800,1614319199999,241909695.32155710,106473,2393.47558700,110855039.12883120,0 -1614319200000,45524.35000000,46500.00000000,45512.02000000,46093.07000000,3894.66556800,1614322799999,179503674.00823412,92708,2004.62294400,92392698.00012970,0 -1614322800000,46098.99000000,46430.02000000,44106.78000000,44973.68000000,10843.41221600,1614326399999,488062440.47692488,182846,4759.61414800,214102124.22802633,0 -1614326400000,44986.99000000,45950.00000000,44939.19000000,45727.74000000,5560.53718000,1614329999999,252899486.53136551,112993,3040.30106900,138268949.01498576,0 -1614330000000,45727.75000000,46626.35000000,45325.00000000,46410.76000000,6228.04563800,1614333599999,287389360.53800643,120877,2953.79986200,136357667.07994773,0 -1614333600000,46410.76000000,46880.40000000,46168.00000000,46706.85000000,3745.26633500,1614337199999,174396328.08068973,83336,1855.10917900,86378782.45516731,0 -1614337200000,46704.75000000,46850.00000000,45662.94000000,46427.65000000,3319.25951200,1614340799999,153378598.05698269,74580,1652.14932400,76345324.90886055,0 -1614340800000,46427.65000000,47266.34000000,46315.08000000,46823.39000000,3485.25260900,1614344399999,163279933.31185639,73849,1769.62185000,82921416.43307298,0 -1614344400000,46823.38000000,46999.77000000,45800.00000000,45958.41000000,3593.67866900,1614347999999,166636422.45052784,74350,1875.93901200,86995976.18924903,0 -1614348000000,45958.41000000,47429.00000000,45828.37000000,46868.98000000,4508.89686400,1614351599999,210961601.75950509,95235,2427.59182800,113576978.93155110,0 -1614351600000,46869.59000000,47853.13000000,46333.00000000,47594.65000000,5170.12468800,1614355199999,243331076.24514916,95719,2707.73438300,127476530.24788660,0 -1614355200000,47590.66000000,48219.08000000,47450.00000000,48127.26000000,4556.16230600,1614358799999,218038757.46334770,97078,2376.52056900,113747181.50612344,0 -1614358800000,48127.26000000,48424.11000000,47542.20000000,47660.98000000,3255.90618200,1614362399999,156184096.40823589,97578,1516.64501800,72767422.86201629,0 -1614362400000,47659.96000000,47873.24000000,47269.99000000,47317.09000000,2473.72390500,1614365999999,117680138.80192218,67348,1261.37198300,59999766.57364878,0 -1614366000000,47317.09000000,47478.07000000,46602.62000000,46959.17000000,3342.27688000,1614369599999,157219140.61462317,81667,1775.23647800,83525665.16354663,0 -1614369600000,46959.18000000,47115.38000000,46071.89000000,46270.00000000,3514.29786700,1614373199999,163727573.68617536,80837,1733.79210500,80755103.94787450,0 -1614373200000,46270.00000000,46867.00000000,45500.00000000,45677.46000000,3831.69018200,1614376799999,177173658.77323526,85141,1806.78594000,83585069.84939639,0 -1614376800000,45680.00000000,45988.77000000,45000.00000000,45476.30000000,4400.97529100,1614380399999,200547396.61397559,123927,2204.94896800,100559178.29847833,0 -1614380400000,45476.30000000,46444.57000000,45368.74000000,46276.87000000,2571.86578500,1614383999999,118542767.20494309,60317,1078.34853900,49692166.80407637,0 -1614384000000,46276.88000000,47568.18000000,46156.24000000,47525.07000000,3534.29999100,1614387599999,165803625.84097623,86580,1665.01567100,78110640.54767086,0 -1614387600000,47523.34000000,47960.00000000,47331.54000000,47761.97000000,2844.98808800,1614391199999,135514542.91739055,66295,1421.25152600,67704139.35897203,0 -1614391200000,47761.97000000,48085.47000000,47186.00000000,47375.34000000,4456.60085500,1614394799999,212457424.21204068,78369,2189.07166400,104342900.46655170,0 -1614394800000,47375.34000000,47937.03000000,47158.26000000,47423.08000000,2661.32193700,1614398399999,126754003.33040374,57862,1405.78906700,66954860.25786872,0 -1614398400000,47423.07000000,47918.40000000,47278.54000000,47657.47000000,2060.90965900,1614401999999,98143308.31298744,53225,1066.13491300,50771040.52663614,0 -1614402000000,47657.48000000,47955.58000000,47460.21000000,47803.71000000,1995.34977400,1614405599999,95113752.31335984,49559,1050.35401800,50073355.08143282,0 -1614405600000,47799.68000000,48394.00000000,47527.33000000,47566.60000000,2654.87120400,1614409199999,127353603.53008118,66971,1405.04827800,67410668.81044190,0 -1614409200000,47560.69000000,47626.26000000,46712.18000000,47158.53000000,3140.61823000,1614412799999,148219870.16535473,103195,1362.54620800,64305961.13869768,0 -1614412800000,47153.01000000,47284.74000000,46380.00000000,46620.50000000,2860.16511300,1614416399999,133799040.21912423,72532,1377.74747200,64451428.41630400,0 -1614416400000,46620.83000000,46827.73000000,46224.84000000,46671.04000000,2576.34509200,1614419999999,119862455.12701158,69632,1302.27292700,60589695.58045667,0 -1614420000000,46671.04000000,47099.97000000,46601.01000000,46775.51000000,2600.52498100,1614423599999,121899926.21080389,73219,1320.99195800,61923992.42977355,0 -1614423600000,46775.68000000,47640.03000000,46690.00000000,47299.99000000,2765.21237600,1614427199999,130625873.88869273,98218,1334.86962300,63061410.76453267,0 -1614427200000,47299.99000000,47800.00000000,46735.63000000,47429.99000000,3286.07999400,1614430799999,155524036.69004770,104559,1719.14008500,81375777.57309195,0 -1614430800000,47430.00000000,47700.00000000,47058.82000000,47441.91000000,2358.37712800,1614434399999,111900397.24020663,67771,1165.13395500,55286834.45013342,0 -1614434400000,47441.91000000,47620.00000000,46836.00000000,47079.64000000,2566.95495400,1614437999999,121112174.87390989,68107,1187.81147400,56048094.24457132,0 -1614438000000,47078.23000000,47378.92000000,46337.53000000,46528.64000000,3281.96265900,1614441599999,153502286.09020234,75010,1591.87644400,74468168.98682059,0 -1614441600000,46528.82000000,46949.96000000,46271.00000000,46883.19000000,2253.46093200,1614445199999,105298736.37827274,63972,1046.25098800,48907145.01779883,0 -1614445200000,46883.19000000,47177.00000000,46700.00000000,47042.53000000,1672.24031500,1614448799999,78515466.79669112,51211,805.28582400,37810517.31586011,0 -1614448800000,47041.13000000,47329.17000000,46900.00000000,47136.30000000,1457.74337900,1614452399999,68687063.11667067,46792,729.86197100,34391944.86717012,0 -1614452400000,47136.29000000,47450.26000000,47028.59000000,47405.39000000,1684.93500000,1614455999999,79658239.62294505,60931,834.00371700,39436662.29000260,0 -1614456000000,47405.38000000,47557.14000000,46900.00000000,47081.07000000,1868.82747200,1614459599999,88246185.35643802,58133,998.73874800,47167746.01101271,0 -1614459600000,47083.43000000,47170.00000000,46534.13000000,46825.30000000,1969.98297900,1614463199999,92418276.77836795,53136,879.07275900,41240297.39382531,0 -1614463200000,46825.30000000,46870.31000000,45742.00000000,45828.43000000,2593.33291400,1614466799999,120278864.92911987,77561,1114.37705300,51711821.91528250,0 -1614466800000,45828.44000000,46441.41000000,45000.00000000,46106.43000000,6915.72926600,1614470399999,315208284.60987299,154880,3014.37330400,137467007.50468982,0 -1614470400000,46103.67000000,46638.46000000,45588.11000000,46345.94000000,3169.79714600,1614473999999,146343245.43574778,73122,1659.58699400,76624309.58339224,0 -1614474000000,46345.93000000,46600.00000000,46100.00000000,46442.50000000,1907.14640000,1614477599999,88446962.56277918,46835,969.55992000,44980753.83648046,0 -1614477600000,46439.20000000,46518.68000000,45220.28000000,45397.23000000,2844.47407400,1614481199999,130253873.25121635,71301,1295.88687100,59331828.16020728,0 -1614481200000,45397.97000000,45684.56000000,44444.00000000,44629.17000000,5409.31508300,1614484799999,243565752.27029851,107113,2459.09725300,110765442.09332018,0 -1614484800000,44632.70000000,45100.00000000,44267.48000000,44384.14000000,3744.72190800,1614488399999,167372917.56371388,81166,1864.17655200,83344548.00617286,0 -1614488400000,44384.38000000,45600.00000000,44200.00000000,44791.27000000,4065.08885100,1614491999999,182473020.62141399,88176,2025.52662800,91017014.80541965,0 -1614492000000,44791.27000000,44977.05000000,43738.65000000,44372.43000000,6061.42567500,1614495599999,268938540.46627653,123877,2986.34030800,132564535.19387009,0 -1614495600000,44379.68000000,44783.29000000,44099.99000000,44400.83000000,2997.71730300,1614499199999,133261571.87941589,71352,1509.46732000,67112779.23711468,0 -1614499200000,44400.83000000,45273.68000000,44375.02000000,44856.61000000,3222.93603900,1614502799999,144621237.55419828,69922,1672.73012400,75067985.53918451,0 -1614502800000,44856.61000000,45530.62000000,44680.71000000,45067.61000000,2733.85811000,1614506399999,123504689.95208467,60914,1397.29972800,63134373.77267454,0 -1614506400000,45067.51000000,45513.78000000,44712.19000000,45177.20000000,2357.30304900,1614509999999,106473932.85628458,51637,1191.64029400,53849452.11931280,0 -1614510000000,45177.20000000,45493.87000000,44966.63000000,45284.86000000,2221.51346500,1614513599999,100639192.03627693,48549,1133.87832600,51377617.18932274,0 -1614513600000,45287.25000000,45500.17000000,44501.00000000,44756.99000000,2991.00191900,1614517199999,134304067.74202045,70740,1533.22514500,68851526.75005113,0 -1614517200000,44756.99000000,44889.00000000,44150.00000000,44178.80000000,3108.19179800,1614520799999,138482357.92560297,65249,1410.56367100,62851419.90856457,0 -1614520800000,44183.52000000,44652.30000000,43556.98000000,44561.92000000,5862.90959100,1614524399999,258553829.19896809,118733,2853.84535500,125894209.04068268,0 -1614524400000,44564.46000000,44628.89000000,43168.00000000,43391.14000000,5007.27058300,1614527999999,218771349.57323169,108126,2347.12410900,102573613.94667773,0 -1614528000000,43391.14000000,43934.56000000,43000.00000000,43514.78000000,4682.77407500,1614531599999,203706183.12276087,100278,2208.85326200,96126605.99246248,0 -1614531600000,43514.77000000,43942.62000000,43085.00000000,43119.02000000,3300.00538700,1614535199999,143500534.33324752,72028,1493.07205400,64961325.13164407,0 -1614535200000,43123.42000000,43779.96000000,43001.00000000,43677.39000000,2672.29292500,1614538799999,116189047.22323296,56790,1365.94908900,59415305.57699560,0 -1614538800000,43683.79000000,44521.66000000,43434.22000000,44405.32000000,2825.26510900,1614542399999,124222953.03989421,66719,1390.80217500,61174762.09096287,0 -1614542400000,44402.88000000,44960.00000000,44088.00000000,44860.38000000,2723.97533900,1614545999999,120993189.49728925,64301,1276.70520100,56732923.18431498,0 -1614546000000,44866.37000000,45380.21000000,44845.88000000,45129.52000000,3611.87808000,1614549599999,163044265.62454782,85094,1695.55722700,76544169.12652960,0 -1614549600000,45129.52000000,45362.35000000,44755.10000000,45180.00000000,1990.55793300,1614553199999,89784874.35224988,55700,1104.36519700,49819715.24342241,0 -1614553200000,45179.99000000,45919.61000000,44850.00000000,45135.66000000,3543.94920000,1614556799999,160912377.37182900,80623,1842.91904700,83681231.07360078,0 -1614556800000,45134.11000000,46571.30000000,44950.53000000,46217.19000000,4899.57483300,1614560399999,225513040.97302689,98570,2546.12383200,117249522.87670990,0 -1614560400000,46217.18000000,46492.33000000,45850.00000000,46161.83000000,2685.38600500,1614563999999,123992734.60490434,63851,1272.87872400,58775192.06854412,0 -1614564000000,46166.16000000,46796.94000000,46102.84000000,46419.56000000,2926.95109900,1614567599999,136131784.14017812,66979,1434.36610300,66682014.58160103,0 -1614567600000,46414.70000000,46540.31000000,46204.08000000,46336.37000000,1970.34891200,1614571199999,91409715.99835350,48608,996.75823700,46245628.53192638,0 -1614571200000,46336.38000000,46688.13000000,45959.70000000,46458.33000000,2152.37990400,1614574799999,99623997.43976883,52281,1018.96408400,47174472.85825921,0 -1614574800000,46474.53000000,46486.33000000,45980.00000000,46200.47000000,2151.81610900,1614578399999,99418827.42803201,42108,1160.44899500,53602856.04459932,0 -1614578400000,46200.46000000,46272.38000000,45641.02000000,45857.30000000,2462.75599200,1614581999999,113251774.58884000,54715,1221.62636300,56181460.93743773,0 -1614582000000,45857.30000000,46425.61000000,45837.28000000,46288.18000000,2757.47142600,1614585599999,127185633.65512986,52132,1401.27958900,64626989.17786812,0 -1614585600000,46291.87000000,47300.00000000,46272.10000000,47009.38000000,4893.93544600,1614589199999,229398351.72244389,105294,2517.08494200,118002132.07713202,0 -1614589200000,47009.38000000,47500.00000000,46900.00000000,47350.12000000,3890.52625300,1614592799999,183805805.57094061,119593,1860.70307400,87929478.97873058,0 -1614592800000,47347.51000000,47714.61000000,46968.00000000,47615.66000000,3790.49879700,1614596399999,179579344.64943491,113749,1814.06676300,85969877.50688835,0 -1614596400000,47615.66000000,48050.00000000,47400.00000000,47722.78000000,5754.50783300,1614599999999,274969148.28367645,148678,2584.48026900,123436759.74516606,0 -1614600000000,47722.42000000,48044.63000000,47450.32000000,47913.80000000,3184.93608500,1614603599999,152215160.11143974,130402,1642.63539700,78521976.07015114,0 -1614603600000,47913.80000000,48441.96000000,47757.78000000,47799.33000000,5239.10988500,1614607199999,252041307.30553061,128669,2231.27196300,107367721.13743488,0 -1614607200000,47799.34000000,48564.03000000,47580.10000000,48083.04000000,4564.09516600,1614610799999,219732963.70363260,106239,2351.11959800,113191346.51585313,0 -1614610800000,48083.04000000,49298.00000000,48065.54000000,49188.00000000,5757.10113300,1614614399999,281053341.77638509,126214,3130.48006600,152782808.66391681,0 -1614614400000,49187.99000000,49469.99000000,48530.36000000,49065.40000000,5837.99284000,1614617999999,286091759.29871188,155200,3045.56667000,149251264.19539030,0 -1614618000000,49069.60000000,49200.00000000,48527.27000000,48565.00000000,3508.19818100,1614621599999,171459146.32915217,75536,1500.41754800,73337903.66428158,0 -1614621600000,48565.00000000,48777.71000000,48233.33000000,48465.27000000,3120.34098400,1614625199999,151243496.69571990,71330,1632.04003700,79098725.14175139,0 -1614625200000,48465.27000000,48700.00000000,48019.06000000,48262.83000000,2240.12268200,1614628799999,108246561.65351669,59593,1097.23393800,53024323.54805958,0 -1614628800000,48262.66000000,48916.55000000,47876.00000000,48512.40000000,4496.21330400,1614632399999,217115102.90005244,101790,2755.45463300,133029219.81850437,0 -1614632400000,48512.99000000,48872.00000000,48338.25000000,48784.09000000,2011.39697700,1614635999999,97812320.09828620,96201,1014.30510600,49324876.35973564,0 -1614636000000,48784.46000000,49300.00000000,48588.89000000,49137.73000000,1882.44168200,1614639599999,92252313.95743198,57553,870.78503600,42666007.40763326,0 -1614639600000,49137.73000000,49790.00000000,49064.62000000,49587.03000000,2908.01012000,1614643199999,143972161.98113952,71938,1516.90339400,75094127.70673212,0 -1614643200000,49595.76000000,50200.00000000,49278.94000000,49354.62000000,4346.81402400,1614646799999,216488087.59988408,129863,2270.17818400,113115088.77165506,0 -1614646800000,49354.63000000,49699.93000000,48710.00000000,49368.60000000,2651.16259000,1614650399999,130190243.85463369,69946,1413.38820000,69418719.02284061,0 -1614650400000,49368.60000000,49777.00000000,49045.45000000,49272.74000000,2909.33571100,1614653999999,143869485.52624628,70920,1463.01451400,72353098.49711370,0 -1614654000000,49272.74000000,49398.00000000,48825.00000000,48974.75000000,2134.19589000,1614657599999,104756035.22156957,50352,962.66098100,47247693.97571770,0 -1614657600000,48974.74000000,49243.00000000,48544.75000000,49159.16000000,2213.46541600,1614661199999,108239030.17290433,54092,1153.58493300,56405746.98290183,0 -1614661200000,49159.16000000,49402.07000000,48660.28000000,48672.07000000,1944.60465600,1614664799999,95318839.01138939,46463,925.04489500,45331645.20696174,0 -1614664800000,48673.88000000,48846.03000000,48333.00000000,48638.36000000,2733.66015400,1614668399999,132803863.87494007,113819,1346.87413900,65437960.53324578,0 -1614668400000,48631.58000000,48833.10000000,48301.36000000,48331.61000000,2277.99261900,1614671999999,110625788.74445659,99655,1231.21930100,59791562.29107835,0 -1614672000000,48331.60000000,49222.00000000,48270.69000000,48858.08000000,2996.19663500,1614675599999,146165949.21175821,67298,1564.55009300,76329343.62713566,0 -1614675600000,48861.23000000,49265.54000000,48861.22000000,49144.23000000,2269.41548500,1614679199999,111331476.44254829,59578,1029.79736100,50509186.80540750,0 -1614679200000,49144.22000000,49263.95000000,48550.00000000,48721.09000000,2242.27340900,1614682799999,109735288.60017008,59225,1055.02994600,51635794.36524153,0 -1614682800000,48721.09000000,49047.06000000,48550.00000000,48844.13000000,1837.03586300,1614686399999,89672315.55733889,51394,925.98387800,45202432.84676146,0 -1614686400000,48844.14000000,49117.00000000,48568.98000000,48811.03000000,1941.87487100,1614689999999,94695646.41897205,58535,939.50143700,45819256.80625263,0 -1614690000000,48807.45000000,49076.70000000,48712.70000000,49000.00000000,2099.03468900,1614693599999,102661918.65693999,53590,1048.34135100,51275549.02548314,0 -1614693600000,49000.00000000,49699.99000000,48769.32000000,48899.31000000,4150.04648100,1614697199999,204406128.59988017,93972,2043.69139200,100694555.36869732,0 -1614697200000,48899.30000000,49043.99000000,48380.83000000,48676.08000000,3178.21165500,1614700799999,154673872.36398197,74708,1340.28285400,65238082.99869603,0 -1614700800000,48676.09000000,48718.18000000,47265.79000000,47520.01000000,5366.20531800,1614704399999,257575962.00608259,151798,2348.60968800,112738228.67151534,0 -1614704400000,47519.58000000,47982.45000000,47200.00000000,47852.63000000,3662.97735400,1614707999999,174456947.30407828,128730,1829.51643800,87142089.64553995,0 -1614708000000,47852.63000000,48030.48000000,47526.31000000,47678.38000000,1994.87417900,1614711599999,95233303.89670687,93769,952.79825600,45494063.33970039,0 -1614711600000,47678.38000000,47944.43000000,47144.22000000,47467.43000000,2771.26309500,1614715199999,131747693.06842034,98596,1309.93651000,62301181.25787985,0 -1614715200000,47467.43000000,47643.28000000,47047.60000000,47529.57000000,2453.64842600,1614718799999,116231937.36985676,64205,1202.55626400,56972275.63864315,0 -1614718800000,47529.57000000,47870.00000000,47273.01000000,47407.03000000,1932.81103100,1614722399999,91943475.69137602,53329,928.83926000,44190501.89233958,0 -1614722400000,47407.25000000,47960.00000000,47331.96000000,47789.87000000,1253.98626200,1614725999999,59837463.58720565,47363,580.48573900,27703230.00487398,0 -1614726000000,47793.36000000,48489.24000000,47719.70000000,48440.65000000,2859.97632700,1614729599999,137811317.12811264,64383,1511.15246300,72798082.56783824,0 -1614729600000,48436.61000000,48745.13000000,48100.71000000,48507.96000000,2531.59123400,1614733199999,122798419.62848665,53077,1177.89221700,57133626.05636271,0 -1614733200000,48514.80000000,48882.43000000,48458.38000000,48848.63000000,1643.30219000,1614736799999,80018499.29918459,41210,726.73526000,35389387.98642285,0 -1614736800000,48848.63000000,49000.51000000,48528.92000000,48594.07000000,1553.52741800,1614740399999,75752054.89001707,38394,719.59482100,35090864.33090984,0 -1614740400000,48594.06000000,48839.27000000,48494.53000000,48704.75000000,1185.08812100,1614743999999,57663580.92956713,40893,607.00264100,29538436.50475996,0 -1614744000000,48704.75000000,49327.70000000,48653.09000000,49105.47000000,2790.44936100,1614747599999,136996237.70821637,65457,1488.15755300,73047477.71140269,0 -1614747600000,49105.47000000,49466.69000000,48837.00000000,49079.64000000,2164.58725700,1614751199999,106340109.61150006,108475,1065.72382500,52357904.27170272,0 -1614751200000,49078.59000000,49637.39000000,49078.59000000,49529.90000000,2958.78076000,1614754799999,146185107.96353998,93723,1666.72251300,82355738.29385587,0 -1614754800000,49529.90000000,49960.00000000,49474.11000000,49752.97000000,2792.45951800,1614758399999,138931530.68384826,97584,1459.85421200,72631476.78293404,0 -1614758400000,49752.97000000,50998.00000000,49752.97000000,50909.41000000,5488.74934600,1614761999999,277024353.58012751,125973,3143.49451100,158582078.01920919,0 -1614762000000,50909.40000000,51495.00000000,50720.00000000,51445.31000000,5106.81950300,1614765599999,261126093.92694194,132698,2763.20349500,141336464.50458270,0 -1614765600000,51445.31000000,51756.05000000,51187.07000000,51414.19000000,4520.03804600,1614769199999,232747613.88113270,151516,2397.06561200,123449947.65462317,0 -1614769200000,51414.19000000,51777.00000000,51155.33000000,51666.33000000,4391.34593700,1614772799999,226230013.96903974,130413,2396.12146300,123441814.32529159,0 -1614772800000,51665.83000000,52575.17000000,51355.00000000,52540.04000000,5714.41055100,1614776399999,296992452.13045612,127191,3308.02935500,171904075.38866856,0 -1614776400000,52547.23000000,52640.00000000,51188.31000000,51559.50000000,5758.60323800,1614779999999,298239335.78139556,137323,2804.76765100,145233591.21723580,0 -1614780000000,51559.63000000,51564.15000000,50651.00000000,50776.36000000,7069.14955100,1614783599999,360402221.17815262,141576,3365.80942100,171557758.40703310,0 -1614783600000,50776.35000000,51155.00000000,50481.00000000,50767.36000000,4526.07871600,1614787199999,229708968.53050298,130473,2035.28169900,103338304.58871397,0 -1614787200000,50767.35000000,51444.90000000,50750.02000000,51077.00000000,4984.12482500,1614790799999,254824653.29664886,165716,2300.10871300,117606484.26926302,0 -1614790800000,51077.00000000,51449.84000000,50825.18000000,51307.78000000,2696.71573800,1614794399999,138068361.30626659,87905,1283.44169500,65716481.02773078,0 -1614794400000,51305.50000000,51600.00000000,51100.00000000,51233.11000000,2318.50380800,1614797999999,119154743.77854526,60959,1156.39773200,59434033.01814201,0 -1614798000000,51233.11000000,51257.29000000,50260.00000000,50857.17000000,3237.72893200,1614801599999,164086181.75125293,85121,1481.36872300,75059542.89752790,0 -1614801600000,50857.17000000,51172.62000000,50431.37000000,50521.40000000,2027.51565200,1614805199999,103090865.08911168,59000,941.50563200,47881773.56682220,0 -1614805200000,50523.93000000,51123.00000000,50364.64000000,50958.60000000,1734.77098600,1614808799999,88022811.63217602,52301,837.51421800,42524598.54984129,0 -1614808800000,50956.10000000,51356.86000000,50500.00000000,50577.34000000,1805.80320500,1614812399999,91937030.51610346,60526,858.10618500,43715137.90935652,0 -1614812400000,50577.33000000,51068.99000000,50301.50000000,50349.37000000,2035.76981200,1614815999999,103180016.47848618,54627,971.46925200,49259901.39581802,0 -1614816000000,50349.37000000,51147.05000000,49850.81000000,50894.48000000,3929.68063600,1614819599999,197918438.70191361,136711,1730.25342400,87217347.38470511,0 -1614819600000,50894.48000000,51622.94000000,50714.28000000,51475.19000000,3033.52882300,1614823199999,155800990.35958906,71501,1699.67633300,87308878.17578879,0 -1614823200000,51475.14000000,51773.88000000,50790.55000000,50791.63000000,2491.78961200,1614826799999,127904320.77595812,63350,1207.29439800,61990478.73723125,0 -1614826800000,50792.02000000,51033.47000000,49401.30000000,49574.89000000,4911.74132000,1614830399999,246022529.21847696,106305,2092.21946100,104801051.58968789,0 -1614830400000,49574.89000000,49811.66000000,49010.10000000,49065.33000000,3987.47014200,1614833999999,197194266.54437518,99280,1978.71458700,97856280.97287022,0 -1614834000000,49065.32000000,49698.43000000,49034.81000000,49661.35000000,2844.02402400,1614837599999,140413615.69223364,102342,1521.52767900,75117152.19597829,0 -1614837600000,49664.40000000,49870.00000000,49237.49000000,49393.07000000,2645.16712500,1614841199999,131018764.94435118,72059,1176.34274000,58273254.52288077,0 -1614841200000,49393.08000000,49816.00000000,49320.00000000,49696.49000000,2234.03931000,1614844799999,110828678.90419889,109498,1055.00032200,52337421.41246901,0 -1614844800000,49701.37000000,50756.23000000,49688.46000000,50221.61000000,4072.44769000,1614848399999,205017535.42104988,98949,1920.06207300,96645888.47671643,0 -1614848400000,50221.67000000,50225.00000000,48524.86000000,49069.98000000,5990.24725100,1614851999999,293836706.53748163,155675,2850.86327900,139805295.23980407,0 -1614852000000,49069.99000000,49562.49000000,48747.46000000,49219.42000000,3159.20152200,1614855599999,155318797.62700935,82160,1450.19468900,71297604.04786283,0 -1614855600000,49216.96000000,49499.00000000,48898.64000000,49323.32000000,2362.81813700,1614859199999,116380363.77900442,79907,1225.97429300,60394695.34874380,0 -1614859200000,49323.31000000,49764.92000000,49113.63000000,49355.84000000,2548.53514900,1614862799999,125917611.75631470,106501,1271.47501100,62830402.83400939,0 -1614862800000,49355.85000000,49710.00000000,48721.43000000,49633.44000000,3379.86793700,1614866399999,166619030.46277974,90032,1744.42532100,86010212.06358469,0 -1614866400000,49633.44000000,50569.41000000,49205.13000000,49422.53000000,4935.92384900,1614869999999,245794766.67514644,122141,2398.65822600,119450300.31675610,0 -1614870000000,49422.53000000,49812.41000000,48829.07000000,49412.60000000,4123.16341300,1614873599999,203320373.60060322,103220,2125.30199900,104800742.77860544,0 -1614873600000,49412.60000000,50033.92000000,49300.01000000,49693.59000000,2731.21131900,1614877199999,135736787.73498519,81783,1392.03344700,69191403.27582915,0 -1614877200000,49694.60000000,49927.34000000,48319.36000000,48508.07000000,4940.77189000,1614880799999,242741823.79543321,124202,2414.98676600,118688903.20083292,0 -1614880800000,48508.01000000,48666.66000000,47588.52000000,47600.01000000,5960.91355300,1614884399999,286835970.47422675,144059,2727.59863900,131306475.85429757,0 -1614884400000,47600.00000000,48394.04000000,47596.29000000,48000.36000000,3689.38935300,1614887999999,177510471.16833480,115542,1802.29835200,86688235.65910484,0 -1614888000000,48000.37000000,48270.99000000,47500.00000000,48221.00000000,3058.63060700,1614891599999,146501948.75320175,76424,1483.31950500,71073269.89941984,0 -1614891600000,48221.00000000,48434.68000000,47800.00000000,47955.77000000,1971.81794600,1614895199999,94901008.52759783,51084,1041.88162500,50141918.29659669,0 -1614895200000,47955.78000000,48350.00000000,47859.16000000,48249.99000000,1346.51845200,1614898799999,64853394.20502821,50261,732.94692900,35308935.56370703,0 -1614898800000,48249.99000000,48710.94000000,48049.00000000,48374.09000000,2300.81776900,1614902399999,111449045.19746825,48950,1226.92879000,59419406.95733242,0 -1614902400000,48374.09000000,48376.20000000,46512.90000000,46829.84000000,6980.75137400,1614905999999,328721516.54924524,147184,2850.39814000,134215808.17783862,0 -1614906000000,46829.84000000,47000.00000000,46300.00000000,46709.94000000,4433.21166500,1614909599999,206693722.64967049,110525,2172.25014500,101302132.56477424,0 -1614909600000,46709.95000000,47180.85000000,46366.33000000,47108.28000000,3350.86472100,1614913199999,156723197.32219965,72991,1732.80657400,81056202.99890545,0 -1614913200000,47107.25000000,47339.00000000,46800.88000000,47289.81000000,2239.18266700,1614916799999,105421027.90991740,61052,1025.98802000,48309932.46178079,0 -1614916800000,47289.81000000,47307.69000000,46500.00000000,46679.08000000,2082.33394200,1614920399999,97950064.72169799,49715,876.45557600,41235865.38349453,0 -1614920400000,46670.26000000,47253.17000000,46665.73000000,47153.13000000,2232.82222600,1614923999999,104974819.51468483,88227,1125.10198900,52905458.28653990,0 -1614924000000,47153.13000000,47442.01000000,46954.81000000,47396.56000000,2085.31822600,1614927599999,98517743.60347576,53209,1051.94983300,49709329.18608152,0 -1614927600000,47396.56000000,47547.00000000,47010.89000000,47380.00000000,2244.81060200,1614931199999,106162561.02350319,54941,1154.78843200,54615062.09516183,0 -1614931200000,47380.00000000,47500.00000000,46418.12000000,46634.35000000,3887.95356200,1614934799999,182154304.92190576,84285,1868.71969900,87561478.41656940,0 -1614934800000,46635.75000000,47157.43000000,46530.00000000,47063.51000000,2099.12380600,1614938399999,98404068.56155052,81748,1069.29766400,50123416.57233001,0 -1614938400000,47063.50000000,47229.79000000,46780.01000000,47080.97000000,2049.14217000,1614941999999,96466965.17676227,56548,1022.73574500,48147056.34526113,0 -1614942000000,47080.96000000,47523.59000000,47080.96000000,47478.87000000,2364.22037600,1614945599999,111937863.72534426,60511,1234.42823500,58449332.72046962,0 -1614945600000,47478.86000000,47880.00000000,46974.32000000,47649.99000000,3769.82325300,1614949199999,179062291.78839200,91969,1890.51077600,89822202.81165216,0 -1614949200000,47650.00000000,48296.93000000,47325.94000000,48056.18000000,4933.82732300,1614952799999,236340662.63323138,112419,2398.93031500,114929846.39371217,0 -1614952800000,48061.21000000,48728.21000000,47936.51000000,48136.81000000,5144.60762100,1614956399999,248717770.50665324,116319,2514.10997600,121555662.47912867,0 -1614956400000,48136.82000000,48698.19000000,47837.83000000,47867.45000000,3709.70111800,1614959999999,178860366.42656119,137384,1948.05050400,93911930.76677332,0 -1614960000000,47867.45000000,47867.45000000,46885.00000000,47658.14000000,5565.80565100,1614963599999,264110340.34202984,145730,2898.83900300,137588239.24386049,0 -1614963600000,47656.65000000,48237.42000000,47320.00000000,48096.01000000,3532.14967600,1614967199999,169030691.69754073,73267,1771.06620500,84768832.99502807,0 -1614967200000,48096.00000000,48558.50000000,47918.38000000,48478.11000000,3039.36504800,1614970799999,146912674.73393674,102775,1519.11297900,73436368.93067457,0 -1614970800000,48478.12000000,49400.00000000,48310.40000000,49295.47000000,3687.78444400,1614974399999,180194817.83148679,81593,2000.57971300,97749213.50761805,0 -1614974400000,49285.76000000,49448.93000000,48832.17000000,49173.85000000,2917.73505300,1614977999999,143449027.15022502,98086,1373.60348600,67531426.71356788,0 -1614978000000,49173.85000000,49398.00000000,48890.97000000,49035.21000000,2046.17724000,1614981599999,100533176.65973319,49623,901.49816000,44284505.17435807,0 -1614981600000,49035.20000000,49389.99000000,48673.71000000,49061.76000000,1773.89885300,1614985199999,87064645.44800825,68027,847.37477500,41588318.89630794,0 -1614985200000,49061.77000000,49160.29000000,48579.59000000,48751.71000000,2021.88575500,1614988799999,98728783.93955465,56088,1069.71443300,52227389.09566100,0 -1614988800000,48746.81000000,49156.00000000,48675.67000000,48808.05000000,1845.19339200,1614992399999,90328263.10627944,50809,831.66585500,40712519.85447785,0 -1614992400000,48807.83000000,48901.65000000,48520.00000000,48647.38000000,1293.84492500,1614995999999,62960628.37109181,36753,686.71059800,33415823.72733721,0 -1614999600000,48647.37000000,48801.81000000,48350.00000000,48657.72000000,818.44067300,1615003199999,39764114.17495608,24356,390.87255100,18994831.45205219,0 -1615003200000,48657.72000000,48687.49000000,48115.83000000,48451.16000000,1726.74406000,1615006799999,83446085.40417748,65417,838.47796700,40521172.94952703,0 -1615006800000,48450.12000000,48895.32000000,48193.00000000,48496.28000000,1653.75943400,1615010399999,80307401.56732063,60397,797.99258200,38755342.22985057,0 -1615010400000,48496.27000000,48971.29000000,48482.17000000,48922.00000000,1754.07195500,1615013999999,85589315.54183216,45201,814.31175800,39727407.03789698,0 -1615014000000,48922.00000000,49117.32000000,48772.24000000,48820.12000000,1647.18114200,1615017599999,80636495.63993865,44370,828.00818800,40541376.07465345,0 -1615017600000,48820.13000000,49100.00000000,48600.00000000,48641.64000000,2233.92258700,1615021199999,109189858.35294529,94092,1019.19495900,49830387.27238900,0 -1615021200000,48641.65000000,48785.00000000,48270.01000000,48335.10000000,1882.87757900,1615024799999,91307735.75840453,48858,968.13415000,46956183.45522934,0 -1615024800000,48335.22000000,48499.99000000,48000.00000000,48035.36000000,2154.95648200,1615028399999,103866218.01211190,86010,799.33601400,38574224.33102557,0 -1615028400000,48035.37000000,48331.91000000,48000.00000000,48171.01000000,1402.21562700,1615031999999,67556132.69875654,65040,720.06973300,34694811.70184996,0 -1615032000000,48171.02000000,48212.85000000,47401.82000000,47660.74000000,3296.63806100,1615035599999,157314265.41861050,107114,1500.30716100,71558286.31501310,0 -1615035600000,47660.75000000,47753.39000000,47070.00000000,47320.30000000,3107.86133500,1615039199999,147223560.49443072,111334,1571.47825100,74445086.16189465,0 -1615039200000,47320.30000000,47725.51000000,47201.12000000,47560.96000000,1820.41148200,1615042799999,86454116.60397910,85390,887.38063000,42145146.74546724,0 -1615042800000,47562.67000000,47712.69000000,47238.32000000,47267.88000000,1475.15553400,1615046399999,70130991.28769348,64970,643.01072600,30570476.13868999,0 -1615046400000,47267.88000000,47941.03000000,47104.85000000,47757.43000000,2487.13413100,1615049999999,118538409.63733009,67272,1233.57733000,58804306.46299256,0 -1615050000000,47755.08000000,48450.00000000,47655.01000000,48250.69000000,2674.93363700,1615053599999,128615238.60874081,74126,1417.64681900,68178381.97808647,0 -1615053600000,48250.70000000,48623.00000000,48109.79000000,48473.30000000,2003.05469900,1615057199999,96878694.16266076,60766,1000.80385800,48414740.66004490,0 -1615057200000,48473.30000000,48690.60000000,48248.27000000,48341.01000000,1584.42261600,1615060799999,76741497.69559580,55227,752.46265000,36448564.22125696,0 -1615060800000,48341.00000000,48734.84000000,48223.36000000,48518.50000000,2390.26653700,1615064399999,115903829.22444935,64961,1131.75658000,54877668.79805545,0 -1615064400000,48518.51000000,48723.00000000,48264.63000000,48578.71000000,1716.06082200,1615067999999,83333485.92817200,45864,853.45273200,41443886.40759648,0 -1615068000000,48577.22000000,49200.00000000,48463.75000000,48920.88000000,1991.42598100,1615071599999,97393078.60634556,64007,1087.31707300,53176565.98816272,0 -1615071600000,48920.87000000,49120.01000000,48805.00000000,48882.20000000,1438.66155100,1615075199999,70431288.99568053,54140,726.64745200,35578683.01640515,0 -1615075200000,48882.20000000,49312.00000000,48882.20000000,49203.25000000,2100.25945600,1615078799999,103198224.50174948,50983,970.03890400,47668550.32244923,0 -1615078800000,49203.25000000,49490.00000000,48982.17000000,49121.95000000,2165.86194700,1615082399999,106634203.07368673,55306,1075.88714600,52971496.16525737,0 -1615082400000,49121.95000000,49851.00000000,49052.91000000,49550.58000000,2579.98201800,1615085999999,127803055.39798113,66389,1312.80248700,65019805.77740570,0 -1615086000000,49550.57000000,49900.99000000,49433.88000000,49551.44000000,1952.16124400,1615089599999,96921817.82949490,45080,1107.94368900,55006437.20451545,0 -1615089600000,49551.43000000,49687.98000000,49296.80000000,49436.18000000,1523.22473900,1615093199999,75402078.26888658,39760,800.13952600,39611555.27593347,0 -1615093200000,49436.18000000,49459.25000000,49111.11000000,49342.00000000,1579.32018600,1615096799999,77820439.49386912,42161,804.41909400,39636770.77620378,0 -1615096800000,49342.00000000,49650.00000000,49146.68000000,49458.56000000,1487.21177300,1615100399999,73428065.58674330,40988,782.70461900,38646695.30076986,0 -1615100400000,49459.61000000,50179.17000000,49327.57000000,50052.68000000,1987.00673700,1615103999999,98810047.42277223,59667,1170.22996700,58216821.35403710,0 -1615104000000,50041.84000000,50839.54000000,50041.84000000,50383.09000000,4309.51042700,1615107599999,217681721.76721014,102837,2278.35695200,115075147.33173563,0 -1615107600000,50384.11000000,51148.22000000,50384.11000000,50943.02000000,4216.98337700,1615111199999,214282778.69557453,92581,1954.81008400,99350510.16871535,0 -1615111200000,50942.82000000,50985.84000000,50448.30000000,50612.92000000,2825.81054000,1615114799999,143295200.53975447,77271,1378.18459300,69882515.37060364,0 -1615114800000,50612.92000000,50899.22000000,50472.81000000,50705.52000000,2058.27371500,1615118399999,104312732.69251849,95481,966.46236400,48974258.26926097,0 -1615118400000,50705.52000000,50827.68000000,50391.19000000,50746.20000000,1924.67203300,1615121999999,97483869.91578244,98865,982.09945300,49745023.69876585,0 -1615122000000,50746.20000000,50850.00000000,50504.22000000,50764.44000000,1476.16870900,1615125599999,74825391.39357174,78201,786.47793900,39869761.83968621,0 -1615125600000,50764.44000000,51250.00000000,50130.65000000,50646.34000000,3464.33850600,1615129199999,175437666.26768617,132882,1812.38114600,91831991.42017184,0 -1615129200000,50644.47000000,50827.93000000,50375.00000000,50585.23000000,1711.75694000,1615132799999,86620570.80002084,82961,831.83894100,42101517.74190130,0 -1615132800000,50585.23000000,51352.10000000,50585.23000000,51052.90000000,3580.06799000,1615136399999,182478941.68802877,142491,1928.84970800,98306982.13874969,0 -1615136400000,51052.89000000,51201.00000000,50757.59000000,51075.93000000,2180.45262000,1615139999999,111189339.99283847,72122,1004.53434100,51215894.92970774,0 -1615140000000,51075.92000000,51085.71000000,50368.20000000,50412.31000000,1905.27267300,1615143599999,96571297.83960345,55137,823.15249100,41713682.58501177,0 -1615143600000,50412.31000000,50580.21000000,50250.00000000,50381.68000000,1644.62770800,1615147199999,82922192.40165974,56614,777.78155300,39217774.29134322,0 -1615147200000,50381.69000000,50381.69000000,49758.01000000,50036.64000000,2640.36389100,1615150799999,131910392.54777115,75982,1291.97714300,64531393.41747630,0 -1615150800000,50036.63000000,50265.81000000,49833.08000000,50086.12000000,1456.99025200,1615154399999,72905828.80531929,46097,737.53448100,36904326.21658190,0 -1615154400000,50086.11000000,50784.12000000,49986.39000000,50498.55000000,1517.24544000,1615157999999,76506985.44567601,57815,805.72865300,40637640.32013040,0 -1615158000000,50498.56000000,51450.03000000,50480.89000000,50971.75000000,2947.46511100,1615161599999,150433067.08092704,90430,1501.26169000,76646327.80473961,0 -1615161600000,50959.11000000,51685.00000000,50843.59000000,51491.10000000,3257.85465200,1615165199999,167532220.80472599,87283,1664.75015900,85625625.09715073,0 -1615165200000,51491.10000000,51847.38000000,51250.05000000,51557.70000000,2584.40645400,1615168799999,133321736.21101052,68603,1386.32360900,71527975.71411801,0 -1615168800000,51557.70000000,51594.22000000,50481.84000000,50730.82000000,2903.06562400,1615172399999,148006873.56592111,91650,1345.21497000,68578272.37141787,0 -1615172400000,50730.82000000,50808.32000000,50234.98000000,50598.49000000,2601.68625600,1615175999999,131406016.57716334,78549,1357.85207700,68578506.12065437,0 -1615176000000,50598.49000000,50598.50000000,50100.00000000,50417.44000000,2251.80367300,1615179599999,113395708.42521138,74157,976.48451800,49163995.41399760,0 -1615179600000,50417.45000000,50816.16000000,50355.16000000,50765.77000000,2044.28415900,1615183199999,103420379.41058103,50504,869.21726000,43967243.94008993,0 -1615183200000,50765.77000000,50944.00000000,50150.42000000,50274.76000000,2858.16042200,1615186799999,144355922.99870986,68636,1336.25596400,67455288.09774121,0 -1615186800000,50274.76000000,50427.53000000,49521.20000000,49755.24000000,4023.21432200,1615190399999,200668275.32925711,144588,1873.21801200,93429823.19165830,0 -1615190400000,49755.24000000,49888.59000000,49274.67000000,49880.35000000,3692.48248300,1615193999999,183134555.22723845,113084,2047.76088700,101577562.53025498,0 -1615194000000,49880.49000000,50099.97000000,49400.00000000,49880.00000000,2802.45034100,1615197599999,139353571.38893106,87412,1425.30809600,70870549.56441601,0 -1615197600000,49883.13000000,50271.67000000,49682.30000000,50061.00000000,2791.02336900,1615201199999,139630861.87948468,83384,1306.78230300,65377786.40296342,0 -1615201200000,50061.01000000,50560.00000000,49878.00000000,50496.82000000,2218.68353400,1615204799999,111303263.46838359,67392,1046.06135000,52500038.21727070,0 -1615204800000,50490.39000000,50550.00000000,50100.01000000,50275.00000000,2463.59128000,1615208399999,123859515.93219230,106998,1230.16748800,61832507.38718820,0 -1615208400000,50274.58000000,51065.63000000,50265.16000000,50978.43000000,3657.93876700,1615211999999,185567165.97821940,96513,1959.70080200,99433094.01405771,0 -1615212000000,50978.42000000,51233.00000000,50122.45000000,50740.90000000,3500.51925400,1615215599999,177662740.73706399,90866,1728.69959400,87764612.54062723,0 -1615215600000,50744.26000000,51220.00000000,50541.67000000,51054.99000000,3226.78819100,1615219199999,164440816.09683350,100209,1585.30549900,80788201.25393567,0 -1615219200000,51055.00000000,51175.00000000,50550.01000000,50664.91000000,2348.85657100,1615222799999,119420974.82149234,94450,1086.43708300,55242344.20254800,0 -1615222800000,50664.91000000,50880.00000000,50630.00000000,50809.04000000,1704.21204600,1615226399999,86504651.13651521,50012,847.61082300,43022964.53166323,0 -1615226400000,50801.55000000,51075.40000000,50732.36000000,50803.18000000,1705.52357700,1615229999999,86766065.46065339,55683,906.68032900,46127826.51742071,0 -1615230000000,50803.19000000,51485.35000000,50790.00000000,51310.82000000,2750.06832100,1615233599999,140806609.39956926,78017,1554.60407500,79595830.83252232,0 -1615233600000,51310.82000000,51996.58000000,51236.20000000,51759.63000000,3743.68592700,1615237199999,193227154.41797584,91822,2046.41460200,105638054.54415526,0 -1615237200000,51762.77000000,51927.00000000,51505.00000000,51848.33000000,2386.92988300,1615240799999,123383951.07238626,69111,1226.12339700,63380257.47346715,0 -1615240800000,51848.34000000,51900.00000000,51300.00000000,51599.99000000,2086.90564400,1615244399999,107715294.63750250,64080,996.38337000,51424034.54236948,0 -1615244400000,51599.99000000,52402.78000000,51599.99000000,52375.17000000,3383.22491400,1615247999999,175963606.05905191,86398,1792.07330300,93215403.60381130,0 -1615248000000,52375.18000000,52540.48000000,51789.41000000,52020.23000000,3791.40283500,1615251599999,197912696.36021609,87276,1664.14966100,86874880.25037327,0 -1615251600000,52020.24000000,53760.00000000,51981.26000000,53575.35000000,7510.12043300,1615255199999,399283702.06985720,175064,3768.11309800,200164678.25920825,0 -1615255200000,53575.35000000,53799.00000000,53250.41000000,53592.70000000,3698.60810800,1615258799999,197955885.60833725,85448,1754.37336900,93895295.30641556,0 -1615258800000,53592.84000000,54100.00000000,53452.47000000,53840.62000000,3755.86080800,1615262399999,202076703.45060345,123817,2013.20313100,108337810.89619365,0 -1615262400000,53840.63000000,54040.00000000,53484.44000000,53678.88000000,2461.50389000,1615265999999,132389835.35042694,105442,1212.58073500,65232255.48113861,0 -1615266000000,53684.14000000,54400.80000000,53681.44000000,54254.52000000,3270.83220000,1615269599999,177122662.01191597,105492,1617.87522500,87612894.14903043,0 -1615269600000,54254.52000000,54448.00000000,53737.00000000,53847.64000000,3100.27232600,1615273199999,167775430.98412366,105727,1472.88790800,79711132.13164485,0 -1615273200000,53847.64000000,53890.92000000,53409.57000000,53546.90000000,3215.78379400,1615276799999,172686602.92112191,89948,1660.18673600,89151626.76902997,0 -1615276800000,53546.89000000,54168.99000000,53274.96000000,54023.79000000,2853.62344200,1615280399999,153610890.80429791,85740,1417.53674300,76321973.66824262,0 -1615280400000,54023.79000000,54270.27000000,53872.05000000,54112.50000000,2719.14579200,1615283999999,147119316.09875463,109901,1324.06080600,71645321.27726512,0 -1615284000000,54112.50000000,54355.00000000,53875.00000000,54159.52000000,3441.45900400,1615287599999,186327392.60715713,84266,1855.50604200,100465270.82105504,0 -1615287600000,54159.52000000,54293.97000000,53917.21000000,54233.32000000,2086.75598400,1615291199999,112971333.32137995,74794,1091.29870400,59083177.99982496,0 -1615291200000,54235.88000000,54236.70000000,53538.77000000,53725.50000000,2514.80248000,1615294799999,135616547.02971201,85101,1219.35717200,65770018.74282352,0 -1615294800000,53725.49000000,54815.84000000,53664.21000000,54779.99000000,4188.62268200,1615298399999,227723165.86607819,95413,2150.28053700,116843910.89693138,0 -1615298400000,54780.26000000,54787.99000000,54364.32000000,54488.22000000,3828.42272800,1615301999999,208801703.42261675,88343,1713.49493600,93455110.78079582,0 -1615302000000,54491.33000000,54515.22000000,53852.36000000,54097.02000000,3283.75887800,1615305599999,178144082.57325058,87761,1620.73577500,87930796.04115975,0 -1615305600000,54097.03000000,54338.00000000,53750.00000000,54098.11000000,2509.81294500,1615309199999,135766937.13154166,81155,1198.87510800,64862537.00357689,0 -1615309200000,54098.10000000,54272.05000000,53770.71000000,53793.76000000,1643.37624400,1615312799999,88748904.97034261,55343,756.51538000,40857782.17084192,0 -1615312800000,53793.75000000,54046.78000000,53626.97000000,53885.96000000,1917.18194000,1615316399999,103252757.97341270,64916,853.52832300,45971308.90448470,0 -1615316400000,53885.96000000,54225.35000000,53790.00000000,54108.79000000,1688.78796300,1615319999999,91204342.10730320,52793,764.36135600,41284647.62990380,0 -1615320000000,54108.79000000,54584.19000000,54052.76000000,54326.14000000,2231.22065500,1615323599999,121220201.85818624,64958,919.93164000,49982072.82172721,0 -1615323600000,54326.14000000,54519.47000000,53882.52000000,54278.61000000,2200.55778200,1615327199999,119259800.97293867,107247,991.92819400,53764999.76525669,0 -1615327200000,54278.61000000,54860.28000000,54139.10000000,54808.75000000,1795.94455500,1615330799999,97889012.49945934,110379,998.30357900,54433604.60717156,0 -1615330800000,54808.76000000,54895.00000000,54474.99000000,54884.50000000,1948.87960800,1615334399999,106591056.66186947,68074,972.45692800,53191667.31053432,0 -1615334400000,54874.67000000,55763.00000000,54782.93000000,55510.00000000,5030.93125900,1615337999999,278163888.80423138,123240,2865.37255900,158451994.67947400,0 -1615338000000,55510.01000000,55813.09000000,54468.26000000,54676.87000000,3691.17587200,1615341599999,203388526.25539069,108462,1723.70589000,95018007.02153540,0 -1615341600000,54676.86000000,54676.87000000,53300.00000000,53936.44000000,5819.53214700,1615345199999,313787381.36255326,184750,2818.00969300,151971986.61652164,0 -1615345200000,53936.43000000,54126.67000000,53134.80000000,53467.80000000,3497.09674400,1615348799999,187553477.50767544,128407,1721.73624900,92340567.68327365,0 -1615348800000,53468.33000000,53837.16000000,53332.46000000,53647.63000000,1979.67065800,1615352399999,106022641.77677777,90802,1016.04946000,54420863.19915381,0 -1615352400000,53647.63000000,53692.21000000,53005.00000000,53651.39000000,2203.22310100,1615355999999,117817036.44144045,61148,1003.51678300,53671721.06711454,0 -1615356000000,53651.38000000,54065.65000000,53510.01000000,53864.41000000,2538.97931000,1615359599999,136586624.91054384,66401,1181.66589300,63576141.89829709,0 -1615359600000,53864.40000000,54407.74000000,53826.26000000,54173.38000000,3010.88572800,1615363199999,163063921.96133852,73576,1305.89170000,70694918.41897156,0 -1615363200000,54177.47000000,54734.96000000,54032.38000000,54632.79000000,2225.61026900,1615366799999,121263076.05268722,68375,1075.33229800,58597179.33791266,0 -1615366800000,54632.78000000,55444.00000000,54300.11000000,55227.99000000,3499.58051200,1615370399999,192174619.38342005,117610,1883.97487600,103469981.96843685,0 -1615370400000,55228.00000000,55389.00000000,54679.95000000,54832.98000000,2604.47748200,1615373999999,143232395.10989021,74415,1258.61416200,69219098.23965225,0 -1615374000000,54832.99000000,54991.00000000,54512.00000000,54858.47000000,2400.09979600,1615377599999,131435336.54839869,72473,1242.54503400,68049556.66874276,0 -1615377600000,54858.47000000,55481.28000000,54834.00000000,55219.99000000,2894.17949200,1615381199999,159715138.18974388,96315,1435.42521300,79210645.41164055,0 -1615381200000,55219.99000000,56333.00000000,55139.01000000,56262.56000000,5022.45430700,1615384799999,280601614.94202186,168592,2834.61204000,158395300.22812159,0 -1615384800000,56260.09000000,56400.00000000,55761.66000000,56092.62000000,4222.23944600,1615388399999,236711475.65369735,105277,2216.06998300,124253250.76830775,0 -1615388400000,56092.62000000,56489.66000000,55952.63000000,56328.81000000,3869.22929400,1615391999999,217544118.14182842,119846,2033.89209200,114362468.87187820,0 -1615392000000,56328.81000000,57075.92000000,56100.00000000,57009.53000000,4890.44202100,1615395599999,276608476.15814133,158136,2688.45561000,152151018.94701652,0 -1615395600000,57009.53000000,57100.00000000,56366.00000000,56860.01000000,4201.85636100,1615399199999,238726485.19676862,112830,2078.51722400,118097883.35913201,0 -1615399200000,56860.01000000,57100.00000000,56566.00000000,56730.54000000,3021.74944600,1615402799999,171672296.48973269,112253,1527.95686100,86833386.89608197,0 -1615402800000,56730.55000000,57387.69000000,56595.76000000,56739.40000000,3678.78143400,1615406399999,209778225.64322700,113397,1948.74731500,111142625.66022464,0 -1615406400000,56739.40000000,56894.11000000,56037.15000000,56266.00000000,4313.70234300,1615409999999,243351448.84513943,103580,2056.77838800,116032467.81399536,0 -1615410000000,56266.00000000,57045.22000000,55530.01000000,56918.40000000,4757.62006100,1615413599999,267433343.98345132,137896,2238.29399300,125891109.13654264,0 -1615413600000,56919.10000000,57225.73000000,56476.95000000,56905.37000000,2148.26032300,1615417199999,122097690.91867705,122720,1031.85684900,58640715.97042828,0 -1615417200000,56905.37000000,56950.00000000,55800.00000000,55851.59000000,3227.46153700,1615420799999,181468323.08243598,126783,1464.86724000,82363403.00431579,0 -1615420800000,55851.59000000,56499.98000000,55505.00000000,55601.55000000,3761.55064900,1615424399999,210353015.90269695,90868,1696.50550100,94915524.54606974,0 -1615424400000,55607.55000000,55947.36000000,55170.22000000,55781.92000000,2880.27800500,1615427999999,159874580.29863754,101593,1368.35340200,75951107.75153002,0 -1615428000000,55781.91000000,56323.51000000,55649.93000000,56314.58000000,2435.82663700,1615431599999,136454058.76350731,75084,1144.62183700,64131823.51034431,0 -1615431600000,56316.41000000,56483.11000000,55599.00000000,55992.60000000,2196.10924700,1615435199999,122958150.58607872,55310,1008.88913300,56489560.21144334,0 -1615435200000,55992.60000000,56179.87000000,55603.66000000,55835.40000000,1923.30227900,1615438799999,107433105.09803673,53208,867.97644500,48494019.10522811,0 -1615438800000,55835.39000000,55835.39000000,55200.80000000,55275.32000000,2300.08825500,1615442399999,127532060.63464739,59755,1026.44407700,56917529.14522981,0 -1615442400000,55275.32000000,55767.15000000,55005.00000000,55557.94000000,2896.87139900,1615445999999,160614869.33489713,88276,1212.49627000,67219434.03965599,0 -1615446000000,55555.13000000,55797.07000000,55005.00000000,55034.20000000,2820.53245100,1615449599999,156384279.72275556,67395,1232.04863500,68339656.64406550,0 -1615449600000,55034.21000000,55093.53000000,54272.82000000,54761.02000000,5458.58310800,1615453199999,298607963.54632673,163889,2560.04374100,140024508.03798743,0 -1615453200000,54761.01000000,54928.43000000,54431.86000000,54474.27000000,2587.03118800,1615456799999,141452638.84688428,104738,1153.32501000,63068186.21338541,0 -1615456800000,54474.27000000,55612.95000000,54414.40000000,55530.60000000,3587.14363000,1615460399999,197503390.76972889,103026,1736.73689000,95653283.58413024,0 -1615460400000,55530.59000000,56270.75000000,55407.18000000,56227.34000000,3528.16672500,1615463999999,196688903.37317042,137451,1746.61171400,97389590.63372770,0 -1615464000000,56233.42000000,56445.09000000,55702.09000000,56272.54000000,3821.53970800,1615467599999,214419408.69514294,120863,2079.66945400,116708252.86877621,0 -1615467600000,56275.00000000,56999.00000000,56272.54000000,56921.18000000,3907.83970500,1615471199999,221504818.85517440,105871,2166.02927900,122786018.61260917,0 -1615471200000,56921.18000000,57238.50000000,56462.48000000,56815.13000000,4930.07917700,1615474799999,280477535.35700521,113826,2610.84844900,148553409.34894555,0 -1615474800000,56815.13000000,57091.06000000,55855.00000000,56347.19000000,4918.27352200,1615478399999,277865272.78465665,132208,2348.87395600,132736207.88730156,0 -1615478400000,56347.19000000,57030.00000000,56340.06000000,56872.10000000,3501.18927600,1615481999999,198572717.14887414,111203,1874.83613400,106345667.99200097,0 -1615482000000,56872.10000000,57050.00000000,56269.76000000,56802.88000000,3424.87557200,1615485599999,194291111.72167817,118769,1684.21031000,95569536.95695499,0 -1615485600000,56802.88000000,57682.00000000,56531.67000000,57519.86000000,4910.64605200,1615489199999,281082821.13913408,164860,2879.09497200,164857199.07505495,0 -1615489200000,57519.86000000,57651.35000000,56628.03000000,56827.84000000,2840.07287800,1615492799999,162499210.35406519,95082,1414.14052500,80929865.24310701,0 -1615492800000,56823.78000000,57600.00000000,56560.00000000,57457.36000000,3049.18616700,1615496399999,174323211.05670353,113435,1521.53775300,87003639.98001721,0 -1615496400000,57457.36000000,57900.00000000,57235.29000000,57562.49000000,4464.24661700,1615499999999,257564954.44470721,118133,2252.67833000,129995977.23068369,0 -1615500000000,57573.70000000,58050.00000000,57462.12000000,57874.67000000,2810.01435900,1615503599999,162377609.21271529,136545,1485.20548800,85852721.92193145,0 -1615503600000,57882.57000000,58150.00000000,57604.16000000,57773.16000000,2961.36625300,1615507199999,171530513.35499559,78582,1532.27236300,88772098.55492637,0 -1615507200000,57773.15000000,58081.51000000,56777.77000000,57362.04000000,4018.33941800,1615510799999,230508156.35945129,134725,1818.08041000,104320105.25958165,0 -1615510800000,57362.05000000,57640.34000000,56624.00000000,56902.80000000,2607.21431900,1615514399999,149079401.68997003,114182,1240.52590800,70947086.08468645,0 -1615514400000,56902.80000000,57120.67000000,56700.00000000,56972.08000000,1664.62869900,1615517999999,94746373.78696695,70797,794.81942400,45243034.81560026,0 -1615518000000,56972.08000000,57294.47000000,56800.00000000,57104.17000000,1559.93359700,1615521599999,88961260.28276833,49973,761.14216000,43413589.44827765,0 -1615521600000,57107.14000000,57238.70000000,56456.58000000,56696.17000000,2369.87029900,1615525199999,134411337.01335934,66996,1031.56377100,58510635.64214419,0 -1615525200000,56696.18000000,57269.87000000,56350.00000000,57164.51000000,2283.87379200,1615528799999,129789530.71142608,69906,1128.04023600,64124927.24905406,0 -1615528800000,57168.24000000,57430.00000000,56894.49000000,57061.52000000,2057.80177800,1615532399999,117619076.35749922,68727,1035.96080400,59220887.22747215,0 -1615532400000,57061.52000000,57061.53000000,56456.71000000,56670.90000000,2870.52267600,1615535999999,162772861.65533323,77700,1440.14415300,81661907.25243049,0 -1615536000000,56670.90000000,57095.76000000,56259.79000000,56503.21000000,3164.29780600,1615539599999,179199309.03937183,98671,1533.97206400,86892152.12575596,0 -1615539600000,56506.71000000,56819.42000000,56311.00000000,56540.53000000,2384.20281800,1615543199999,134846075.46292302,72558,1096.98013800,62041774.84713004,0 -1615543200000,56540.53000000,56866.83000000,55826.05000000,56715.97000000,3955.42674200,1615546799999,222654294.08345982,111261,1931.75464500,108780158.60526391,0 -1615546800000,56715.97000000,57073.48000000,56347.00000000,56500.00000000,2990.14879600,1615550399999,169660312.34448261,143232,1436.44442200,81511264.82595460,0 -1615550400000,56499.99000000,56844.61000000,56179.47000000,56386.89000000,2404.35050800,1615553999999,135679621.30430332,87431,1167.11705000,65871600.70213599,0 -1615554000000,56385.97000000,56391.25000000,54962.84000000,55689.99000000,8573.23928300,1615557599999,476655241.56194007,258557,3933.54816400,218767849.41357745,0 -1615557600000,55689.99000000,56252.77000000,55368.42000000,56211.83000000,3760.79857900,1615561199999,209965143.95426218,142307,1899.51679500,106074466.50853060,0 -1615561200000,56221.53000000,57095.41000000,56025.20000000,56956.95000000,4384.39718600,1615564799999,248013123.58209527,140803,2373.42698400,134272670.05564597,0 -1615564800000,56956.96000000,57625.91000000,56956.95000000,57367.21000000,4127.97399200,1615568399999,236584058.17017194,120676,2255.18753800,129253583.05823978,0 -1615568400000,57367.21000000,57768.00000000,57062.31000000,57175.99000000,2912.77803200,1615571999999,167389828.43288778,105122,1337.48670200,76849459.49283539,0 -1615572000000,57175.26000000,57667.79000000,57070.00000000,57349.23000000,2355.16939400,1615575599999,135217315.90090701,64578,1254.78695300,72036826.11114289,0 -1615575600000,57349.24000000,57547.07000000,56712.51000000,56942.41000000,2759.49276100,1615579199999,157560117.21653335,76856,1346.64805100,76894391.52923280,0 -1615579200000,56942.41000000,57200.00000000,56400.00000000,56696.80000000,3482.30673400,1615582799999,197381435.60371237,103916,1628.03761400,92278016.38806870,0 -1615582800000,56696.81000000,57170.00000000,56262.14000000,56936.78000000,2554.41954900,1615586399999,144882646.37166268,123258,1234.56876500,70050444.56596873,0 -1615586400000,56936.78000000,57465.38000000,56859.06000000,57157.29000000,2252.89020400,1615589999999,128889329.20606505,107068,1090.60234600,62389139.17149281,0 -1615590000000,57157.29000000,57500.00000000,57153.68000000,57221.72000000,1911.32908500,1615593599999,109588876.28728603,80631,1032.58636500,59210330.09320884,0 -1615593600000,57221.72000000,57307.20000000,56312.91000000,56689.35000000,2913.36172600,1615597199999,165168452.54477606,113394,1417.09885200,80336764.68534269,0 -1615597200000,56689.36000000,56707.00000000,56081.59000000,56386.39000000,2358.62457700,1615600799999,132887326.66178754,74110,1151.11350100,64862774.93364839,0 -1615600800000,56386.39000000,56639.54000000,56078.23000000,56473.41000000,2183.69769500,1615604399999,123160401.31981544,60691,1223.91871700,69032245.32164948,0 -1615604400000,56473.41000000,56790.00000000,56308.98000000,56694.32000000,1902.37529900,1615607999999,107744212.64804490,54805,950.26145200,53819559.32391189,0 -1615608000000,56694.32000000,56899.00000000,56257.47000000,56896.32000000,1547.93218100,1615611599999,87520342.53587563,52050,782.23049200,44236447.06928076,0 -1615611600000,56882.74000000,57090.46000000,56610.00000000,56744.89000000,1432.00306800,1615615199999,81423246.77819168,49512,683.34391900,38858981.70426900,0 -1615615200000,56744.89000000,57060.86000000,56491.92000000,56931.58000000,1759.40972700,1615618799999,99851921.21550119,57668,1017.24287500,57722872.08075861,0 -1615618800000,56931.57000000,57389.58000000,56753.90000000,57343.70000000,1998.20036800,1615622399999,113909858.80102126,69690,1028.78919900,58662494.06794287,0 -1615622400000,57343.70000000,57649.03000000,57126.20000000,57434.31000000,2957.35947100,1615625999999,169868896.01532680,85667,1636.12207400,93990427.23668130,0 -1615626000000,57434.30000000,57614.52000000,57253.31000000,57610.77000000,1827.03931000,1615629599999,104898332.10026139,62926,960.81918100,55167917.14087029,0 -1615629600000,57610.77000000,59850.00000000,57446.81000000,59448.19000000,12696.97324300,1615633199999,750024013.95725474,308276,6970.79882700,411352961.91663017,0 -1615633200000,59448.20000000,60200.00000000,59420.99000000,59849.74000000,9101.22864900,1615636799999,544708721.09328957,230042,5410.48940700,323841046.32586433,0 -1615636800000,59853.58000000,60500.00000000,59232.53000000,59911.99000000,5886.08542200,1615640399999,352958744.72774301,152578,2983.04807900,178934553.17226557,0 -1615640400000,59911.99000000,60159.45000000,59500.00000000,59915.25000000,3621.79620900,1615643999999,216545084.88078375,125555,1860.58251200,111263139.20593685,0 -1615644000000,59915.30000000,60087.09000000,59700.67000000,59756.45000000,2295.31131800,1615647599999,137491113.63501919,123378,1178.62234500,70603882.18347910,0 -1615647600000,59761.93000000,59953.63000000,59523.00000000,59692.99000000,2357.24358600,1615651199999,140901493.52422564,109010,1038.61150400,62081067.12577019,0 -1615651200000,59693.00000000,59924.18000000,59458.67000000,59820.43000000,2721.30396300,1615654799999,162527909.67512986,78798,1488.98656700,88925467.77484757,0 -1615654800000,59820.39000000,60520.00000000,59751.70000000,60333.33000000,3328.78742800,1615658399999,200018042.39036289,90171,1629.79518600,97905366.36486346,0 -1615658400000,60333.33000000,60451.39000000,59977.60000000,60281.95000000,2419.09522400,1615661999999,145583487.30112188,73902,1202.73477600,72388179.96026483,0 -1615662000000,60281.95000000,60864.97000000,60144.20000000,60773.56000000,3093.95316800,1615665599999,187200648.05200946,92026,1723.99670400,104318320.72619846,0 -1615665600000,60773.56000000,61844.00000000,60651.74000000,61648.26000000,6042.50281900,1615669199999,370846057.04175508,162598,3694.46812800,226772352.26017361,0 -1615669200000,61648.26000000,61737.02000000,60605.50000000,61151.07000000,4486.03221700,1615672799999,274099735.55532582,163963,2167.40269400,132488084.65847787,0 -1615672800000,61156.40000000,61311.19000000,60767.62000000,61096.04000000,1770.67694100,1615676399999,108082107.64509043,100492,870.90845200,53168252.09290489,0 -1615676400000,61091.75000000,61480.00000000,61089.98000000,61188.39000000,2544.09773700,1615679999999,155963303.14626481,67700,1315.84647500,80657657.44076047,0 -1615680000000,61188.38000000,61724.79000000,60900.00000000,61260.48000000,2902.15756100,1615683599999,178152245.82840269,78033,1479.97667400,90847893.62271734,0 -1615683600000,61260.47000000,61260.48000000,60724.26000000,61081.00000000,2275.23627800,1615687199999,138789298.91416191,70486,1047.79405500,63914782.16084928,0 -1615687200000,61081.00000000,61218.20000000,60788.01000000,61061.27000000,1563.80244800,1615690799999,95357203.88183232,64760,802.93989200,48962245.42333133,0 -1615690800000,61061.28000000,61472.08000000,60900.00000000,61356.31000000,1564.46519700,1615694399999,95843858.04768765,48896,785.52393200,48122174.79458445,0 -1615694400000,61356.30000000,61595.09000000,61088.67000000,61225.53000000,1478.03990500,1615697999999,90606709.62163290,50459,785.00741000,48134610.92757440,0 -1615698000000,61225.54000000,61285.41000000,60903.96000000,61016.29000000,1714.88950900,1615701599999,104720513.49644333,46898,899.67837300,54930777.67156941,0 -1615701600000,61016.29000000,61016.30000000,60523.14000000,60975.39000000,2353.14978300,1615705199999,143136145.20747868,61901,1136.06327400,69101977.93047488,0 -1615705200000,60975.39000000,60975.39000000,60455.28000000,60494.80000000,1519.28971800,1615708799999,92234962.64422141,56073,704.87003800,42795620.94834144,0 -1615708800000,60494.80000000,60871.03000000,60250.01000000,60787.75000000,2163.70124000,1615712399999,131189408.73618039,98980,1075.27290900,65197075.16781411,0 -1615712400000,60787.75000000,61110.53000000,60618.00000000,60934.11000000,1847.33840300,1615715999999,112600404.62197312,55882,868.62255900,52950318.77186565,0 -1615716000000,60933.62000000,60970.00000000,60135.37000000,60293.09000000,2947.30181100,1615719599999,178349426.28366977,85222,1530.03164500,92592255.68971744,0 -1615719600000,60293.08000000,60405.03000000,59354.62000000,60308.31000000,4632.32120400,1615723199999,277582980.75469308,175131,2195.46267400,131591203.91019273,0 -1615723200000,60308.30000000,60550.00000000,60140.96000000,60427.82000000,2296.79355700,1615726799999,138632917.16206044,73366,1097.82405300,66268257.78031005,0 -1615726800000,60427.81000000,60481.70000000,59734.03000000,59940.00000000,2543.07988300,1615730399999,152769221.56988017,82975,1205.33089600,72403815.66563478,0 -1615730400000,59940.00000000,60477.83000000,59868.12000000,60001.91000000,1950.74360500,1615733999999,117410605.02275073,63605,1001.67006300,60290558.84116310,0 -1615734000000,60001.90000000,60150.00000000,59470.00000000,59681.26000000,2495.61525600,1615737599999,149336242.94249174,76701,1064.23896100,63721696.97498350,0 -1615737600000,59681.21000000,60066.59000000,59300.00000000,59567.74000000,3099.34760800,1615741199999,184953713.99594900,120192,1377.26474400,82198780.32783666,0 -1615741200000,59567.74000000,60023.07000000,59523.66000000,59701.10000000,1638.55137800,1615744799999,97971937.36521324,89045,829.24043300,49596173.31314670,0 -1615744800000,59701.10000000,60369.99000000,59700.00000000,60138.31000000,1579.17760400,1615748399999,94907457.27258277,64152,846.77215100,50891878.69917035,0 -1615748400000,60138.31000000,60200.00000000,59789.74000000,59931.70000000,1318.69249000,1615751999999,79162190.55300161,55188,619.65932700,37195690.01610081,0 -1615752000000,59928.71000000,60325.98000000,59702.78000000,60264.48000000,1677.50289300,1615755599999,100584010.81332785,57797,795.01996600,47679877.50516328,0 -1615755600000,60264.48000000,60485.08000000,59852.18000000,60081.54000000,1480.96127700,1615759199999,89065134.54869998,57633,732.28274800,44037662.87055341,0 -1615759200000,60081.55000000,60324.43000000,59733.38000000,60201.19000000,1414.97297300,1615762799999,84965673.31902896,53647,633.95168400,38072956.04917135,0 -1615762800000,60201.19000000,60750.00000000,58966.78000000,58968.31000000,4143.92116900,1615766399999,248075311.28127877,142747,1810.76858900,108552720.33577378,0 -1615766400000,58976.08000000,59917.78000000,58705.47000000,59404.48000000,4470.86309900,1615769999999,265713953.23734152,100243,2528.17046300,150316819.44283939,0 -1615770000000,59404.48000000,60251.42000000,59227.52000000,60066.56000000,2965.91702300,1615773599999,177264954.87272399,80765,1686.30905400,100744333.35911317,0 -1615773600000,60066.56000000,60331.02000000,60037.61000000,60069.63000000,1776.36213400,1615777199999,106937773.31051113,56984,969.20763300,58344923.59552751,0 -1615777200000,60069.63000000,60491.47000000,60069.62000000,60379.99000000,1353.80793600,1615780799999,81603410.21082850,48278,689.84765400,41586267.39876213,0 -1615780800000,60379.99000000,60633.43000000,59658.87000000,59773.71000000,2437.90966500,1615784399999,146672139.53938653,68290,1186.42199500,71396347.27299430,0 -1615784400000,59773.70000000,59916.24000000,59005.00000000,59013.35000000,3320.90935200,1615787999999,197532625.47269636,81960,1585.25655700,94305122.29442164,0 -1615788000000,59019.39000000,59365.42000000,58421.00000000,58781.49000000,4947.78241200,1615791599999,291146694.77416573,130536,2194.57443400,129180466.61114140,0 -1615791600000,58783.38000000,58792.57000000,57253.00000000,57789.76000000,8895.35121600,1615795199999,515335194.02854789,208289,3768.96655700,218358307.60227077,0 -1615795200000,57789.75000000,58350.00000000,57500.00000000,57757.70000000,4975.32173200,1615798799999,288336805.06503649,119653,2424.43659300,140511615.46207805,0 -1615798800000,57757.71000000,58100.00000000,54600.00000000,55867.91000000,16138.46740100,1615802399999,905203244.19086457,325051,7435.24769500,416798260.80812348,0 -1615802400000,55871.29000000,56438.00000000,55555.55000000,56355.14000000,5624.83382900,1615805999999,315479252.50055925,153767,2615.80008500,146712393.30472208,0 -1615806000000,56355.13000000,56576.37000000,55888.01000000,56150.79000000,4161.88247500,1615809599999,234126646.76055732,137998,2003.62985100,112723665.39977284,0 -1615809600000,56150.80000000,56481.38000000,55050.00000000,56439.53000000,6180.17600300,1615813199999,344675696.13245714,133436,3111.95745300,173549833.79185964,0 -1615813200000,56439.54000000,57046.87000000,56250.48000000,56855.58000000,4832.09007800,1615816799999,274254493.32146787,124306,2321.19488900,131723807.43708121,0 -1615816800000,56855.58000000,57312.47000000,56123.12000000,56134.09000000,4699.21633300,1615820399999,267295233.12895629,143725,2203.52400400,125368219.14239431,0 -1615820400000,56134.09000000,56816.69000000,55854.20000000,56224.13000000,4402.38440100,1615823999999,247998456.87422206,96774,2407.06727300,135606156.46048522,0 -1615824000000,56224.14000000,56700.00000000,55669.28000000,56247.87000000,4462.95611200,1615827599999,251075090.05218074,153182,2259.94406500,127126686.27498670,0 -1615827600000,56261.02000000,56331.11000000,55478.01000000,56035.79000000,3315.71378600,1615831199999,185299555.94013669,116860,1603.26706300,89604950.24974911,0 -1615831200000,56034.82000000,56377.66000000,55800.00000000,56113.90000000,2345.77916800,1615834799999,131599524.68354643,64657,1239.80361500,69548719.30195049,0 -1615834800000,56113.90000000,56647.24000000,56096.80000000,56570.36000000,2094.00178400,1615838399999,118124197.63037133,71275,1090.66108800,61529446.31604523,0 -1615838400000,56570.37000000,56930.17000000,56221.00000000,56379.97000000,2748.53681400,1615841999999,155576007.81124944,75928,1325.01700800,75010039.35635407,0 -1615842000000,56379.97000000,56940.00000000,56338.56000000,56707.71000000,1725.16621500,1615845599999,97702184.79430900,61993,805.67747200,45624776.00748374,0 -1615845600000,56712.71000000,56900.00000000,55979.22000000,56136.73000000,2331.70503600,1615849199999,131374668.50131774,64676,1105.40621600,62274498.24970701,0 -1615849200000,56144.74000000,56672.00000000,55537.00000000,55605.20000000,2564.29329400,1615852799999,143913249.25993820,65189,1264.04963000,70961431.49450600,0 -1615852800000,55605.20000000,56140.55000000,53960.11000000,54088.76000000,7957.15358700,1615856399999,437202648.13417986,191332,3393.89436400,186476877.39676450,0 -1615856400000,54097.20000000,54568.42000000,53271.34000000,54471.57000000,6577.50139400,1615859999999,354381089.45398518,142568,3216.72500800,173331683.36020260,0 -1615860000000,54471.57000000,54649.95000000,54122.38000000,54567.64000000,2831.21352800,1615863599999,154093135.08368528,75225,1481.73098600,80637920.03171625,0 -1615863600000,54567.64000000,54624.99000000,53850.00000000,54272.86000000,3152.44796100,1615867199999,170852387.52141331,75978,1515.48532200,82140373.34025877,0 -1615867200000,54272.66000000,54850.00000000,54188.82000000,54418.19000000,2351.53507500,1615870799999,128281117.37242801,57980,1142.11968000,62312485.76723559,0 -1615870800000,54418.19000000,54459.08000000,53607.93000000,54096.52000000,2955.46035700,1615874399999,159632428.00944406,87512,1519.06826000,82053862.77793192,0 -1615874400000,54088.44000000,55334.77000000,53650.00000000,55060.06000000,4606.99276500,1615877999999,251599927.65034215,106911,1980.46517000,108056129.30196051,0 -1615878000000,55060.05000000,55491.00000000,54787.70000000,55239.81000000,3771.70482300,1615881599999,208210331.92943864,100358,1724.85199900,95216251.56835064,0 -1615881600000,55239.81000000,56100.00000000,55110.73000000,55894.27000000,3835.32871400,1615885199999,213901595.63400257,105005,1970.90749200,109933399.52205052,0 -1615885200000,55892.13000000,56400.00000000,55709.32000000,55870.43000000,2595.14560500,1615888799999,145272849.09308388,80280,1271.74494000,71201820.33019871,0 -1615888800000,55870.43000000,56150.05000000,55432.44000000,55805.00000000,2847.30433300,1615892399999,158917868.72733189,101166,1422.74274800,79427012.81574484,0 -1615892400000,55805.00000000,55900.00000000,55079.63000000,55471.21000000,3253.39736400,1615895999999,180370410.51099929,119308,1740.04620400,96461021.80227283,0 -1615896000000,55464.11000000,55631.57000000,54596.89000000,55091.95000000,3389.37464000,1615899599999,186675722.53714168,92060,1640.04266700,90333547.83750450,0 -1615899600000,55091.94000000,55906.86000000,55006.35000000,55324.30000000,3311.89499300,1615903199999,183623764.90859133,80400,1554.87881600,86221695.13271721,0 -1615903200000,55324.30000000,55722.55000000,55199.48000000,55645.93000000,2532.83420700,1615906799999,140545964.75380359,76281,1318.68961200,73175688.08518264,0 -1615906800000,55645.93000000,55913.57000000,55420.00000000,55844.92000000,2814.91292800,1615910399999,156715501.88552340,80479,1327.82193500,73922058.01778391,0 -1615910400000,55844.92000000,56087.02000000,55436.66000000,55657.89000000,2849.02842900,1615913999999,158841732.94560050,100571,1363.08471400,76004971.37626362,0 -1615914000000,55657.90000000,55850.99000000,54950.16000000,55250.21000000,3538.50365500,1615917599999,195923778.17482664,126985,1721.68249600,95314824.30772918,0 -1615917600000,55250.20000000,55667.95000000,55091.32000000,55349.99000000,2023.35062100,1615921199999,112029692.96213441,61640,1017.04283100,56315680.78136919,0 -1615921200000,55349.99000000,55820.00000000,55151.70000000,55731.36000000,1579.06637200,1615924799999,87714795.49289385,53288,823.00404700,45727907.58998827,0 -1615924800000,55731.36000000,56431.41000000,55673.23000000,56373.10000000,2877.44784500,1615928399999,161651593.80010455,80244,1550.92710700,87119308.17251491,0 -1615928400000,56369.86000000,56619.02000000,56083.08000000,56450.11000000,1699.81433600,1615931999999,95842718.19096621,87749,864.81714100,48773282.71847072,0 -1615932000000,56450.10000000,56820.00000000,56225.79000000,56243.43000000,2651.03478600,1615935599999,150005594.50554297,71284,1204.15907700,68143298.44410021,0 -1615935600000,56243.44000000,56938.29000000,56070.23000000,56900.75000000,1984.24603700,1615939199999,111972558.36763656,86604,1059.56887700,59810262.07292637,0 -1615939200000,56900.74000000,57189.43000000,56258.77000000,56518.57000000,3017.41179500,1615942799999,171061428.51151949,79700,1522.15582100,86311900.38341505,0 -1615942800000,56518.57000000,56535.06000000,56060.00000000,56283.40000000,1658.77751200,1615946399999,93420081.73884519,77672,792.60604400,44643219.26220265,0 -1615946400000,56283.41000000,56283.41000000,55629.34000000,55777.69000000,2010.75917400,1615949999999,112448953.68323780,112846,991.58997400,55448075.53475651,0 -1615950000000,55777.68000000,56152.41000000,55401.02000000,55506.23000000,1845.94923000,1615953599999,103036667.73348934,67859,848.76650100,47384837.81674542,0 -1615953600000,55506.23000000,55861.88000000,55401.01000000,55569.07000000,1498.02164200,1615957199999,83352718.56123611,44454,752.72640300,41883730.67841739,0 -1615957200000,55569.06000000,55970.28000000,55185.42000000,55951.37000000,2124.18924800,1615960799999,118057910.85231841,77314,1048.49974300,58285628.85644024,0 -1615960800000,55951.37000000,56326.53000000,55834.29000000,56306.84000000,2223.80240100,1615964399999,124730274.66955771,63389,1036.15118100,58122491.18894678,0 -1615964400000,56306.84000000,56322.46000000,55682.03000000,55821.01000000,1768.83825900,1615967999999,99041648.72076432,74940,803.44729100,44985306.91548634,0 -1615968000000,55819.23000000,56052.63000000,55622.94000000,55775.16000000,1931.02047100,1615971599999,107751893.61626658,62044,936.79581700,52277764.17880552,0 -1615971600000,55784.11000000,55871.05000000,54326.27000000,54762.77000000,4958.34282200,1615975199999,272971874.23444566,127316,2140.09281600,117904688.76140569,0 -1615975200000,54763.59000000,55234.88000000,54600.00000000,55088.89000000,2354.37472200,1615978799999,129491352.51325751,84505,1173.86053400,64559380.27751988,0 -1615978800000,55088.90000000,55200.00000000,54569.99000000,54840.00000000,2315.50151700,1615982399999,127134285.80518269,90616,1100.81634200,60441474.01781767,0 -1615982400000,54840.01000000,55413.63000000,54123.69000000,55151.01000000,3929.96578900,1615985999999,215310490.77771350,137146,1963.79428800,107624094.07202577,0 -1615986000000,55151.01000000,55406.79000000,54711.60000000,55105.41000000,3060.90680800,1615989599999,168599299.64973796,121106,1497.14663600,82469230.61745621,0 -1615989600000,55108.44000000,55152.48000000,54524.65000000,54548.97000000,2732.54603100,1615993199999,149859158.26320678,67724,1296.64359300,71119003.88558349,0 -1615993200000,54547.57000000,55244.03000000,54298.18000000,54930.00000000,3582.18486800,1615996799999,196551207.33039579,80629,1729.89689900,94945360.50294275,0 -1615996800000,54930.00000000,55600.27000000,54740.00000000,55275.08000000,2677.39676100,1616000399999,147973226.98216747,71997,1342.13665500,74175857.79149212,0 -1616000400000,55275.08000000,55659.93000000,55162.60000000,55542.50000000,1783.07855900,1616003999999,98799496.44741874,54185,857.00826500,47479669.26712274,0 -1616004000000,55542.50000000,57576.28000000,55542.50000000,57575.51000000,6667.37098400,1616007599999,378321072.89441844,154832,3591.51023300,203764983.57290041,0 -1616007600000,57575.51000000,58201.58000000,57329.44000000,57867.42000000,5960.95180800,1616011199999,344434829.14549266,133407,2970.35677800,171667082.00578924,0 -1616011200000,57867.42000000,58333.00000000,57709.04000000,57715.19000000,3384.95866500,1616014799999,196329088.70543287,88383,1772.89216100,102835167.85216363,0 -1616014800000,57710.93000000,58732.08000000,57601.92000000,58427.49000000,3200.25526600,1616018399999,186219950.72705665,115571,1649.64849300,96007562.23631201,0 -1616018400000,58427.49000000,58940.00000000,58234.33000000,58284.41000000,3296.26553800,1616021999999,193172893.75094541,118643,1626.83635100,95348141.72472217,0 -1616022000000,58299.98000000,58974.73000000,58236.00000000,58912.97000000,2438.75097100,1616025599999,142923166.84018515,98018,1333.36695600,78140871.27985895,0 -1616025600000,58912.97000000,59561.54000000,58709.03000000,58927.54000000,4549.11801800,1616029199999,269144816.40752417,108968,2364.27987700,139892545.35798252,0 -1616029200000,58927.53000000,59326.93000000,58758.01000000,59043.14000000,2078.67188300,1616032799999,122755934.65744768,57646,1005.39054000,59373223.94041600,0 -1616032800000,59043.13000000,59300.00000000,58908.00000000,58996.77000000,1879.60094200,1616036399999,111172999.55449290,60761,884.14754000,52292935.24279920,0 -1616036400000,58999.17000000,59058.33000000,58606.10000000,58712.33000000,1790.19748100,1616039999999,105284148.20737737,86293,840.22241000,49409421.01416344,0 -1616040000000,58712.34000000,59200.00000000,58623.85000000,58800.01000000,1944.10750100,1616043599999,114428946.48940695,66378,986.44569300,58063497.36896383,0 -1616043600000,58800.01000000,59183.96000000,58651.00000000,58957.44000000,1825.78964000,1616047199999,107606654.08827600,78974,884.13185800,52108142.48884573,0 -1616047200000,58957.43000000,59070.00000000,58650.01000000,58910.00000000,2056.93352100,1616050799999,121023138.80481180,52697,1028.90090600,60540991.57198846,0 -1616050800000,58909.99000000,58926.26000000,58119.00000000,58355.15000000,3028.61646600,1616054399999,177130313.04424154,69124,1372.10672700,80234741.54906116,0 -1616054400000,58355.14000000,58525.83000000,57899.00000000,58007.11000000,2413.16618300,1616057999999,140565936.73101818,67896,1062.36634500,61890023.72523356,0 -1616058000000,58007.11000000,58475.01000000,57936.22000000,58399.98000000,2245.14676100,1616061599999,130759852.31288753,63316,1095.37950100,63795071.49612447,0 -1616061600000,58399.98000000,58660.00000000,58221.05000000,58520.25000000,1746.54181800,1616065199999,102079058.46371358,57295,813.19083800,47527049.03234213,0 -1616065200000,58520.24000000,58550.00000000,57870.38000000,58170.37000000,2116.02090500,1616068799999,123129919.35665675,66479,987.42541500,57455402.62199199,0 -1616068800000,58168.69000000,58187.11000000,57586.31000000,58051.31000000,3297.48134200,1616072399999,190832667.23974137,121393,1603.70198000,92809239.50561036,0 -1616072400000,58051.31000000,58188.85000000,57777.00000000,57846.31000000,1998.12233000,1616075999999,115885895.93320046,65146,979.62463200,56815083.20210928,0 -1616076000000,57846.31000000,58037.35000000,57500.00000000,57863.14000000,2429.21171200,1616079599999,140366667.47553594,74499,1137.69450000,65752018.42164948,0 -1616079600000,57863.13000000,59637.39000000,57700.00000000,59533.68000000,5520.69352300,1616083199999,324789182.97982674,140483,2966.63565500,174573742.56305089,0 -1616083200000,59533.67000000,60129.97000000,59037.15000000,59080.61000000,7435.16430300,1616086799999,443802273.70528617,202184,3589.95027100,214372955.02612068,0 -1616086800000,59074.61000000,59480.00000000,59073.40000000,59250.81000000,2837.01594900,1616090399999,168260289.73092714,116412,1408.93320100,83562882.73898958,0 -1616090400000,59250.81000000,59310.13000000,58000.10000000,58221.01000000,3740.43498100,1616093999999,219147368.77852779,140677,1834.83854600,107509027.11434387,0 -1616094000000,58221.02000000,58416.56000000,57200.00000000,57293.79000000,3699.02170400,1616097599999,213974977.63845645,103954,1654.74019900,95766804.03167023,0 -1616097600000,57294.12000000,57898.66000000,57023.00000000,57508.90000000,2886.38146400,1616101199999,166099816.10098642,83598,1331.09690200,76606514.53457965,0 -1616101200000,57506.15000000,57995.00000000,57434.79000000,57900.05000000,1567.21836000,1616104799999,90568291.24721251,58003,823.22815600,47573781.80871666,0 -1616104800000,57900.06000000,58146.60000000,57623.23000000,57627.64000000,1703.48873100,1616108399999,98643846.84367895,52033,800.32859400,46345304.48002936,0 -1616108400000,57635.11000000,58036.43000000,57354.24000000,57648.16000000,1792.26115700,1616111999999,103432765.42157160,46738,832.61962500,48057292.52991381,0 -1616112000000,57641.00000000,57689.65000000,56270.74000000,56880.00000000,4455.45187500,1616115599999,253070962.09478709,100646,2047.65500000,116275710.26080408,0 -1616115600000,56880.00000000,57413.67000000,56663.23000000,57393.18000000,1844.07931800,1616119199999,105265428.45446349,56616,928.15780800,52978321.32668744,0 -1616119200000,57393.19000000,57763.00000000,57200.00000000,57358.32000000,1694.18144200,1616122799999,97307383.21843027,58815,775.78713600,44556456.19386931,0 -1616122800000,57358.31000000,57898.48000000,57298.81000000,57779.84000000,1431.32020600,1616126399999,82462970.94126710,50245,711.89017200,41013823.76315546,0 -1616126400000,57779.84000000,58259.02000000,57632.38000000,57866.12000000,1888.53228500,1616129999999,109408385.55747506,54755,980.51198600,56816146.68573658,0 -1616130000000,57866.13000000,58391.78000000,57603.92000000,58364.76000000,1694.97517700,1616133599999,98262292.53285442,65184,838.57177100,48616229.52199021,0 -1616133600000,58362.01000000,58492.85000000,57978.71000000,58142.29000000,1609.31248800,1616137199999,93601976.39314127,72093,759.53529400,44177666.93720238,0 -1616137200000,58142.29000000,58381.50000000,57700.00000000,57834.04000000,1715.83562300,1616140799999,99685537.27183893,88932,758.64932200,44074140.42954641,0 -1616140800000,57834.04000000,58568.00000000,57499.63000000,58338.07000000,3166.10615900,1616144399999,184070527.78925468,118845,1568.42710500,91216742.61388867,0 -1616144400000,58338.09000000,58888.00000000,58178.13000000,58300.00000000,2622.97662600,1616147999999,153558830.06692741,85814,1278.53904100,74861504.91367807,0 -1616148000000,58295.02000000,58707.27000000,58101.97000000,58583.92000000,1819.57824000,1616151599999,106206708.27996261,62413,886.68383000,51761378.14575761,0 -1616151600000,58583.92000000,58834.49000000,58402.66000000,58831.33000000,2091.39124600,1616155199999,122595300.34469474,84995,1016.71732600,59604527.28874963,0 -1616155200000,58831.34000000,59249.50000000,58718.57000000,58849.99000000,2998.89340500,1616158799999,176968100.07543716,116170,1509.39615600,89072512.02173588,0 -1616158800000,58849.99000000,58884.00000000,58057.04000000,58280.00000000,3297.06543700,1616162399999,192659656.79324941,107817,1628.43476900,95162627.69846460,0 -1616162400000,58279.99000000,58786.03000000,57950.59000000,58729.99000000,2375.16803100,1616165999999,138727999.56583795,90305,1063.17486400,62097776.87239500,0 -1616166000000,58729.98000000,59164.86000000,58500.00000000,58971.50000000,2704.90537500,1616169599999,159309454.29883239,76398,1378.13950700,81176226.94425808,0 -1616169600000,58977.04000000,59180.00000000,58610.56000000,58859.79000000,2724.40921100,1616173199999,160457239.10271708,81048,1284.64922300,75662984.31666912,0 -1616173200000,58857.51000000,58976.47000000,58625.00000000,58864.30000000,1451.31398100,1616176799999,85356895.91241080,57905,707.29487800,41600812.02682967,0 -1616176800000,58865.57000000,58956.00000000,58345.14000000,58800.00000000,1683.61190300,1616180399999,98818631.87480621,80113,818.89689700,48066970.89750706,0 -1616180400000,58800.00000000,58970.60000000,58643.99000000,58826.56000000,1456.44676300,1616183999999,85633513.74350445,89411,696.73233000,40966148.44637518,0 -1616184000000,58826.56000000,59468.00000000,58101.92000000,58372.40000000,3962.11893500,1616187599999,232999139.19975382,122541,2161.95202000,127191965.26271928,0 -1616187600000,58372.41000000,58755.15000000,58299.08000000,58648.78000000,1105.40938700,1616191199999,64737463.55670261,67783,521.25318200,30529585.70503679,0 -1616191200000,58648.78000000,58648.78000000,58283.94000000,58501.56000000,972.23017900,1616194799999,56836165.13578407,43768,450.74137100,26347224.81248144,0 -1616194800000,58501.55000000,58550.61000000,58000.00000000,58030.01000000,1627.33966900,1616198399999,94710585.73079219,53218,780.72023500,45446600.17880425,0 -1616198400000,58030.01000000,58677.52000000,57820.17000000,58639.33000000,2400.21478100,1616201999999,139775135.61008880,117250,1347.97935500,78500967.45701455,0 -1616202000000,58639.33000000,58879.18000000,58482.57000000,58724.01000000,1418.75610600,1616205599999,83213022.25642246,101473,722.87817700,42402789.32659511,0 -1616205600000,58724.02000000,58913.98000000,58416.16000000,58549.33000000,1292.83658600,1616209199999,75847128.67752989,69251,619.03400700,36318989.33848892,0 -1616209200000,58549.33000000,58581.62000000,58179.05000000,58367.74000000,1369.40514100,1616212799999,79937434.71747051,46038,591.44081400,34524792.40265906,0 -1616212800000,58367.75000000,58606.63000000,58153.28000000,58209.83000000,1090.34821100,1616216399999,63662122.44935170,43737,526.13731800,30719558.56332919,0 -1616216400000,58209.83000000,58362.11000000,58050.00000000,58131.57000000,1005.92984900,1616219999999,58567178.12265729,39647,465.76256300,27119534.26410283,0 -1616220000000,58131.57000000,58373.46000000,57980.00000000,58344.30000000,1229.53603800,1616223599999,71624722.72447132,44474,575.16413900,33509550.96012928,0 -1616223600000,58344.30000000,58536.84000000,58268.00000000,58402.41000000,1346.29394400,1616227199999,78602838.71808992,50903,630.86528300,36832154.86072246,0 -1616227200000,58402.41000000,58798.60000000,58402.40000000,58671.46000000,2269.32666400,1616230799999,133160868.73101746,84561,1187.39108200,69673923.44977065,0 -1616230800000,58671.45000000,58899.00000000,58577.55000000,58780.02000000,1730.98715900,1616234399999,101687855.91921922,68464,980.32261400,57593022.15701652,0 -1616234400000,58780.03000000,58908.26000000,58577.00000000,58687.97000000,1237.61178800,1616237999999,72708435.82915073,48073,611.82429800,35947362.69142132,0 -1616238000000,58685.98000000,59299.00000000,58626.27000000,59242.47000000,2563.59353600,1616241599999,151265724.30349677,83862,1402.49375900,82758094.51402984,0 -1616241600000,59242.91000000,59325.60000000,58756.41000000,59144.54000000,1890.87877900,1616245199999,111643256.77481865,89613,951.30027100,56166468.01419311,0 -1616245200000,59144.54000000,59880.00000000,58610.62000000,59033.13000000,4616.41624000,1616248799999,274375295.41173724,144830,2437.66477000,144919181.18357401,0 -1616248800000,59027.95000000,59368.75000000,58755.30000000,59365.02000000,2675.66907300,1616252399999,158134357.72929599,90798,1349.33902900,79747356.17011844,0 -1616252400000,59365.02000000,59722.00000000,59030.23000000,59244.52000000,2360.94706800,1616255999999,140261533.88830589,99599,1167.31284200,69353759.96468136,0 -1616256000000,59244.51000000,59300.00000000,58901.66000000,59031.13000000,2191.01910100,1616259599999,129425314.87936093,106206,1081.41617800,63877039.82319377,0 -1616259600000,59032.02000000,59297.00000000,59019.00000000,59138.44000000,1417.88486700,1616263199999,83895162.59915379,56570,704.21017900,41666608.98425554,0 -1616263200000,59138.43000000,59474.89000000,59104.28000000,59173.03000000,1437.47696500,1616266799999,85219757.78372868,51039,729.13193800,43227766.82794822,0 -1616266800000,59173.03000000,59424.73000000,59134.89000000,59272.82000000,1012.05506600,1616270399999,59990429.45451150,43892,493.90540200,29275388.50818034,0 -1616270400000,59272.83000000,59381.70000000,58131.55000000,58519.84000000,3576.51468400,1616273999999,209782761.79146679,93892,1574.40247100,92363981.56180753,0 -1616274000000,58519.77000000,58782.77000000,58371.01000000,58728.76000000,935.90892000,1616277599999,54866148.76920476,48358,464.09406300,27208066.08540614,0 -1616277600000,58728.75000000,58800.00000000,58370.65000000,58503.01000000,1162.19642700,1616281199999,68105272.24163728,44509,552.25397300,32361495.99054868,0 -1616281200000,58503.01000000,58525.96000000,57966.85000000,58102.28000000,2245.13478300,1616284799999,130783333.66939774,57092,1046.12219800,60956140.02425656,0 -1616284800000,58100.02000000,58589.10000000,57811.41000000,58331.43000000,2342.92980100,1616288399999,136538084.48522659,69680,1071.69380000,62463637.34090045,0 -1616288400000,58331.42000000,58463.99000000,58091.02000000,58180.00000000,953.47411000,1616291999999,55562369.53512714,41963,471.57221500,27483461.87584013,0 -1616292000000,58179.99000000,58180.00000000,57480.00000000,57615.32000000,2283.57109300,1616295599999,131982856.29604345,68914,1031.96878600,59651950.01712061,0 -1616295600000,57615.33000000,57856.42000000,57363.07000000,57790.00000000,1761.74702000,1616299199999,101663371.52994261,74206,774.97245600,44722649.09867494,0 -1616299200000,57790.00000000,57797.45000000,56717.81000000,56909.83000000,3073.16835200,1616302799999,175780313.09631984,86215,1400.08391000,80068414.86685879,0 -1616302800000,56911.99000000,57242.59000000,56856.66000000,57129.99000000,1641.05936900,1616306399999,93655921.94588568,49850,822.28281100,46929002.35872647,0 -1616306400000,57130.00000000,57413.66000000,56668.00000000,57047.98000000,1874.11392200,1616309999999,107040728.45689568,89964,901.11668200,51477799.54670575,0 -1616310000000,57047.98000000,57312.64000000,56862.07000000,56972.68000000,1201.10772200,1616313599999,68584960.24931010,82421,567.77407600,32420902.28364581,0 -1616313600000,56972.68000000,57325.45000000,56800.00000000,57161.38000000,1533.42174700,1616317199999,87617906.39176203,76623,762.34381100,43565517.29553083,0 -1616317200000,57161.38000000,57260.00000000,55450.11000000,55963.32000000,4428.20952900,1616320799999,249238457.27821915,117612,1862.78710700,104843164.02340083,0 -1616320800000,55960.52000000,56384.33000000,55605.94000000,56134.34000000,3100.61806200,1616324399999,174018493.39656378,77409,1595.71448900,89559114.55119471,0 -1616324400000,56134.34000000,56330.00000000,55811.00000000,56267.65000000,1990.46123800,1616327999999,111699942.41938144,62748,1003.13094700,56304195.87072113,0 -1616328000000,56270.13000000,56291.16000000,55870.23000000,56191.64000000,1993.88243600,1616331599999,111861648.18482057,73949,1045.76484400,58672203.00334655,0 -1616331600000,56191.64000000,57362.68000000,56191.63000000,57026.80000000,3817.15107500,1616335199999,216997391.56100694,133424,1884.98794200,107128557.41369605,0 -1616335200000,57021.95000000,57320.66000000,57000.05000000,57177.37000000,1476.54953400,1616338799999,84452550.78751477,81647,748.03938200,42786152.92264914,0 -1616338800000,57177.37000000,57539.00000000,57013.30000000,57159.04000000,1843.33045400,1616342399999,105609106.64405382,61563,937.73976400,53732812.62977626,0 -1616342400000,57159.04000000,57415.00000000,56750.00000000,57222.31000000,2353.11073100,1616345999999,134543097.31826908,86291,1178.59886900,67387726.55387739,0 -1616346000000,57220.26000000,57303.95000000,56962.26000000,57249.14000000,1477.50516500,1616349599999,84478197.57182931,63505,691.44195400,39535734.17814303,0 -1616349600000,57249.13000000,57481.01000000,57186.82000000,57365.08000000,1076.79595800,1616353199999,61746267.59817861,45033,548.34495900,31446857.79532542,0 -1616353200000,57365.08000000,57676.00000000,57357.94000000,57513.18000000,1742.06422400,1616356799999,100208419.86674434,54295,994.36570000,57198073.86755493,0 -1616356800000,57517.00000000,57997.00000000,57517.00000000,57760.48000000,1929.96849900,1616360399999,111551469.71607171,85083,921.49112100,53254664.60693564,0 -1616360400000,57760.47000000,58098.99000000,57474.46000000,58087.79000000,1423.23587900,1616363999999,82369330.63404686,88451,809.43402600,46859959.40497461,0 -1616364000000,58085.41000000,58113.00000000,57530.82000000,57588.25000000,1502.15820800,1616367599999,86800599.92592376,49980,714.67580600,41297372.24385507,0 -1616367600000,57588.25000000,57789.25000000,57128.89000000,57351.56000000,1744.83614600,1616371199999,100221644.73467261,52720,908.61621900,52199267.52738395,0 -1616371200000,57351.56000000,57449.47000000,56420.00000000,56590.76000000,2801.92626700,1616374799999,159511227.34993432,80233,1291.52256900,73546883.98473089,0 -1616374800000,56585.85000000,56735.00000000,56289.00000000,56623.19000000,1877.89480400,1616378399999,106146306.73804803,53896,892.30534900,50445499.72483795,0 -1616378400000,56623.20000000,57034.96000000,56418.55000000,56969.85000000,1345.87219900,1616381999999,76432376.58302056,41406,654.52106400,37173612.33176436,0 -1616382000000,56969.84000000,57647.89000000,56969.84000000,57563.63000000,1620.72010500,1616385599999,92915275.30407545,50721,788.40620400,45203195.33613145,0 -1616385600000,57564.17000000,57831.41000000,57388.07000000,57615.80000000,1442.60001400,1616389199999,83119342.58225359,45408,750.20054900,43232008.92556114,0 -1616389200000,57615.80000000,57780.10000000,57315.22000000,57597.39000000,1190.09061200,1616392799999,68453599.31324255,40938,631.30461900,36316971.65137910,0 -1616392800000,57597.39000000,57895.78000000,57569.43000000,57678.12000000,1405.51551800,1616396399999,81180072.53030996,65014,703.22747400,40614862.12442252,0 -1616396400000,57678.12000000,57850.00000000,57513.41000000,57576.50000000,1477.31556400,1616399999999,85236518.96565482,82797,760.52052700,43883138.18569509,0 -1616400000000,57576.51000000,57703.29000000,57095.00000000,57210.57000000,1811.99817200,1616403599999,104035984.59794557,59255,843.64639300,48435675.04139424,0 -1616403600000,57210.58000000,57396.99000000,57024.13000000,57372.00000000,1792.56444500,1616407199999,102557149.48416985,61249,936.44394200,53579887.01839904,0 -1616407200000,57372.01000000,58430.73000000,57282.00000000,57908.82000000,3343.84880100,1616410799999,194015333.86772802,92851,1764.35161600,102352164.12642537,0 -1616410800000,57908.82000000,58160.55000000,57555.55000000,57713.79000000,1618.68330300,1616414399999,93649806.04137077,79396,787.39208700,45559240.92842103,0 -1616414400000,57713.79000000,57761.00000000,56857.96000000,57259.48000000,2852.46023200,1616417999999,163502623.71671915,85516,1249.20398500,71606668.77078305,0 -1616418000000,57267.75000000,57414.00000000,56521.01000000,56969.98000000,3973.05211400,1616421599999,226578587.93555710,97449,2226.93106200,127038349.35222041,0 -1616421600000,56969.98000000,57279.26000000,56778.52000000,56990.02000000,2367.48035700,1616425199999,135060741.10554547,70581,1110.84682800,63381210.78553680,0 -1616425200000,56990.02000000,57229.71000000,56866.38000000,57083.00000000,1765.17847300,1616428799999,100730863.45070069,80274,783.60784100,44718133.17019892,0 -1616428800000,57082.99000000,57195.00000000,56191.19000000,56753.60000000,3186.88379200,1616432399999,180496976.74780123,131357,1486.68921200,84200698.55555634,0 -1616432400000,56753.61000000,57190.00000000,56551.04000000,57080.31000000,1802.84405200,1616435999999,102592238.20817184,57615,939.04505400,53427746.32490926,0 -1616436000000,57080.31000000,57175.11000000,56366.00000000,56494.11000000,2352.94605100,1616439599999,133534931.82958492,65710,1149.93163300,65262463.95418620,0 -1616439600000,56492.91000000,56561.60000000,55508.00000000,55524.99000000,3887.35387300,1616443199999,217417256.22068123,107907,1757.33603100,98306562.52081137,0 -1616443200000,55524.99000000,56000.00000000,54179.99000000,54507.62000000,6810.57256100,1616446799999,374982959.28179078,174717,3169.02834400,174521797.60015351,0 -1616446800000,54504.94000000,54956.33000000,54200.00000000,54566.77000000,3177.52924700,1616450399999,173720317.29485479,122333,1605.76399300,87820957.43857936,0 -1616450400000,54566.77000000,54658.87000000,53650.00000000,54614.23000000,5482.64059100,1616453999999,297418671.82235456,112911,2727.73412300,148061680.68348945,0 -1616454000000,54614.99000000,54871.14000000,54060.00000000,54083.25000000,3193.65502200,1616457599999,174190353.35413761,67811,1739.09852900,94889672.03341370,0 -1616457600000,54083.25000000,54760.00000000,53777.68000000,54697.73000000,3111.38298200,1616461199999,169359321.48806101,76981,1449.90908700,78956072.74628498,0 -1616461200000,54681.39000000,55344.26000000,54509.89000000,55120.83000000,3136.55410600,1616464799999,172242309.75594473,63208,1704.80057500,93614276.00034668,0 -1616464800000,55120.83000000,55145.05000000,54438.00000000,54548.58000000,2407.13516200,1616468399999,132073097.72445253,56842,1260.43128900,69151617.90890726,0 -1616468400000,54548.58000000,54742.30000000,54379.96000000,54684.83000000,1868.28540600,1616471999999,101923157.23816557,49728,958.07430000,52273409.44137583,0 -1616472000000,54683.60000000,54780.02000000,54057.28000000,54438.64000000,1925.28416300,1616475599999,104735575.91838238,58804,930.73708500,50624150.91438398,0 -1616475600000,54435.33000000,54471.36000000,53111.66000000,53532.25000000,4706.26226700,1616479199999,252354951.53553537,122164,2096.05363800,112425536.36115415,0 -1616479200000,53532.26000000,53806.65000000,53000.00000000,53306.84000000,4134.57248500,1616482799999,220711968.66368728,108218,1910.60801300,102027627.28618405,0 -1616482800000,53306.84000000,54277.78000000,53306.83000000,54161.34000000,2579.31068500,1616486399999,138655852.90025482,72768,1380.90517300,74257828.68765255,0 -1616486400000,54166.12000000,54482.81000000,53821.79000000,54309.24000000,2327.97458700,1616489999999,126148537.96936443,67620,1141.27102300,61839349.06153722,0 -1616490000000,54309.24000000,54698.30000000,54215.24000000,54607.86000000,1916.51903700,1616493599999,104265823.29169431,60656,940.84217500,51188559.87600498,0 -1616493600000,54602.43000000,54865.37000000,54430.52000000,54671.06000000,1862.74427000,1616497199999,101733390.20100931,56591,909.13491900,49657314.27881122,0 -1616497200000,54671.05000000,54804.98000000,54060.79000000,54249.81000000,2196.96097500,1616500799999,119728525.46655410,65637,1107.09554300,60330606.70631122,0 -1616500800000,54249.80000000,55287.52000000,54234.96000000,55110.00000000,2936.00755100,1616504399999,161275779.25986892,82894,1576.94428500,86601477.76655093,0 -1616504400000,55110.00000000,55450.00000000,55020.81000000,55263.36000000,2692.72391700,1616507999999,148785566.49087356,76122,1258.37749700,69538143.33867124,0 -1616508000000,55263.35000000,55367.34000000,54744.86000000,55184.25000000,2359.37426300,1616511599999,129942554.18421825,74552,1187.05767300,65378157.41766447,0 -1616511600000,55185.06000000,55356.31000000,54919.72000000,55165.19000000,1857.12265600,1616515199999,102459149.92956987,58405,861.27869100,47523308.38980538,0 -1616515200000,55165.20000000,55760.00000000,54830.01000000,55548.52000000,2642.91064000,1616518799999,146358183.32594861,76457,1345.99041000,74544053.91249981,0 -1616518800000,55548.52000000,55767.01000000,55401.00000000,55710.87000000,2130.55535000,1616522399999,118490038.55690664,76235,1051.04156200,58453622.16245961,0 -1616522400000,55705.78000000,55830.90000000,55362.18000000,55364.69000000,1880.51975300,1616525999999,104635595.34151700,64129,879.14894800,48920929.59875126,0 -1616526000000,55364.68000000,55541.81000000,54825.42000000,55008.46000000,2847.21136700,1616529599999,156951291.73596590,85941,1458.84093800,80427794.45161654,0 -1616529600000,55008.45000000,55080.16000000,54318.70000000,54452.60000000,2952.88122100,1616533199999,161716826.35639441,90165,1549.23165000,84854921.62285177,0 -1616533200000,54453.30000000,54759.56000000,54190.10000000,54646.59000000,1816.23829000,1616536799999,98891795.36927970,62680,985.19547400,53644698.90738132,0 -1616536800000,54646.58000000,54906.78000000,54359.15000000,54387.91000000,1981.08289400,1616540399999,108292192.28130133,53815,868.19852200,47449972.86481284,0 -1616540400000,54387.91000000,54816.01000000,54299.95000000,54340.89000000,1519.75140000,1616543999999,82919289.83251141,79737,752.24127000,41038721.11723732,0 -1616544000000,54342.80000000,54669.35000000,53596.32000000,53688.07000000,2878.75426500,1616547599999,155551408.22227117,77847,1428.23242900,77192218.91941071,0 -1616547600000,53691.25000000,54588.00000000,53511.39000000,54466.36000000,2069.62147300,1616551199999,111900928.17014262,53512,1003.03013300,54222277.88259269,0 -1616551200000,54466.38000000,54647.87000000,54350.00000000,54430.79000000,1756.51100600,1616554799999,95699346.08002542,45589,745.57320100,40619126.31955856,0 -1616554800000,54430.79000000,54769.44000000,54051.35000000,54350.54000000,1667.11248500,1616558399999,90720483.01972345,44344,717.65786400,39055830.90927197,0 -1616558400000,54350.54000000,54580.00000000,53966.89000000,54122.07000000,1650.39079900,1616561999999,89595053.32201413,44963,776.40264800,42152171.35246611,0 -1616562000000,54127.12000000,54294.82000000,53783.23000000,54100.00000000,2037.76106000,1616565599999,110112223.99485043,84112,1061.28869900,57352901.51932588,0 -1616565600000,54100.00000000,55000.00000000,53700.00000000,54662.79000000,3668.39656900,1616569199999,199442187.71947095,95215,1909.91984900,103780541.74010558,0 -1616569200000,54661.64000000,55612.92000000,54606.00000000,55464.20000000,4769.80029300,1616572799999,263851963.16444796,103773,2423.07429800,134023367.44869755,0 -1616572800000,55464.46000000,56400.13000000,55452.14000000,56280.41000000,4871.58581200,1616576399999,273041085.20244553,162454,2448.51989500,137253356.33358640,0 -1616576400000,56280.40000000,56662.08000000,56280.40000000,56404.73000000,3431.05606800,1616579999999,193735178.66180754,94783,1718.52029200,97041353.40019452,0 -1616580000000,56405.11000000,56592.85000000,56028.00000000,56465.75000000,3062.55839300,1616583599999,172464238.20031060,74043,1536.60997600,86533653.90556176,0 -1616583600000,56465.74000000,56600.54000000,56256.51000000,56541.03000000,1881.59611200,1616587199999,106175943.96314848,55058,973.29741400,54926971.48586247,0 -1616587200000,56536.08000000,57038.31000000,56536.08000000,56900.01000000,3523.67933600,1616590799999,200364741.51211092,87707,1889.89349400,107467342.96187261,0 -1616590800000,56900.00000000,57200.00000000,56368.42000000,56759.91000000,3226.30560000,1616594399999,183420203.94672230,148723,1582.11030300,89955718.60459568,0 -1616594400000,56761.86000000,56929.99000000,56450.00000000,56539.35000000,2514.75323900,1616597999999,142547204.49858636,100545,1268.99312600,71931766.29005245,0 -1616598000000,56539.34000000,56641.81000000,56000.00000000,56298.12000000,2954.00683600,1616601599999,166382192.12277658,100677,1502.21666800,84613926.23650695,0 -1616601600000,56298.12000000,56422.02000000,55729.46000000,55762.89000000,2997.53171600,1616605199999,167825985.28421889,100162,1479.47991700,82836693.54239147,0 -1616605200000,55762.89000000,56400.00000000,55570.82000000,56125.89000000,2956.20302600,1616608799999,165719682.77496397,72526,1199.34307700,67211925.26658294,0 -1616608800000,56125.90000000,56370.14000000,55300.00000000,55378.91000000,2463.77060200,1616612399999,137560449.34312896,69102,1190.55857000,66465103.11659430,0 -1616612400000,55380.64000000,55571.12000000,54666.66000000,54736.53000000,3623.33929400,1616615999999,199638470.11340974,100074,1761.73370400,97070813.81605629,0 -1616616000000,54736.52000000,54743.38000000,53202.00000000,54058.85000000,7329.51347200,1616619599999,395485214.78828580,177333,3287.50398000,177418185.89877426,0 -1616619600000,54058.85000000,54250.00000000,53540.05000000,53749.99000000,3305.88222100,1616623199999,178083270.81082235,108086,1507.36472600,81231854.41667767,0 -1616623200000,53749.99000000,53749.99000000,51700.00000000,52534.03000000,11193.61641800,1616626799999,589015075.15365663,282465,4162.92819500,219014081.40070485,0 -1616626800000,52534.03000000,52987.87000000,52300.00000000,52303.65000000,3703.71892600,1616630399999,194827083.97712048,118895,1748.87760900,92015496.03937699,0 -1616630400000,52303.66000000,52900.00000000,52000.00000000,52626.91000000,3818.55095700,1616633999999,200450080.56963453,92858,1765.43595700,92712596.84464090,0 -1616634000000,52626.91000000,52768.46000000,51748.08000000,51830.21000000,4295.49111100,1616637599999,224589381.98383145,115065,1744.03579500,91200782.07496712,0 -1616637600000,51831.13000000,52555.00000000,51500.00000000,52255.37000000,4425.19588600,1616641199999,230458328.69211754,136670,2353.76078200,122563812.50369456,0 -1616641200000,52255.38000000,52561.65000000,51818.84000000,52122.86000000,2267.35784400,1616644799999,118262107.04763841,71486,1140.63903100,59497229.49147399,0 -1616644800000,52131.51000000,52518.73000000,51905.58000000,52250.97000000,2280.57600700,1616648399999,119232385.39634225,51434,1172.34162600,61306793.85894235,0 -1616648400000,52251.96000000,52850.00000000,52135.14000000,52686.15000000,2898.57613500,1616651999999,152565712.00503198,57773,1508.61654700,79373011.07798306,0 -1616652000000,52686.15000000,53287.00000000,52653.81000000,52975.46000000,2716.60009400,1616655599999,143920679.28504265,69694,1346.67962100,71345751.08485464,0 -1616655600000,52975.46000000,53130.00000000,52200.00000000,52270.71000000,2325.33150700,1616659199999,122659234.04926998,88971,1105.86691400,58332374.18134711,0 -1616659200000,52270.72000000,52794.66000000,52101.00000000,52611.36000000,2720.76383900,1616662799999,142635288.72351974,70456,1303.76901600,68357327.59089941,0 -1616662800000,52611.36000000,53000.00000000,52365.00000000,52944.42000000,2363.32549700,1616666399999,124632201.85269174,54796,1254.87434600,66192681.54965097,0 -1616666400000,52944.95000000,53067.67000000,52520.00000000,52958.00000000,2287.57664200,1616669999999,120883638.70860772,58153,1130.16331400,59726541.53665456,0 -1616670000000,52955.72000000,53160.85000000,52134.27000000,52163.19000000,3108.30368400,1616673599999,163792245.89433620,65244,1597.71674000,84267299.83006734,0 -1616673600000,52163.20000000,52408.64000000,50438.88000000,51076.92000000,10807.72007300,1616677199999,553156328.02624602,204711,4966.28792600,253954059.43797068,0 -1616677200000,51076.93000000,51976.95000000,50427.56000000,51653.76000000,6586.26208100,1616680799999,337522102.57548612,120381,3358.83894400,172164883.21954525,0 -1616680800000,51649.90000000,52066.21000000,51046.40000000,51296.96000000,4571.04064800,1616684399999,235699668.78455467,103180,2352.25979600,121267023.38923817,0 -1616684400000,51296.96000000,51521.68000000,50620.00000000,50996.15000000,5364.28269200,1616687999999,273722391.00535959,122707,2664.79042000,136009452.44271864,0 -1616688000000,50996.15000000,51700.00000000,50550.00000000,51306.95000000,5642.86629400,1616691599999,288380030.63168987,136824,2694.64565600,137723867.71011495,0 -1616691600000,51303.96000000,51811.13000000,51102.45000000,51620.60000000,2738.11289100,1616695199999,141213953.34081945,73647,1365.56004100,70429570.24703839,0 -1616695200000,51620.61000000,52532.00000000,51500.00000000,52236.72000000,3466.09995100,1616698799999,180434431.52875690,77150,1896.86907000,98760375.93244444,0 -1616698800000,52225.00000000,52300.00000000,51619.72000000,52195.19000000,2450.56717600,1616702399999,127509658.96445912,62484,1214.30305800,63196955.66676113,0 -1616702400000,52195.19000000,52700.00000000,51820.00000000,51980.75000000,2724.34316400,1616705999999,142350337.90325796,69042,1297.19804000,67806356.60360115,0 -1616706000000,51981.60000000,52575.39000000,51937.19000000,52437.10000000,1473.66235700,1616709599999,77047746.78310463,54897,785.14608000,41061910.93976086,0 -1616709600000,52437.21000000,52720.24000000,51578.93000000,51741.60000000,3342.12628800,1616713199999,174483103.70195988,71206,1578.51001900,82421963.14397177,0 -1616713200000,51734.03000000,52048.41000000,51220.72000000,51293.78000000,2725.80172000,1616716799999,140726147.50410202,70596,1349.08899400,69678949.22868479,0 -1616716800000,51293.78000000,52258.47000000,51214.60000000,52083.14000000,3107.22228900,1616720399999,161203741.48680420,76103,1564.03721000,81155462.99447099,0 -1616720400000,52083.13000000,52350.00000000,51966.66000000,52255.41000000,2051.39237900,1616723999999,107099565.46150144,56433,1172.44353700,61223620.85473877,0 -1616724000000,52255.41000000,52364.87000000,51551.00000000,51696.70000000,2151.71252000,1616727599999,111613727.47233746,50258,963.67258200,50016797.42882324,0 -1616727600000,51696.70000000,52723.68000000,51696.70000000,52407.19000000,2341.37913200,1616731199999,122330161.64175278,60617,1162.85447800,60756284.69271860,0 -1616731200000,52407.19000000,52774.71000000,52172.34000000,52693.13000000,1990.73609700,1616734799999,104360255.49163349,63258,988.11893300,51812192.72997649,0 -1616734800000,52693.13000000,52899.01000000,52500.86000000,52825.67000000,2442.40859200,1616738399999,128747568.68613190,59654,1096.18089800,57790510.20795073,0 -1616738400000,52822.29000000,52883.09000000,52462.16000000,52582.45000000,1853.44596500,1616741999999,97622109.18512037,52665,855.88947200,45083272.11983136,0 -1616742000000,52582.44000000,53600.90000000,52400.86000000,53569.85000000,4262.21365600,1616745599999,226172721.70545823,96447,2253.45557400,119601995.96011808,0 -1616745600000,53569.24000000,53826.48000000,53164.34000000,53365.17000000,4277.03815300,1616749199999,228930046.36871684,107906,2012.82223900,107767269.47585222,0 -1616749200000,53365.17000000,53600.00000000,53205.29000000,53331.62000000,2018.78349400,1616752799999,107858768.78490826,90208,992.50190400,53027966.55061846,0 -1616752800000,53331.62000000,53579.98000000,53169.00000000,53378.06000000,1879.14152100,1616756399999,100279148.67613374,83361,985.09292800,52572921.95404697,0 -1616756400000,53378.06000000,53450.00000000,52570.00000000,52710.96000000,4910.15029700,1616759999999,259774910.38714589,136866,2400.58644100,127011157.75202571,0 -1616760000000,52710.95000000,53242.96000000,52508.19000000,53001.57000000,2859.89410700,1616763599999,151424408.70949303,78430,1535.95176200,81325257.57926955,0 -1616763600000,53001.57000000,53325.35000000,52731.49000000,53316.82000000,2320.57870300,1616767199999,123115623.86085248,64320,1229.35551600,65228938.90248027,0 -1616767200000,53316.81000000,53500.00000000,53108.36000000,53414.09000000,2174.35898400,1616770799999,115808702.46777224,59857,1127.90610200,60077808.03137052,0 -1616770800000,53414.10000000,53542.00000000,53210.01000000,53308.27000000,2174.15690500,1616774399999,115970527.50414414,70500,1026.41002900,54752839.00056230,0 -1616774400000,53315.54000000,54060.24000000,52888.81000000,53776.05000000,4853.62403400,1616777999999,260457166.12043516,110983,2581.39113600,138578980.88302339,0 -1616778000000,53776.14000000,53908.20000000,53500.00000000,53823.98000000,2110.34306600,1616781599999,113357603.19732892,63599,994.72314700,53435857.75605738,0 -1616781600000,53826.34000000,53913.79000000,53463.49000000,53682.52000000,2058.32871800,1616785199999,110444768.58990754,56784,935.66443000,50205576.37231101,0 -1616785200000,53682.51000000,53813.90000000,53528.35000000,53778.55000000,1472.06874700,1616788799999,78989614.45684412,44923,750.21060400,40253223.94046864,0 -1616788800000,53773.38000000,54270.53000000,53773.38000000,53960.00000000,3098.79430600,1616792399999,167456588.00422865,85794,1435.50703800,77589075.87193469,0 -1616792400000,53960.00000000,54599.66000000,53950.16000000,54574.41000000,2342.53501700,1616795999999,127349702.94799847,77107,1188.46925700,64612879.41575459,0 -1616796000000,54574.40000000,54773.00000000,54329.79000000,54383.14000000,2638.52615500,1616799599999,143971966.12851574,65988,1162.57323100,63445421.96028515,0 -1616799600000,54383.15000000,55073.46000000,54292.00000000,55025.59000000,2424.94185500,1616803199999,132696743.41647237,61089,1406.72679000,77000730.90242663,0 -1616803200000,55025.59000000,55555.00000000,54716.31000000,54745.38000000,3813.28749100,1616806799999,210558188.92293044,89810,2078.13138200,114763238.17050419,0 -1616806800000,54745.37000000,54972.32000000,54558.67000000,54682.64000000,2538.82245100,1616810399999,139077370.26333832,46940,1194.90105200,65472778.77159020,0 -1616810400000,54682.64000000,54886.51000000,54495.12000000,54745.00000000,1287.98930800,1616813999999,70496326.53284203,38556,629.80439400,34475358.55821082,0 -1616814000000,54745.01000000,54838.98000000,54560.51000000,54760.97000000,983.71561600,1616817599999,53797137.45597051,34111,471.42434400,25781122.65192854,0 -1616817600000,54759.96000000,55236.76000000,54660.11000000,54944.72000000,1853.10508800,1616821199999,101929616.43429739,45673,927.56069900,51013311.08651071,0 -1616821200000,54944.72000000,55378.70000000,54698.28000000,55177.81000000,1819.66166300,1616824799999,100074621.52002179,45339,899.51962700,49484126.01661243,0 -1616824800000,55177.89000000,55283.65000000,54957.43000000,55027.16000000,1532.80929200,1616828399999,84473486.50331581,44599,728.06527300,40127410.30989917,0 -1616828400000,55027.16000000,55088.14000000,54733.65000000,54950.28000000,1643.40177400,1616831999999,90254339.32602816,45888,771.92583100,42392538.15125774,0 -1616832000000,54950.27000000,55146.23000000,54641.63000000,54925.06000000,1774.05187700,1616835599999,97343324.86190110,51405,825.59863200,45315219.63881574,0 -1616835600000,54925.05000000,55030.24000000,54781.64000000,55013.42000000,1104.07671200,1616839199999,60612014.97437757,39025,592.93297900,32553218.45573852,0 -1616839200000,55013.42000000,55105.85000000,54672.98000000,54680.00000000,1823.37695100,1616842799999,100048615.84434317,48410,954.79092300,52404322.41498533,0 -1616842800000,54680.01000000,54814.89000000,54311.60000000,54442.89000000,2715.09874800,1616846399999,148052315.22014372,71198,1302.61919800,71036710.98991807,0 -1616846400000,54442.89000000,54592.97000000,53950.00000000,54291.28000000,3025.90670800,1616849999999,163956828.11981612,82878,1466.85499800,79480493.05146479,0 -1616850000000,54291.29000000,54847.47000000,54066.42000000,54735.64000000,1817.70857700,1616853599999,98875964.55337676,53433,941.21802600,51204991.78189068,0 -1616853600000,54735.64000000,54745.81000000,54376.08000000,54630.06000000,1515.53858600,1616857199999,82710006.44784728,73639,723.93461500,39507717.34045950,0 -1616857200000,54630.06000000,55041.79000000,54501.29000000,54961.85000000,1871.17756700,1616860799999,102630822.11146984,59849,1043.41067700,57235895.25939040,0 -1616860800000,54961.85000000,56220.00000000,54949.27000000,56167.46000000,4967.78600700,1616864399999,276296469.26793608,146020,2782.79195200,154797598.87943919,0 -1616864400000,56163.52000000,56271.00000000,55838.73000000,56084.74000000,2788.99092700,1616867999999,156303282.98407852,114796,1421.27478500,79649976.80420796,0 -1616868000000,56081.46000000,56086.00000000,55556.00000000,55728.93000000,1829.78972500,1616871599999,102078097.66506941,57505,873.15263000,48717247.56064160,0 -1616871600000,55728.92000000,55900.00000000,55621.00000000,55765.01000000,1160.07360300,1616875199999,64694044.51713007,45178,566.66566600,31601666.54312198,0 -1616875200000,55765.01000000,55900.01000000,55680.68000000,55858.74000000,1197.78080300,1616878799999,66865724.21912843,42396,568.27281000,31725433.01574969,0 -1616878800000,55858.73000000,56700.36000000,55675.00000000,56433.17000000,3146.20652000,1616882399999,177153409.04362109,104593,1251.05327000,70359768.94070693,0 -1616882400000,56433.17000000,56605.93000000,56024.67000000,56370.94000000,2002.30136400,1616885999999,112698006.35896190,94181,923.44259100,51979259.73473495,0 -1616886000000,56373.50000000,56440.00000000,55730.00000000,55817.14000000,1892.81769700,1616889599999,106090162.71398531,53354,800.60211700,44885913.12274446,0 -1616889600000,55817.14000000,56200.00000000,55572.00000000,56020.28000000,2235.45500000,1616893199999,124776057.31375610,62844,1098.59957800,61334890.83932521,0 -1616893200000,56020.29000000,56182.88000000,55720.00000000,56068.69000000,1365.79256800,1616896799999,76486642.20641871,75351,688.42456400,38556009.88051891,0 -1616896800000,56068.69000000,56113.08000000,55742.94000000,55804.92000000,1407.04222200,1616900399999,78662433.63180383,67635,660.52041700,36929855.25078275,0 -1616900400000,55804.92000000,56161.67000000,55738.17000000,56052.05000000,1153.92000100,1616903999999,64597522.46181432,35879,609.31927000,34112360.97682889,0 -1616904000000,56052.52000000,56496.00000000,56052.52000000,56272.49000000,1608.60462400,1616907599999,90513603.12576843,62710,851.97516000,47935957.83942802,0 -1616907600000,56272.49000000,56407.86000000,56104.49000000,56269.49000000,965.54662500,1616911199999,54295462.77117824,35334,475.68744000,26748622.09901928,0 -1616911200000,56264.90000000,56319.56000000,55831.43000000,55935.61000000,1197.02946100,1616914799999,67090845.13916098,41015,550.49140100,30849219.04566741,0 -1616914800000,55935.61000000,56400.01000000,55865.62000000,56200.66000000,1269.24642400,1616918399999,71229641.28343878,40309,649.10535800,36415932.64458981,0 -1616918400000,56200.66000000,56300.00000000,55976.99000000,56296.57000000,1089.73930400,1616921999999,61187723.74379152,51167,514.75863900,28904012.72157900,0 -1616922000000,56296.57000000,56559.75000000,56026.19000000,56114.95000000,1703.62729600,1616925599999,95976040.03285566,53325,845.76674400,47654835.17881137,0 -1616925600000,56117.75000000,56181.83000000,55683.56000000,56085.93000000,1817.70847800,1616929199999,101694218.68295016,55706,861.80915500,48214347.15659487,0 -1616929200000,56085.93000000,56085.94000000,55777.00000000,55787.03000000,1395.39065100,1616932799999,78046762.47714711,77955,604.99011500,33836544.57376214,0 -1616932800000,55787.02000000,56000.00000000,55291.13000000,55525.24000000,2202.09845400,1616936399999,122365045.02834841,72499,983.72505800,54674165.58883575,0 -1616936400000,55525.25000000,55895.65000000,55461.01000000,55750.00000000,1325.18108600,1616939999999,73843442.16354856,46718,689.98490400,38450010.15488302,0 -1616940000000,55750.00000000,55842.50000000,55500.25000000,55800.00000000,1498.58557500,1616943599999,83437514.53453176,82162,824.50173800,45909959.36144047,0 -1616943600000,55800.00000000,56375.19000000,55654.10000000,56354.35000000,2105.25225400,1616947199999,118116692.12387639,116205,1159.91396500,65077998.92674479,0 -1616947200000,56356.98000000,56490.00000000,56016.12000000,56275.59000000,2003.53328500,1616950799999,112683455.67809744,122117,1083.97224400,60967773.61198476,0 -1616950800000,56275.59000000,56325.68000000,55803.19000000,55967.73000000,1986.58486200,1616954399999,111327313.81614129,73812,994.92543200,55751289.59572361,0 -1616954400000,55967.73000000,56000.00000000,55159.17000000,55192.08000000,2296.06143500,1616957999999,127597057.31964615,98361,970.73839700,53944980.68752933,0 -1616958000000,55192.08000000,55414.01000000,54691.84000000,55208.69000000,3037.57113200,1616961599999,167193396.55173506,99041,1448.09051900,79716592.63892804,0 -1616961600000,55208.70000000,55210.47000000,54743.18000000,54860.00000000,1697.20807300,1616965199999,93358763.69516436,48978,793.58749100,43654358.98349944,0 -1616965200000,54859.99000000,55370.45000000,54819.40000000,55140.01000000,1060.81353600,1616968799999,58396461.40825655,45187,566.47489400,31189257.44195137,0 -1616968800000,55140.01000000,55655.53000000,55000.00000000,55600.01000000,1412.65683200,1616972399999,78194033.40293175,42840,727.08090300,40254121.26236848,0 -1616972400000,55600.01000000,55884.40000000,55511.80000000,55777.63000000,1215.73833300,1616975999999,67707200.85285509,44133,608.28254900,33876449.49821212,0 -1616976000000,55777.65000000,56013.76000000,55290.00000000,55409.67000000,2071.04547900,1616979599999,115328946.29623365,65853,1058.11918400,58941601.78172665,0 -1616979600000,55409.68000000,55500.00000000,54977.80000000,55241.28000000,1598.26657600,1616983199999,88174215.88755206,42237,815.55528500,44997031.46995951,0 -1616983200000,55241.29000000,55515.36000000,55151.26000000,55349.99000000,1797.37321700,1616986799999,99524934.40911369,55712,793.78474100,43941663.89633333,0 -1616986800000,55354.67000000,55554.40000000,55276.51000000,55371.60000000,1157.88863600,1616990399999,64182444.67418246,43554,598.46616000,33174266.97238507,0 -1616990400000,55371.61000000,55522.00000000,55107.08000000,55315.01000000,1701.17971000,1616993999999,94034508.05690524,41399,949.36692600,52474859.53412208,0 -1616994000000,55315.01000000,55425.26000000,54848.98000000,55048.80000000,2153.12934600,1616997599999,118593995.64283484,48496,1056.61297000,58217933.65360399,0 -1616997600000,55048.80000000,55656.64000000,54800.01000000,55401.26000000,2624.40515100,1617001199999,145049141.44089716,57299,1386.21812100,76643520.67276970,0 -1617001200000,55401.26000000,56167.37000000,55358.94000000,55911.99000000,2920.30807700,1617004799999,163231921.36289134,71453,1468.16003800,82061550.27542268,0 -1617004800000,55911.99000000,57230.00000000,55911.99000000,57126.15000000,4953.17895100,1617008399999,280273899.54828792,121645,2864.44451700,162139540.48968718,0 -1617008400000,57129.58000000,58225.00000000,56966.54000000,57922.20000000,6364.37953800,1617011999999,366418067.01212099,196931,3265.45814300,188067573.91604340,0 -1617012000000,57922.20000000,58350.00000000,57777.87000000,58024.51000000,4216.17275300,1617015599999,244694727.97123165,114396,2128.60634200,123511781.77295208,0 -1617015600000,58024.50000000,58100.00000000,57609.81000000,57854.32000000,3166.06761800,1617019199999,183121495.98477236,83322,1783.24176900,103144315.32135820,0 -1617019200000,57854.14000000,58405.82000000,57792.05000000,58035.18000000,3524.58542700,1617022799999,204922801.06191140,104038,1912.60890200,111202240.97322648,0 -1617022800000,58035.19000000,58200.00000000,57808.80000000,57960.17000000,2105.23642700,1617026399999,122113580.99902324,70519,1088.52919600,63138292.93043591,0 -1617026400000,57960.65000000,58174.24000000,57837.83000000,58130.06000000,3009.31286400,1617029999999,174710051.40184007,81033,1576.54641600,91529961.34626998,0 -1617030000000,58130.05000000,58182.13000000,57267.98000000,57719.74000000,6372.19390400,1617033599999,367698873.44186746,119376,2750.83258200,158620090.59605364,0 -1617033600000,57719.74000000,57845.00000000,57170.00000000,57624.77000000,3104.75509000,1617037199999,178757579.06012564,112954,1450.19861400,83505593.05370778,0 -1617037200000,57622.63000000,58290.00000000,57571.42000000,57924.69000000,3251.68148300,1617040799999,188539539.19729034,129259,1743.42300800,101091142.61955894,0 -1617040800000,57924.69000000,58021.19000000,57561.22000000,57819.99000000,2358.37922700,1617044399999,136323805.24272664,74306,1182.06909700,68327740.25483105,0 -1617044400000,57820.00000000,57870.01000000,57317.02000000,57676.42000000,2131.84129600,1617047999999,122920792.15640929,69948,1014.50226400,58501397.22307647,0 -1617048000000,57676.41000000,57733.95000000,57103.43000000,57277.13000000,2539.76849000,1617051599999,145862942.49307925,71736,1220.82565200,70127618.82793776,0 -1617051600000,57281.79000000,57641.47000000,57160.00000000,57547.60000000,1773.72325000,1617055199999,101843500.17786626,68698,930.68027900,53443616.66314266,0 -1617055200000,57547.60000000,57900.00000000,57478.74000000,57747.01000000,1508.92329700,1617058799999,87089305.83361645,53386,683.24983900,39440004.75300571,0 -1617058800000,57747.00000000,57782.20000000,57297.31000000,57635.47000000,1454.14159100,1617062399999,83720040.38186638,85887,652.30451100,37556834.65844935,0 -1617062400000,57635.46000000,57769.01000000,57405.23000000,57520.41000000,1518.86521600,1617065999999,87465062.91814267,48026,729.82436800,42027940.79360449,0 -1617066000000,57520.41000000,57612.40000000,57259.48000000,57439.67000000,2383.17463600,1617069599999,136867004.91287573,47284,859.34133400,49351905.02889852,0 -1617069600000,57439.67000000,57450.00000000,57175.02000000,57322.02000000,1655.60849800,1617073199999,94837975.50820101,43755,789.68075100,45232343.69098869,0 -1617073200000,57322.84000000,57391.74000000,57117.36000000,57181.33000000,1542.71398500,1617076799999,88314309.28355520,50051,678.57167900,38843352.44940175,0 -1617076800000,57181.33000000,57839.16000000,57071.35000000,57567.01000000,2296.11506500,1617080399999,131847984.28645300,53331,1022.34422600,58709715.58729569,0 -1617080400000,57567.01000000,57692.97000000,57369.50000000,57670.13000000,1700.34384000,1617083999999,97798019.89366861,45992,879.17370600,50572579.09743021,0 -1617084000000,57670.14000000,58277.00000000,57505.49000000,58056.00000000,2326.61064000,1617087599999,134751998.94810390,65792,1296.15693700,75094362.00608593,0 -1617087600000,58056.01000000,58272.60000000,57938.38000000,58116.17000000,2286.43578300,1617091199999,132842065.85690621,89608,1100.25818200,63930632.08591835,0 -1617091200000,58116.16000000,58200.00000000,57726.72000000,57940.00000000,2180.46204100,1617094799999,126375544.28008422,65215,1085.04134500,62887334.52707004,0 -1617094800000,57940.00000000,58923.26000000,57842.82000000,58873.91000000,4935.51160900,1617098399999,288798913.04362479,117981,2774.32116000,162370557.67149478,0 -1617098400000,58873.91000000,59335.00000000,58625.00000000,58842.87000000,5932.47726500,1617101999999,350371808.64148619,148029,3135.48199900,185186684.01270213,0 -1617102000000,58842.87000000,59246.93000000,58837.60000000,59240.34000000,2607.64886000,1617105599999,153932693.35447709,77002,1462.82457500,86361226.59975722,0 -1617105600000,59240.33000000,59368.00000000,59015.32000000,59112.81000000,2817.34673100,1617109199999,166730083.48264003,80325,1528.22515700,90444899.25447350,0 -1617109200000,59112.81000000,59265.18000000,58819.19000000,58890.01000000,3403.89104400,1617112799999,200801285.28601236,87357,1526.73265000,90072826.99409722,0 -1617112800000,58890.01000000,58999.14000000,58626.92000000,58865.90000000,2524.06003800,1617116399999,148462062.65103608,84866,1232.67507500,72506202.06124762,0 -1617116400000,58865.90000000,58948.40000000,58500.00000000,58526.42000000,2265.27843200,1617119999999,133010137.85156953,68431,1081.48309000,63513212.35139124,0 -1617120000000,58526.43000000,58825.00000000,58470.00000000,58698.26000000,2018.91882000,1617123599999,118411705.78234949,68812,955.85755100,56070177.48376798,0 -1617123600000,58698.26000000,58888.00000000,58656.71000000,58700.00000000,1371.58600300,1617127199999,80626365.56949211,51314,686.19165400,40336960.28473891,0 -1617127200000,58699.99000000,59107.84000000,58699.99000000,58853.02000000,1916.95905200,1617130799999,113014689.52405256,58984,1128.64343300,66551057.15028870,0 -1617130800000,58853.02000000,59060.00000000,58700.00000000,59060.00000000,1508.34278900,1617134399999,88829363.90160433,50704,808.93419800,47645503.91391312,0 -1617134400000,59060.00000000,59086.65000000,58380.02000000,58627.00000000,2548.96789200,1617137999999,149425767.90078410,73902,1091.99253600,64049218.63463485,0 -1617138000000,58627.00000000,58840.00000000,58542.18000000,58722.88000000,833.34634400,1617141599999,48899761.22614474,45462,424.17697100,24891465.58338964,0 -1617141600000,58722.89000000,58900.00000000,58615.00000000,58682.41000000,1112.28554000,1617145199999,65351002.59584944,47622,524.66519200,30826197.05793409,0 -1617145200000,58682.41000000,58769.96000000,58531.70000000,58746.57000000,1435.49299900,1617148799999,84178500.75591707,42899,738.92891100,43336303.60937723,0 -1617148800000,58746.57000000,59015.00000000,58631.65000000,58991.52000000,1856.65897800,1617152399999,109296782.49070419,50873,1007.80582200,59334863.41574539,0 -1617152400000,58991.52000000,59050.00000000,58799.81000000,58885.76000000,1462.52542900,1617155999999,86169707.05261345,69577,704.26948200,41495303.39039286,0 -1617156000000,58885.76000000,58913.74000000,58638.00000000,58646.12000000,1675.45249900,1617159599999,98498070.28046075,62156,799.09776200,46975424.69170163,0 -1617159600000,58646.11000000,58714.28000000,58369.00000000,58608.63000000,2120.52541700,1617163199999,124137053.40944241,67770,830.77275200,48640734.74089529,0 -1617163200000,58608.62000000,58779.63000000,58476.81000000,58716.86000000,1677.41118800,1617166799999,98367051.53985620,89192,719.62003500,42193412.16569014,0 -1617166800000,58716.87000000,58719.00000000,58550.00000000,58710.95000000,1450.80283800,1617170399999,85028068.69057727,55520,723.82156800,42417111.64578463,0 -1617170400000,58710.96000000,59800.00000000,58651.08000000,59687.56000000,3882.81602800,1617173999999,230554277.57013244,122063,2264.64883400,134482173.04852253,0 -1617174000000,59687.56000000,59800.00000000,57500.18000000,58173.83000000,4724.35382100,1617177599999,277638882.92866280,130942,2242.19520600,131899837.78532271,0 -1617177600000,58173.82000000,58275.45000000,56769.00000000,57975.33000000,6030.92628900,1617181199999,347871145.55522117,164094,2797.41271800,161410102.28062567,0 -1617181200000,57983.77000000,58263.87000000,57697.22000000,57959.05000000,2145.27057600,1617184799999,124345771.92504257,62110,929.34340200,53887503.04761828,0 -1617184800000,57959.05000000,58088.66000000,57254.90000000,57718.44000000,2719.46263800,1617188399999,156807399.02013939,73737,1304.84043300,75244264.49328016,0 -1617188400000,57718.44000000,58137.01000000,57630.63000000,58015.02000000,1758.37729100,1617191999999,101869366.29738325,56290,900.70539500,52179882.36324988,0 -1617192000000,58015.02000000,58326.01000000,57641.06000000,58159.98000000,2438.46892900,1617195599999,141585307.26241322,67917,1226.43656400,71218887.68414101,0 -1617195600000,58159.99000000,58813.10000000,58059.02000000,58598.55000000,2612.02426100,1617199199999,152728839.07119546,81208,1426.74893200,83424079.83187165,0 -1617199200000,58598.55000000,58783.63000000,58370.20000000,58588.16000000,1701.22005700,1617202799999,99654763.16196278,60649,802.35669400,47001346.66996654,0 -1617202800000,58588.15000000,59430.54000000,58586.73000000,59304.75000000,3850.19529900,1617206399999,227594348.75084859,114524,2062.22434000,121908008.91494210,0 -1617206400000,59304.76000000,59648.52000000,58782.80000000,59000.00000000,3236.75426100,1617209999999,191676527.00814682,102849,1758.15755800,104160176.44341033,0 -1617210000000,58999.99000000,59269.03000000,58880.00000000,59251.99000000,2257.73872300,1617213599999,133352749.95385355,69215,1492.08909500,88128255.27330304,0 -1617213600000,59251.99000000,59585.61000000,59165.85000000,59299.45000000,2328.76026400,1617217199999,138240288.46227170,79040,1350.03023200,80136456.81664591,0 -1617217200000,59304.45000000,59567.28000000,58453.30000000,58553.12000000,3276.30590300,1617220799999,193887301.21751742,97127,1740.88181600,103076769.90146989,0 -1617220800000,58553.12000000,59087.00000000,58328.55000000,58934.60000000,3283.19091600,1617224399999,192746174.57383441,86303,1756.55816400,103123186.26419529,0 -1617224400000,58935.10000000,59289.45000000,58700.00000000,58940.50000000,1671.19972700,1617227999999,98577068.47579318,68641,866.58065300,51119834.72804941,0 -1617228000000,58940.50000000,59009.85000000,58558.00000000,58621.94000000,1447.62271200,1617231599999,85052315.52218886,48355,715.99932200,42068025.01783044,0 -1617231600000,58621.94000000,58895.20000000,58540.00000000,58740.55000000,1367.47862200,1617235199999,80296823.58431382,48072,652.21640800,38297152.29579528,0 diff --git a/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv b/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv deleted file mode 100644 index 2c9b593d47..0000000000 --- a/pkg/datasource/csvsource/testdata/FXSUSDT-ticks-2023-10-29.csv +++ /dev/null @@ -1,5 +0,0 @@ -11782578,6.00000000,1.00000000,14974844,14974844,1698623884463,True,True -11782579,6.00000000,1.00000000,14974845,14974845,1698623893787,True,True -11782580,6.00000000,1.00000000,14974846,14974846,1698623893793,True,True -11782581,6.00000000,5.00000000,14974847,14974847,1698623920955,True,True -11782582,6.00000000,10.50000000,14974848,14974848,1698623939783,False,True diff --git a/pkg/datasource/csvsource/tick_downloader.go b/pkg/datasource/csvsource/tick_downloader.go deleted file mode 100644 index fe0dd12f85..0000000000 --- a/pkg/datasource/csvsource/tick_downloader.go +++ /dev/null @@ -1,171 +0,0 @@ -package csvsource - -import ( - "archive/zip" - "bytes" - "compress/gzip" - "errors" - "fmt" - "io" - "net/http" - "os" - "path/filepath" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/c9s/bbgo/pkg/types" -) - -func Download(saveToPath, symbol string, exchange types.ExchangeName, start time.Time) error { - for { - var ( - fileName = fmt.Sprintf("%s%s.csv", symbol, start.Format("2006-01-02")) - ) - - if fileExists(filepath.Join(saveToPath, fileName)) { - start = start.AddDate(0, 0, 1) - continue - } - - var url = buildURL(exchange, symbol, fileName, start) - - log.Info("fetching ", url) - - csvContent, err := readCSVFromUrl(exchange, url) - if err != nil { - log.Error(err) - break - } - - err = write(csvContent, saveToPath, fileName) - if err != nil { - log.Error(err) - break - } - start = start.AddDate(0, 0, 1) - } - - return nil -} - -func buildURL(exchange types.ExchangeName, symbol string, fileName string, start time.Time) (url string) { - switch exchange { - case types.ExchangeBybit: - url = fmt.Sprintf("https://public.bybit.com/trading/%s/%s.gz", - symbol, - fileName) - - case types.ExchangeBinance: - url = fmt.Sprintf("https://data.binance.vision/data/spot/daily/aggTrades/%s/%s-aggTrades-%s.zip", - symbol, - symbol, - start.Format("2006-01-02")) - } - return url -} - -func readCSVFromUrl(exchange types.ExchangeName, url string) (csvContent []byte, err error) { - resp, err := http.Get(url) - if err != nil { - return nil, fmt.Errorf("get %s: %w", url, err) - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("read body %s: %w", url, err) - } - - switch exchange { - case types.ExchangeBybit: - csvContent, err = gUnzipData(body) - if err != nil { - return nil, fmt.Errorf("gunzip data %s: %w", url, err) - } - - case types.ExchangeBinance: - csvContent, err = unzipData(body) - if err != nil { - return nil, fmt.Errorf("unzip data %s: %w", url, err) - } - } - - return csvContent, nil -} - -func write(content []byte, saveToPath, fileName string) error { - - if _, err := os.Stat(saveToPath); errors.Is(err, os.ErrNotExist) { - err := os.MkdirAll(saveToPath, os.ModePerm) - if err != nil { - return fmt.Errorf("mkdir %s: %w", saveToPath, err) - } - } - - err := os.WriteFile(fmt.Sprintf("%s/%s", saveToPath, fileName), content, 0666) - if err != nil { - return fmt.Errorf("write %s: %w", saveToPath+fileName, err) - } - - return nil -} - -func unzipData(data []byte) (resData []byte, err error) { - zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) - if err != nil { - log.Error(err) - } - - if zipReader == nil || len(zipReader.File) == 0 { - return nil, errors.New("no data to unzip") - } - - // Read all the files from zip archive - for _, zipFile := range zipReader.File { - resData, err = readZipFile(zipFile) - if err != nil { - log.Error(err) - break - } - } - - return -} - -func readZipFile(zf *zip.File) ([]byte, error) { - f, err := zf.Open() - if err != nil { - return nil, err - } - defer f.Close() - return io.ReadAll(f) -} - -func gUnzipData(data []byte) (resData []byte, err error) { - b := bytes.NewBuffer(data) - - var r io.Reader - r, err = gzip.NewReader(b) - if err != nil { - return - } - - var resB bytes.Buffer - _, err = resB.ReadFrom(r) - if err != nil { - return - } - - resData = resB.Bytes() - - return -} - -func fileExists(fileName string) bool { - info, err := os.Stat(fileName) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} diff --git a/pkg/datasource/csvsource/tick_downloader_test.go b/pkg/datasource/csvsource/tick_downloader_test.go deleted file mode 100644 index d124d12775..0000000000 --- a/pkg/datasource/csvsource/tick_downloader_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package csvsource - -import ( - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/types" -) - -func Test_Download_Binance_Default(t *testing.T) { - if _, ok := os.LookupEnv("TEST_CSV_DOWNLOADER"); !ok { - t.Skip() - } - var ( - symbol = strings.ToUpper("fxsusdt") - path = "testdata/binance/" + symbol - start = time.Now().Round(0).Add(-24 * time.Hour) - ) - - err := Download(path, symbol, types.ExchangeBinance, start) - assert.NoError(t, err) - klines, err := ReadTicksFromCSV(path, types.Interval1h) - assert.NoError(t, err) - assert.Equal(t, 24, len(klines)) - err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, types.Interval1h), klines) - assert.NoError(t, err) - err = os.RemoveAll("testdata/binance/") - assert.NoError(t, err) -} - -func Test_Download_Bybit(t *testing.T) { - if _, ok := os.LookupEnv("TEST_CSV_DOWNLOADER"); !ok { - t.Skip() - } - var ( - symbol = strings.ToUpper("fxsusdt") - path = "testdata/bybit/" + symbol - start = time.Now().Round(0).Add(-24 * time.Hour) - ) - - err := Download(path, symbol, types.ExchangeBybit, start) - assert.NoError(t, err) - klines, err := ReadTicksFromCSVWithDecoder(path, types.Interval1h, MakeCSVTickReader(NewBybitCSVTickReader)) - assert.NoError(t, err) - assert.Equal(t, 24, len(klines)) - err = WriteKLines(fmt.Sprintf("%s/%s_%s.csv", path, symbol, types.Interval1h), klines) - assert.NoError(t, err) - err = os.RemoveAll("testdata/bybit/") - assert.NoError(t, err) -} diff --git a/pkg/datasource/csvsource/types.go b/pkg/datasource/csvsource/types.go deleted file mode 100644 index e260e66937..0000000000 --- a/pkg/datasource/csvsource/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package csvsource - -import ( - "github.com/c9s/bbgo/pkg/fixedpoint" -) - -type CsvTick struct { - Timestamp int64 `json:"timestamp"` - Symbol string `json:"symbol"` - Side string `json:"side"` - TickDirection string `json:"tickDirection"` - Size fixedpoint.Value `json:"size"` - Price fixedpoint.Value `json:"price"` - HomeNotional fixedpoint.Value `json:"homeNotional"` - ForeignNotional fixedpoint.Value `json:"foreignNotional"` -} diff --git a/pkg/datasource/csvsource/write_klines.go b/pkg/datasource/csvsource/write_klines.go deleted file mode 100644 index c1c4aecc1f..0000000000 --- a/pkg/datasource/csvsource/write_klines.go +++ /dev/null @@ -1,39 +0,0 @@ -package csvsource - -import ( - "encoding/csv" - "os" - "strconv" - - "github.com/pkg/errors" - - "github.com/c9s/bbgo/pkg/types" -) - -// WriteKLines writes csv to path. -func WriteKLines(path string, prices []types.KLine) (err error) { - file, err := os.Create(path) - if err != nil { - return errors.Wrap(err, "failed to open file") - } - defer func() { - err = file.Close() - if err != nil { - panic("failed to close file") - } - }() - w := csv.NewWriter(file) - defer w.Flush() - // Using Write - for _, record := range prices { - row := []string{strconv.Itoa(int(record.StartTime.Unix())), record.Open.String(), record.High.String(), record.Low.String(), record.Close.String(), record.Volume.String()} - if err := w.Write(row); err != nil { - return errors.Wrap(err, "writing record to file") - } - } - if err != nil { - return err - } - - return nil -} diff --git a/pkg/indicator/v2/abdx.go b/pkg/indicator/v2/abdx.go new file mode 100644 index 0000000000..5e2ac8fcf3 --- /dev/null +++ b/pkg/indicator/v2/abdx.go @@ -0,0 +1,98 @@ +package indicatorv2 + +import ( + "math" + + "github.com/c9s/bbgo/pkg/types" +) + +type DxStream struct { + *types.Float64Series + window int + tr *TRStream + sTr *smooth + sPlusDm *smooth + sMinusDm *smooth +} + +func DirectionalIndex(source KLineSubscription, window int) *DxStream { + high := HighPrices(source) + low := LowPrices(source) + s := &DxStream{ + Float64Series: types.NewFloat64Series(), + window: window, + tr: TR2(source), + sTr: WilderSmoothing(window), + sPlusDm: WilderSmoothing(window), + sMinusDm: WilderSmoothing(window), + } + source.AddSubscriber(func(kLine types.KLine) { + if source.Length() == 1 { + s.PushAndEmit(0) + return + } + tr := s.tr.Last(0) + plusDm := high.Last(0) - high.Last(1) + minusDm := low.Last(1) - low.Last(0) + if minusDm > plusDm || plusDm < 0 { + plusDm = 0 + } + if plusDm > minusDm || minusDm < 0 { + minusDm = 0 + } + + str := s.sTr.update(tr) + spDm := s.sPlusDm.update(plusDm) + smDm := s.sMinusDm.update(minusDm) + if source.Length() < s.window { + s.PushAndEmit(0) + return + } + dx := .0 + if !almostZero(str) { + // NOTE: when tr is non-zero, str * 100.0 seems cancelled out in the formula? + pDi := spDm /// str * 100.0 + mDi := smDm /// str * 100.0 + sumDi := pDi + mDi + if !almostZero(sumDi) { + dx = math.Abs(pDi-mDi) / sumDi * 100 + } + } + + s.PushAndEmit(dx) + }) + + return s +} + +type smooth struct { + window int + k float64 + sz int + sm float64 +} + +func WilderSmoothing(window int) *smooth { + return &smooth{ + window: window, + k: float64(window-1) / float64(window), + sz: 0, + sm: 0, + } +} + +func (s *smooth) update(v float64) float64 { + s.sz++ + if s.sz < s.window { + s.sm += v + return 0 + } else { + s.sm = s.sm*s.k + v + } + + return s.sm +} + +func almostZero(v float64) bool { + return v > -0.00000000000001 && v < 0.00000000000001 +} diff --git a/pkg/indicator/v2/abdx_test.go b/pkg/indicator/v2/abdx_test.go new file mode 100644 index 0000000000..58b186bed7 --- /dev/null +++ b/pkg/indicator/v2/abdx_test.go @@ -0,0 +1,46 @@ +package indicatorv2 + +import ( + "encoding/json" + "slices" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_DX(t *testing.T) { + high := []byte(`[30.20,30.28,30.45,29.35,29.35,29.29,28.83,28.73,28.67,28.85,28.64,27.68,27.21,26.87,27.41,26.94,26.52,26.52,27.09,27.69,28.45,28.53,28.67,29.01,29.87,29.80,29.75,30.65,30.60,30.76,31.17,30.89,30.04,30.66,30.60,31.97,32.10,32.03,31.63,31.85,32.71,32.76,32.58,32.13,33.12,33.19,32.52]`) + low := []byte(`[29.41,29.32,29.96,28.74,28.56,28.41,28.08,27.43,27.66,27.83,27.40,27.09,26.18,26.13,26.63,26.13,25.43,25.35,25.88,26.96,27.14,28.01,27.88,27.99,28.76,29.14,28.71,28.93,30.03,29.39,30.14,30.43,29.35,29.99,29.52,30.94,31.54,31.36,30.92,31.20,32.13,32.23,31.97,31.56,32.21,32.63,31.76]`) + close := []byte(`[29.87,30.24,30.10,28.90,28.92,28.48,28.56,27.56,28.47,28.28,27.49,27.23,26.35,26.33,27.03,26.22,26.01,25.46,27.03,27.45,28.36,28.43,27.95,29.01,29.38,29.36,28.91,30.61,30.05,30.19,31.12,30.54,29.78,30.04,30.49,31.47,32.05,31.97,31.13,31.66,32.64,32.59,32.19,32.10,32.93,33.00,31.94]`) + buildKLines := func(high, low, close []fixedpoint.Value) (kLines []types.KLine) { + for i := range high { + kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i]}) + } + return kLines + } + var h, l, c []fixedpoint.Value + _ = json.Unmarshal(high, &h) + _ = json.Unmarshal(low, &l) + _ = json.Unmarshal(close, &c) + + expected := []float64{ + 33.58, 32.15, 29.93, 28.36, 26.90, 25.78, 23.95, 22.78, 22.07, 21.53, 20.80, 19.59, 18.72, 18.75, 18.84, 18.55, 17.73, 17.95, 18.23, 17.35, + } + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + ind := DirectionalIndex(kLines, 14) + k := buildKLines(h, l, c) + for _, candle := range k { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + // assert.InDelta(t, expected[0], ind.Slice[0], 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", 0, expected[0], ind.Slice[0]) + slices.Reverse(expected) + for i, v := range expected { + assert.InDelta(t, v, ind.Last(i), 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", i, v, ind.Last(i)) + } +} diff --git a/pkg/indicator/v2/adx.go b/pkg/indicator/v2/adx.go new file mode 100644 index 0000000000..bff91aee02 --- /dev/null +++ b/pkg/indicator/v2/adx.go @@ -0,0 +1,56 @@ +package indicatorv2 + +import "github.com/c9s/bbgo/pkg/types" + +// The Average Directional Index (ADX), Minus Directional +// Indicator (-DI) and Plus Directional Indicator (+DI) +// represent a group of directional movement indicators +// that form a trading system developed by Welles Wilder. +// Although Wilder designed his Directional Movement System +// with commodities and daily prices in mind, these indicators +// can also be applied to stocks. +// +// Positive and negative directional movement form the backbone +// of the Directional Movement System. Wilder determined +// directional movement by comparing the difference between +// two consecutive lows with the difference between their +// respective highs. +// +// The Plus Directional Indicator (+DI) and Minus Directional +// Indicator (-DI) are derived from smoothed averages of +// these differences and measure trend direction over time. +// These two indicators are often collectively referred to +// as the Directional Movement Indicator (DMI). +// +// The Average Directional Index (ADX) is in turn derived +// from the smoothed averages of the difference between +DI +// and -DI; it measures the strength of the trend +// (regardless of direction) over time. +// +// Using these three indicators together, chartists can +// determine both the direction and strength of the trend. +// +// https://school.stockcharts.com/doku.php?id=technical_indicators:average_directional_index_adx +// https://www.investopedia.com/articles/trading/07/adx-trend-indicator.asp +// https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/adx +type AdxStream struct { + *types.Float64Series + window int + dx *DxStream + adx *EWMAStream +} + +func ADX(source KLineSubscription, window int) *AdxStream { + s := &AdxStream{ + Float64Series: types.NewFloat64Series(), + window: window, + dx: DirectionalIndex(source, window), + adx: EWMA2(nil, window, 1.0/float64(window)), + } + source.AddSubscriber(func(kLine types.KLine) { + adx := s.adx.Calculate(s.dx.Last(0)) + s.adx.Push(adx) + s.PushAndEmit(adx) + }) + return s +} diff --git a/pkg/indicator/v2/adx_test.go b/pkg/indicator/v2/adx_test.go new file mode 100644 index 0000000000..e0b51e67ca --- /dev/null +++ b/pkg/indicator/v2/adx_test.go @@ -0,0 +1,47 @@ +package indicatorv2 + +import ( + "encoding/json" + "slices" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_ADX(t *testing.T) { + high := []byte(`[30.20,30.28,30.45,29.35,29.35,29.29,28.83,28.73,28.67,28.85,28.64,27.68,27.21,26.87,27.41,26.94,26.52,26.52,27.09,27.69,28.45,28.53,28.67,29.01,29.87,29.80,29.75,30.65,30.60,30.76,31.17,30.89,30.04,30.66,30.60,31.97,32.10,32.03,31.63,31.85,32.71,32.76,32.58,32.13,33.12,33.19,32.52]`) + low := []byte(`[29.41,29.32,29.96,28.74,28.56,28.41,28.08,27.43,27.66,27.83,27.40,27.09,26.18,26.13,26.63,26.13,25.43,25.35,25.88,26.96,27.14,28.01,27.88,27.99,28.76,29.14,28.71,28.93,30.03,29.39,30.14,30.43,29.35,29.99,29.52,30.94,31.54,31.36,30.92,31.20,32.13,32.23,31.97,31.56,32.21,32.63,31.76]`) + close := []byte(`[29.87,30.24,30.10,28.90,28.92,28.48,28.56,27.56,28.47,28.28,27.49,27.23,26.35,26.33,27.03,26.22,26.01,25.46,27.03,27.45,28.36,28.43,27.95,29.01,29.38,29.36,28.91,30.61,30.05,30.19,31.12,30.54,29.78,30.04,30.49,31.47,32.05,31.97,31.13,31.66,32.64,32.59,32.19,32.10,32.93,33.00,31.94]`) + buildKLines := func(high, low, close []fixedpoint.Value) (kLines []types.KLine) { + for i := range high { + kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i]}) + } + return kLines + } + var h, l, c []fixedpoint.Value + _ = json.Unmarshal(high, &h) + _ = json.Unmarshal(low, &l) + _ = json.Unmarshal(close, &c) + + expected := []float64{ + 33.58, 32.15, 29.93, 28.36, 26.90, 25.78, 23.95, 22.78, 22.07, 21.53, 20.80, 19.59, 18.72, 18.75, 18.84, 18.55, 17.73, 17.95, 18.23, 17.35, + } + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + ind := ADX(kLines, 14) + k := buildKLines(h, l, c) + for _, candle := range k { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + // assert.InDelta(t, expected[0], ind.Slice[0], 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", 0, expected[0], ind.Slice[0]) + + slices.Reverse(expected) + for i, v := range expected { + assert.InDelta(t, v, ind.Last(i), 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", i, v, ind.Last(i)) + } +} diff --git a/pkg/indicator/v2/drift.go b/pkg/indicator/v2/drift.go new file mode 100644 index 0000000000..633695bac7 --- /dev/null +++ b/pkg/indicator/v2/drift.go @@ -0,0 +1,48 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +// Refer: https://tradingview.com/script/aDymGrFx-Drift-Study-Inspired-by-Monte-Carlo-Simulations-with-BM-KL/ +// Brownian Motion's drift factor +// could be used in Monte Carlo Simulations +// +// In the context of Brownian motion, drift can be measured by calculating the simple moving average (SMA) of the logarithm +// of the price changes of a security over a specified period of time. This SMA can be used to identify the long-term trend +// or bias in the random movement of the security's price. A security with a positive drift is said to be trending upwards, +// while a security with a negative drift is said to be trending downwards. Drift can be used by traders to identify potential +// entry and exit points for trades, or to confirm other technical analysis signals. +// It is typically used in conjunction with other indicators to provide a more comprehensive view of the security's price. +type DriftStream struct { + *types.Float64Series + sma *SMAStream + window int +} + +func Drift(source KLineSubscription, window int) *DriftStream { + var ( + diffClose = DiffClose(source) + s = &DriftStream{ + Float64Series: types.NewFloat64Series(), + sma: SMA(diffClose, window), + window: window, + } + ) + source.AddSubscriber(func(v types.KLine) { + var drift float64 + + if source.Length() > s.window { + var stdev = diffClose.Stdev(s.window) + drift = s.sma.Last(0) - stdev*stdev*0.5 + } + + s.PushAndEmit(drift) + }) + + return s +} + +func (s *DriftStream) Truncate() { + s.Slice = s.Slice.Truncate(MaxNumOfMA) +} diff --git a/pkg/indicator/v2/drift_test.go b/pkg/indicator/v2/drift_test.go new file mode 100644 index 0000000000..1389faf9bd --- /dev/null +++ b/pkg/indicator/v2/drift_test.go @@ -0,0 +1,46 @@ +package indicatorv2 + +import ( + "encoding/json" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +func Test_Drift(t *testing.T) { + var randomPrices = []byte(`[1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9]`) + var input []fixedpoint.Value + _ = json.Unmarshal(randomPrices, &input) + + tests := []struct { + name string + kLines []types.KLine + all int + }{ + { + name: "random_case", + kLines: buildKLines(input), + all: 47, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + ind := Drift(kLines, 3) + for _, candle := range tt.kLines { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + assert.Equal(t, ind.Length(), tt.all) + for _, v := range ind.Slice { + assert.LessOrEqual(t, v, 1.0) + } + }) + } +} diff --git a/pkg/indicator/v2/loss_gains.go b/pkg/indicator/v2/loss_gains.go new file mode 100644 index 0000000000..10fbe2c72c --- /dev/null +++ b/pkg/indicator/v2/loss_gains.go @@ -0,0 +1,106 @@ +package indicatorv2 + +import ( + "github.com/c9s/bbgo/pkg/types" +) + +// 1 for Gain and -1 for Loss +type Coefficient int + +const ( + GainCoefficient Coefficient = 1 + LossCoefficient Coefficient = -1 +) + +type GainLossStream struct { + *types.Float64Series + coefficient, gainSum float64 +} + +// Gain returns a derivative indicator that returns the gains in the underlying indicator in the last bar, +// if any. If the delta is negative, zero is returned +// Loss returns a derivative indicator that returns the losses in the underlying indicator in the last bar, +// if any. If the delta is positive, zero is returned +func GainLoss(source KLineSubscription, coff Coefficient) *GainLossStream { + c := ClosePrices(source) + s := &GainLossStream{ + Float64Series: types.NewFloat64Series(), + coefficient: float64(coff), + gainSum: 0, + } + source.AddSubscriber(func(kLine types.KLine) { + if source.Length() == 1 { + s.PushAndEmit(Neutral) + } + + var avgGain = s.gainSum / float64(source.Length()) + var gain = c.Last(1) - c.Last(0) + if gain > 0 { + s.gainSum += gain + } + avgGain = avgGain * (float64(source.Length()-1) + gain) / float64(source.Length()) + + s.PushAndEmit(avgGain) + }) + + return s +} + +// type cumulativeIndicator struct { +// Indicator +// window int +// mult decimal.Decimal +// } + +// // NewCumulativeGainsIndicator returns a derivative indicator which returns all gains made in a base indicator for a given +// // window. +// func NewCumulativeGainsIndicator(indicator Indicator, window int) Indicator { +// return cumulativeIndicator{ +// Indicator: indicator, +// window: window, +// mult: decimal.NewFromInt(1), +// } +// } + +// // NewCumulativeLossesIndicator returns a derivative indicator which returns all losses in a base indicator for a given +// // window. +// func NewCumulativeLossesIndicator(indicator Indicator, window int) Indicator { +// return cumulativeIndicator{ +// Indicator: indicator, +// window: window, +// mult: decimal.NewFromInt(1).Neg(), +// } +// } + +// func (ci cumulativeIndicator) Calculate(index int) decimal.Decimal { +// total := decimal.NewFromInt(0.0) + +// for i := Max(1, index-(ci.window-1)); i <= index; i++ { +// diff := ci.Indicator.Calculate(i).Sub(ci.Indicator.Calculate(i - 1)) +// if diff.Mul(ci.mult).GreaterThan(decimal.Zero) { +// total = total.Add(diff.Abs()) +// } +// } + +// return total +// } + +// type percentChangeIndicator struct { +// Indicator +// } + +// // NewPercentChangeIndicator returns a derivative indicator which returns the percent change (positive or negative) +// // made in a base indicator up until the given indicator +// func NewPercentChangeIndicator(indicator Indicator) Indicator { +// return percentChangeIndicator{indicator} +// } + +// func (pgi percentChangeIndicator) Calculate(index int) decimal.Decimal { +// if index == 0 { +// return decimal.Zero +// } + +// cp := pgi.Indicator.Calculate(index) +// cplast := pgi.Indicator.Calculate(index - 1) +// return cp.Div(cplast).Sub(decimal.NewFromInt(1)) +// } diff --git a/pkg/indicator/v2/loss_gains_test.go b/pkg/indicator/v2/loss_gains_test.go new file mode 100644 index 0000000000..33a25ccfe3 --- /dev/null +++ b/pkg/indicator/v2/loss_gains_test.go @@ -0,0 +1,159 @@ +package indicatorv2 + +import ( + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/stretchr/testify/assert" + + "github.com/c9s/bbgo/pkg/types" +) + +func TestGainIndicator(t *testing.T) { + + closing := []float64{44.3389, 44.0902, 44.1497, 43.6124, 44.3278, 44.8264, 45.0955, 45.4245, 45.8433, 46.0826, 45.8931, 46.0328, 45.6140, 46.2820, 46.2820, 46.0028, 46.0328, 46.4116, 46.2222, 45.6439, 46.2122, 46.2521, 45.7137, 46.4515, 45.7835, 45.3548, 44.0288, 44.1783, 44.2181, 44.5672, 43.4205, 42.6628, 43.1314} + expected := []float64{.24, .22, .21, .22, 0.20, .19, .22, .20, .19, .23, .21, .20, .18, .18, .17, .18, .17, .16, .18} + + ts := buildKLinesFromC(closing) + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + ind := GainLoss(kLines, GainCoefficient) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected Gain.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} + +func TestLossIndicator(t *testing.T) { + ts := []types.KLine{ + {Close: n(1)}, + {Close: n(2)}, + {Close: n(3)}, + {Close: n(3)}, + {Close: n(2)}, + {Close: n(0)}, + } + expected := []float64{0, 0, 0, 0, 1, 2} + + stream := &types.StandardStream{} + kLines := KLines(stream, "", "") + ind := GainLoss(kLines, LossCoefficient) + + for _, candle := range ts { + stream.EmitKLineClosed(candle) + } + spew.Dump(ind) + for i, v := range expected { + assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected Loss.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) + } +} + +// func TestCumulativeGainsIndicator(t *testing.T) { +// t.Run("Basic", func(t *testing.T) { +// ts := mockTimeSeriesFl(1, 2, 3, 5, 8, 13) + +// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 6) + +// decimalEquals(t, 0, cumGains.Calculate(0)) +// decimalEquals(t, 1, cumGains.Calculate(1)) +// decimalEquals(t, 2, cumGains.Calculate(2)) +// decimalEquals(t, 4, cumGains.Calculate(3)) +// decimalEquals(t, 7, cumGains.Calculate(4)) +// decimalEquals(t, 12, cumGains.Calculate(5)) +// }) + +// t.Run("Oscillating scale", func(t *testing.T) { +// ts := mockTimeSeriesFl(0, 5, 2, 10, 12, 11) + +// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 6) + +// decimalEquals(t, 0, cumGains.Calculate(0)) +// decimalEquals(t, 5, cumGains.Calculate(1)) +// decimalEquals(t, 5, cumGains.Calculate(2)) +// decimalEquals(t, 13, cumGains.Calculate(3)) +// decimalEquals(t, 15, cumGains.Calculate(4)) +// decimalEquals(t, 15, cumGains.Calculate(5)) +// }) + +// t.Run("Rolling timeframe", func(t *testing.T) { +// ts := mockTimeSeriesFl(0, 5, 2, 10, 12, 11) + +// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 3) + +// decimalEquals(t, 0, cumGains.Calculate(0)) +// decimalEquals(t, 5, cumGains.Calculate(1)) +// decimalEquals(t, 5, cumGains.Calculate(2)) +// decimalEquals(t, 13, cumGains.Calculate(3)) +// decimalEquals(t, 10, cumGains.Calculate(4)) +// decimalEquals(t, 10, cumGains.Calculate(5)) +// }) +// } + +// func TestCumulativeLossesIndicator(t *testing.T) { +// t.Run("Basic", func(t *testing.T) { +// ts := mockTimeSeriesFl(13, 8, 5, 3, 2, 1) + +// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 6) + +// decimalEquals(t, 0, cumLosses.Calculate(0)) +// decimalEquals(t, 5, cumLosses.Calculate(1)) +// decimalEquals(t, 8, cumLosses.Calculate(2)) +// decimalEquals(t, 10, cumLosses.Calculate(3)) +// decimalEquals(t, 11, cumLosses.Calculate(4)) +// decimalEquals(t, 12, cumLosses.Calculate(5)) +// }) + +// t.Run("Oscillating indicator", func(t *testing.T) { +// ts := mockTimeSeriesFl(13, 16, 10, 8, 9, 8) + +// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 6) + +// decimalEquals(t, 0, cumLosses.Calculate(0)) +// decimalEquals(t, 0, cumLosses.Calculate(1)) +// decimalEquals(t, 6, cumLosses.Calculate(2)) +// decimalEquals(t, 8, cumLosses.Calculate(3)) +// decimalEquals(t, 8, cumLosses.Calculate(4)) +// decimalEquals(t, 9, cumLosses.Calculate(5)) +// }) + +// t.Run("Rolling timeframe", func(t *testing.T) { +// ts := mockTimeSeriesFl(13, 16, 10, 8, 9, 8) + +// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 3) + +// decimalEquals(t, 0, cumLosses.Calculate(0)) +// decimalEquals(t, 0, cumLosses.Calculate(1)) +// decimalEquals(t, 6, cumLosses.Calculate(2)) +// decimalEquals(t, 8, cumLosses.Calculate(3)) +// decimalEquals(t, 8, cumLosses.Calculate(4)) +// decimalEquals(t, 3, cumLosses.Calculate(5)) +// }) +// } + +// func TestPercentGainIndicator(t *testing.T) { +// t.Run("Up", func(t *testing.T) { +// ts := mockTimeSeriesFl(1, 1.5, 2.25, 2.25) + +// pgi := NewPercentChangeIndicator(NewCloseIndicator(ts)) + +// decimalEquals(t, 0, pgi.Calculate(0)) +// decimalEquals(t, .5, pgi.Calculate(1)) +// decimalEquals(t, .5, pgi.Calculate(2)) +// decimalEquals(t, 0, pgi.Calculate(3)) +// }) + +// t.Run("Down", func(t *testing.T) { +// ts := mockTimeSeriesFl(10, 5, 2.5, 2.5) + +// pgi := NewPercentChangeIndicator(NewCloseIndicator(ts)) + +// decimalEquals(t, 0, pgi.Calculate(0)) +// decimalEquals(t, -.5, pgi.Calculate(1)) +// decimalEquals(t, -.5, pgi.Calculate(2)) +// decimalEquals(t, 0, pgi.Calculate(3)) +// }) +// } diff --git a/pkg/indicator/v2/volume_profile.go b/pkg/indicator/v2/volume_profile.go deleted file mode 100644 index ad8622d935..0000000000 --- a/pkg/indicator/v2/volume_profile.go +++ /dev/null @@ -1,195 +0,0 @@ -package indicatorv2 - -import ( - "math" - - "golang.org/x/exp/slices" - "gonum.org/v1/gonum/floats" - "gonum.org/v1/gonum/stat" - - bbgofloats "github.com/c9s/bbgo/pkg/datatype/floats" - - "github.com/c9s/bbgo/pkg/types" -) - -// DefaultValueAreaPercentage is the percentage of the total volume used to calculate the value area. -const DefaultValueAreaPercentage = 0.68 - -type VolumeProfileStream struct { - *types.Float64Series - VP VolumeProfile - window int -} - -// VolumeProfile is a histogram of market price and volume. -// Intent is to show the price points with most volume during a period. -// The profile gives key features such as: -// -// Point of control (POC) -// -// Value area high (VAH) -// -// Value area low (VAL) -// -// Session High/Low -type VolumeProfile struct { - - // Bins is the histogram bins. - Bins []float64 - - // Hist is the histogram values. - Hist []float64 - - // POC is the point of control. - POC float64 - - // VAH is the value area high. - VAH float64 - - // VAL is the value area low. - VAL float64 - - // High is the highest price in the profile. - High float64 - - // Low is the lowest price in the profile. - Low float64 -} - -// VolumeLevel is a price and volume pair used to build a volume profile. -type VolumeLevel struct { - - // Price is the market price, typically the high/low average of the kline. - Price float64 - - // Volume is the total buy and sell volume at the price. - Volume float64 -} - -func NewVolumeProfile(source KLineSubscription, window int) *VolumeProfileStream { - prices := HLC3(source) - volumes := Volumes(source) - - s := &VolumeProfileStream{ - Float64Series: types.NewFloat64Series(), - window: window, - } - - source.AddSubscriber(func(v types.KLine) { - if source.Length() < window { - s.PushAndEmit(0) - return - } - var nBins = 10 - // nBins = int(math.Floor((prices.Slice.Max()-prices.Slice.Min())/binWidth)) + 1 - s.VP.High = prices.Slice.Max() - s.VP.Low = prices.Slice.Min() - sortedPrices, sortedVolumes := buildVolumeLevel(prices.Slice, volumes.Slice) - s.VP.Bins = make([]float64, nBins) - s.VP.Bins = floats.Span(s.VP.Bins, s.VP.Low, s.VP.High+1) - s.VP.Hist = stat.Histogram(nil, s.VP.Bins, sortedPrices, sortedVolumes) - - pocIdx := floats.MaxIdx(s.VP.Hist) - s.VP.POC = midBin(s.VP.Bins, pocIdx) - - // TODO the results are of by small difference whereas it is expected they work the same - // vaTotalVol := volumes.Sum() * DefaultValueAreaPercentage - // Calculate Value Area with POC as the centre point\ - vaTotalVol := floats.Sum(volumes.Slice) * DefaultValueAreaPercentage - - vaCumVol := s.VP.Hist[pocIdx] - var vahVol, valVol float64 - vahIdx, valIdx := pocIdx+1, pocIdx-1 - stepVAH, stepVAL := true, true - - for (vaCumVol <= vaTotalVol) && - (vahIdx <= len(s.VP.Hist)-1 && valIdx >= 0) { - - if stepVAH { - vahVol = 0 - for vahVol == 0 && vahIdx+1 < len(s.VP.Hist)-1 { - vahVol = s.VP.Hist[vahIdx] + s.VP.Hist[vahIdx+1] - vahIdx += 2 - } - stepVAH = false - } - - if stepVAL { - valVol = 0 - for valVol == 0 && valIdx-1 >= 0 { - valVol = s.VP.Hist[valIdx] + s.VP.Hist[valIdx-1] - valIdx -= 2 - } - stepVAL = false - } - - switch { - case vahVol > valVol: - vaCumVol += vahVol - stepVAH, stepVAL = true, false - case vahVol < valVol: - vaCumVol += valVol - stepVAH, stepVAL = false, true - case vahVol == valVol: - vaCumVol += valVol + vahVol - stepVAH, stepVAL = true, true - } - - if vahIdx >= len(s.VP.Hist)-1 { - stepVAH = false - } - - if valIdx <= 0 { - stepVAL = false - } - } - - s.VP.VAH = midBin(s.VP.Bins, vahIdx) - s.VP.VAL = midBin(s.VP.Bins, valIdx) - - }) - - return s -} - -func (s *VolumeProfileStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) -} - -func buildVolumeLevel(p, v bbgofloats.Slice) (sortedp, sortedv bbgofloats.Slice) { - var levels []VolumeLevel - for i := range p { - levels = append(levels, VolumeLevel{ - Price: p[i], - Volume: v[i], - }) - } - - slices.SortStableFunc(levels, func(i, j VolumeLevel) bool { - return i.Price < j.Price - }) - - for _, v := range levels { - sortedp.Append(v.Price) - sortedv.Append(v.Volume) - } - - return -} - -func midBin(bins []float64, idx int) float64 { - - if len(bins) == 0 { - return math.NaN() - } - - if idx >= len(bins)-1 { - return bins[len(bins)-1] - } - - if idx < 0 { - return bins[0] - } - - return stat.Mean([]float64{bins[idx], bins[idx+1]}, nil) -} diff --git a/pkg/indicator/v2/volume_profile_test.go b/pkg/indicator/v2/volume_profile_test.go deleted file mode 100644 index 4feb90845a..0000000000 --- a/pkg/indicator/v2/volume_profile_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package indicatorv2 - -import ( - "encoding/csv" - "os" - "path" - "testing" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/datasource/csvsource" - - "github.com/c9s/bbgo/pkg/types" -) - -func TestVolumeProfile(t *testing.T) { - file, _ := os.Open(path.Join("testdata", "BTCUSDT-1m-2022-05-06.csv")) - defer func() { - assert.NoError(t, file.Close()) - }() - - candles, err := csvsource.NewCSVKLineReader(csv.NewReader(file)).ReadAll(time.Minute) - assert.NoError(t, err) - - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := NewVolumeProfile(kLines, 10) - - for _, candle := range candles { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - - assert.InDelta(t, 35359.26666666667, ind.VP.Low, 0.01, "VP.LOW") - assert.InDelta(t, 35569.12777777779, ind.VP.VAL, 0.01, "VP.VAL") - assert.InDelta(t, 35988.850000000006, ind.VP.POC, 0.01, "VP.POC") - assert.InDelta(t, 36408.572222222225, ind.VP.VAH, 0.01, "VP.VAH") - assert.InDelta(t, 36617.433333333334, ind.VP.High, 0.01, "VP.HIGH") -} diff --git a/pkg/types/beta.go b/pkg/types/beta.go new file mode 100644 index 0000000000..e54d1b4f17 --- /dev/null +++ b/pkg/types/beta.go @@ -0,0 +1,82 @@ +package types + +func Beta(returns, market []float64) float64 { + if len(returns) != len(market) { + return 0.0 + } + + returnsMean := 0.0 + marketMean := 0.0 + numDataPoints := float64(len(returns)) + + for i := 0; i < len(returns); i++ { + returnsMean += returns[i] + marketMean += market[i] + } + + returnsMean /= numDataPoints + marketMean /= numDataPoints + + covar := 0.0 + marketVar := 0.0 + + for i := 0; i < len(returns); i++ { + covar += (returns[i] - returnsMean) * (market[i] - marketMean) + marketVar += (market[i] - marketMean) * (market[i] - marketMean) + } + + if marketVar == 0.0 { + return 0.0 // Avoid division by zero + } + + return covar / marketVar +} + +// func MaxDrawDown(returns []float64) (max, avg float64) { +// maxDrawdown := math.Inf(-1) + +// for i := 0; i < len(returns); i++ { +// drawdown := DrawDown(returns, i) +// if drawdown > maxDrawdown { +// maxDrawdown = drawdown +// } +// } + +// return math.Abs(maxDrawdown) +// } + +// func AverageDrawDown(returns []float64, periods int) float64 { +// drawdowns := make([]float64, len(returns)) + +// for i := 0; i < len(returns); i++ { +// drawdowns[i] = DrawDown(returns, i) +// } + +// sort.Float64s(drawdowns) + +// total_dd := math.Abs(drawdowns[0]) + +// for i := 1; i < periods; i++ { +// total_dd += math.Abs(drawdowns[i]) +// } + +// return total_dd / float64(periods) +// } + +// func AverageDrawDownSquared(returns []float64, periods int) float64 { +// drawdowns := make([]float64, len(returns)) + +// for i := 0; i < len(returns); i++ { +// drawdowns[i] = math.Pow(DrawDown(returns, i), 2.0) +// } + +// sort.Float64s(drawdowns) + +// total_dd := math.Abs(drawdowns[0]) + +// for i := 1; i < periods; i++ { +// total_dd += math.Abs(drawdowns[i]) +// } + +// return total_dd / float64(periods) +// } From 164065e93bf63aa7709cf9da33cf1036664bd5a7 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Thu, 2 Nov 2023 17:15:42 +0100 Subject: [PATCH 14/17] cleanup --- pkg/indicator/v2/abdx.go | 98 ----------------- pkg/indicator/v2/abdx_test.go | 46 -------- pkg/indicator/v2/adx.go | 56 ---------- pkg/indicator/v2/adx_test.go | 47 -------- pkg/indicator/v2/drift.go | 48 --------- pkg/indicator/v2/drift_test.go | 46 -------- pkg/indicator/v2/loss_gains.go | 106 ------------------- pkg/indicator/v2/loss_gains_test.go | 159 ---------------------------- pkg/types/beta.go | 82 -------------- 9 files changed, 688 deletions(-) delete mode 100644 pkg/indicator/v2/abdx.go delete mode 100644 pkg/indicator/v2/abdx_test.go delete mode 100644 pkg/indicator/v2/adx.go delete mode 100644 pkg/indicator/v2/adx_test.go delete mode 100644 pkg/indicator/v2/drift.go delete mode 100644 pkg/indicator/v2/drift_test.go delete mode 100644 pkg/indicator/v2/loss_gains.go delete mode 100644 pkg/indicator/v2/loss_gains_test.go delete mode 100644 pkg/types/beta.go diff --git a/pkg/indicator/v2/abdx.go b/pkg/indicator/v2/abdx.go deleted file mode 100644 index 5e2ac8fcf3..0000000000 --- a/pkg/indicator/v2/abdx.go +++ /dev/null @@ -1,98 +0,0 @@ -package indicatorv2 - -import ( - "math" - - "github.com/c9s/bbgo/pkg/types" -) - -type DxStream struct { - *types.Float64Series - window int - tr *TRStream - sTr *smooth - sPlusDm *smooth - sMinusDm *smooth -} - -func DirectionalIndex(source KLineSubscription, window int) *DxStream { - high := HighPrices(source) - low := LowPrices(source) - s := &DxStream{ - Float64Series: types.NewFloat64Series(), - window: window, - tr: TR2(source), - sTr: WilderSmoothing(window), - sPlusDm: WilderSmoothing(window), - sMinusDm: WilderSmoothing(window), - } - source.AddSubscriber(func(kLine types.KLine) { - if source.Length() == 1 { - s.PushAndEmit(0) - return - } - tr := s.tr.Last(0) - plusDm := high.Last(0) - high.Last(1) - minusDm := low.Last(1) - low.Last(0) - if minusDm > plusDm || plusDm < 0 { - plusDm = 0 - } - if plusDm > minusDm || minusDm < 0 { - minusDm = 0 - } - - str := s.sTr.update(tr) - spDm := s.sPlusDm.update(plusDm) - smDm := s.sMinusDm.update(minusDm) - if source.Length() < s.window { - s.PushAndEmit(0) - return - } - dx := .0 - if !almostZero(str) { - // NOTE: when tr is non-zero, str * 100.0 seems cancelled out in the formula? - pDi := spDm /// str * 100.0 - mDi := smDm /// str * 100.0 - sumDi := pDi + mDi - if !almostZero(sumDi) { - dx = math.Abs(pDi-mDi) / sumDi * 100 - } - } - - s.PushAndEmit(dx) - }) - - return s -} - -type smooth struct { - window int - k float64 - sz int - sm float64 -} - -func WilderSmoothing(window int) *smooth { - return &smooth{ - window: window, - k: float64(window-1) / float64(window), - sz: 0, - sm: 0, - } -} - -func (s *smooth) update(v float64) float64 { - s.sz++ - if s.sz < s.window { - s.sm += v - return 0 - } else { - s.sm = s.sm*s.k + v - } - - return s.sm -} - -func almostZero(v float64) bool { - return v > -0.00000000000001 && v < 0.00000000000001 -} diff --git a/pkg/indicator/v2/abdx_test.go b/pkg/indicator/v2/abdx_test.go deleted file mode 100644 index 58b186bed7..0000000000 --- a/pkg/indicator/v2/abdx_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package indicatorv2 - -import ( - "encoding/json" - "slices" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -func Test_DX(t *testing.T) { - high := []byte(`[30.20,30.28,30.45,29.35,29.35,29.29,28.83,28.73,28.67,28.85,28.64,27.68,27.21,26.87,27.41,26.94,26.52,26.52,27.09,27.69,28.45,28.53,28.67,29.01,29.87,29.80,29.75,30.65,30.60,30.76,31.17,30.89,30.04,30.66,30.60,31.97,32.10,32.03,31.63,31.85,32.71,32.76,32.58,32.13,33.12,33.19,32.52]`) - low := []byte(`[29.41,29.32,29.96,28.74,28.56,28.41,28.08,27.43,27.66,27.83,27.40,27.09,26.18,26.13,26.63,26.13,25.43,25.35,25.88,26.96,27.14,28.01,27.88,27.99,28.76,29.14,28.71,28.93,30.03,29.39,30.14,30.43,29.35,29.99,29.52,30.94,31.54,31.36,30.92,31.20,32.13,32.23,31.97,31.56,32.21,32.63,31.76]`) - close := []byte(`[29.87,30.24,30.10,28.90,28.92,28.48,28.56,27.56,28.47,28.28,27.49,27.23,26.35,26.33,27.03,26.22,26.01,25.46,27.03,27.45,28.36,28.43,27.95,29.01,29.38,29.36,28.91,30.61,30.05,30.19,31.12,30.54,29.78,30.04,30.49,31.47,32.05,31.97,31.13,31.66,32.64,32.59,32.19,32.10,32.93,33.00,31.94]`) - buildKLines := func(high, low, close []fixedpoint.Value) (kLines []types.KLine) { - for i := range high { - kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i]}) - } - return kLines - } - var h, l, c []fixedpoint.Value - _ = json.Unmarshal(high, &h) - _ = json.Unmarshal(low, &l) - _ = json.Unmarshal(close, &c) - - expected := []float64{ - 33.58, 32.15, 29.93, 28.36, 26.90, 25.78, 23.95, 22.78, 22.07, 21.53, 20.80, 19.59, 18.72, 18.75, 18.84, 18.55, 17.73, 17.95, 18.23, 17.35, - } - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := DirectionalIndex(kLines, 14) - k := buildKLines(h, l, c) - for _, candle := range k { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - // assert.InDelta(t, expected[0], ind.Slice[0], 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", 0, expected[0], ind.Slice[0]) - slices.Reverse(expected) - for i, v := range expected { - assert.InDelta(t, v, ind.Last(i), 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", i, v, ind.Last(i)) - } -} diff --git a/pkg/indicator/v2/adx.go b/pkg/indicator/v2/adx.go deleted file mode 100644 index bff91aee02..0000000000 --- a/pkg/indicator/v2/adx.go +++ /dev/null @@ -1,56 +0,0 @@ -package indicatorv2 - -import "github.com/c9s/bbgo/pkg/types" - -// The Average Directional Index (ADX), Minus Directional -// Indicator (-DI) and Plus Directional Indicator (+DI) -// represent a group of directional movement indicators -// that form a trading system developed by Welles Wilder. -// Although Wilder designed his Directional Movement System -// with commodities and daily prices in mind, these indicators -// can also be applied to stocks. -// -// Positive and negative directional movement form the backbone -// of the Directional Movement System. Wilder determined -// directional movement by comparing the difference between -// two consecutive lows with the difference between their -// respective highs. -// -// The Plus Directional Indicator (+DI) and Minus Directional -// Indicator (-DI) are derived from smoothed averages of -// these differences and measure trend direction over time. -// These two indicators are often collectively referred to -// as the Directional Movement Indicator (DMI). -// -// The Average Directional Index (ADX) is in turn derived -// from the smoothed averages of the difference between +DI -// and -DI; it measures the strength of the trend -// (regardless of direction) over time. -// -// Using these three indicators together, chartists can -// determine both the direction and strength of the trend. -// -// https://school.stockcharts.com/doku.php?id=technical_indicators:average_directional_index_adx -// https://www.investopedia.com/articles/trading/07/adx-trend-indicator.asp -// https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/adx -type AdxStream struct { - *types.Float64Series - window int - dx *DxStream - adx *EWMAStream -} - -func ADX(source KLineSubscription, window int) *AdxStream { - s := &AdxStream{ - Float64Series: types.NewFloat64Series(), - window: window, - dx: DirectionalIndex(source, window), - adx: EWMA2(nil, window, 1.0/float64(window)), - } - source.AddSubscriber(func(kLine types.KLine) { - adx := s.adx.Calculate(s.dx.Last(0)) - s.adx.Push(adx) - s.PushAndEmit(adx) - }) - return s -} diff --git a/pkg/indicator/v2/adx_test.go b/pkg/indicator/v2/adx_test.go deleted file mode 100644 index e0b51e67ca..0000000000 --- a/pkg/indicator/v2/adx_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package indicatorv2 - -import ( - "encoding/json" - "slices" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -func Test_ADX(t *testing.T) { - high := []byte(`[30.20,30.28,30.45,29.35,29.35,29.29,28.83,28.73,28.67,28.85,28.64,27.68,27.21,26.87,27.41,26.94,26.52,26.52,27.09,27.69,28.45,28.53,28.67,29.01,29.87,29.80,29.75,30.65,30.60,30.76,31.17,30.89,30.04,30.66,30.60,31.97,32.10,32.03,31.63,31.85,32.71,32.76,32.58,32.13,33.12,33.19,32.52]`) - low := []byte(`[29.41,29.32,29.96,28.74,28.56,28.41,28.08,27.43,27.66,27.83,27.40,27.09,26.18,26.13,26.63,26.13,25.43,25.35,25.88,26.96,27.14,28.01,27.88,27.99,28.76,29.14,28.71,28.93,30.03,29.39,30.14,30.43,29.35,29.99,29.52,30.94,31.54,31.36,30.92,31.20,32.13,32.23,31.97,31.56,32.21,32.63,31.76]`) - close := []byte(`[29.87,30.24,30.10,28.90,28.92,28.48,28.56,27.56,28.47,28.28,27.49,27.23,26.35,26.33,27.03,26.22,26.01,25.46,27.03,27.45,28.36,28.43,27.95,29.01,29.38,29.36,28.91,30.61,30.05,30.19,31.12,30.54,29.78,30.04,30.49,31.47,32.05,31.97,31.13,31.66,32.64,32.59,32.19,32.10,32.93,33.00,31.94]`) - buildKLines := func(high, low, close []fixedpoint.Value) (kLines []types.KLine) { - for i := range high { - kLines = append(kLines, types.KLine{High: high[i], Low: low[i], Close: close[i]}) - } - return kLines - } - var h, l, c []fixedpoint.Value - _ = json.Unmarshal(high, &h) - _ = json.Unmarshal(low, &l) - _ = json.Unmarshal(close, &c) - - expected := []float64{ - 33.58, 32.15, 29.93, 28.36, 26.90, 25.78, 23.95, 22.78, 22.07, 21.53, 20.80, 19.59, 18.72, 18.75, 18.84, 18.55, 17.73, 17.95, 18.23, 17.35, - } - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := ADX(kLines, 14) - k := buildKLines(h, l, c) - for _, candle := range k { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - // assert.InDelta(t, expected[0], ind.Slice[0], 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", 0, expected[0], ind.Slice[0]) - - slices.Reverse(expected) - for i, v := range expected { - assert.InDelta(t, v, ind.Last(i), 0.000001, "Expected ADX.slice[%d] to be %v, but got %v", i, v, ind.Last(i)) - } -} diff --git a/pkg/indicator/v2/drift.go b/pkg/indicator/v2/drift.go deleted file mode 100644 index 633695bac7..0000000000 --- a/pkg/indicator/v2/drift.go +++ /dev/null @@ -1,48 +0,0 @@ -package indicatorv2 - -import ( - "github.com/c9s/bbgo/pkg/types" -) - -// Refer: https://tradingview.com/script/aDymGrFx-Drift-Study-Inspired-by-Monte-Carlo-Simulations-with-BM-KL/ -// Brownian Motion's drift factor -// could be used in Monte Carlo Simulations -// -// In the context of Brownian motion, drift can be measured by calculating the simple moving average (SMA) of the logarithm -// of the price changes of a security over a specified period of time. This SMA can be used to identify the long-term trend -// or bias in the random movement of the security's price. A security with a positive drift is said to be trending upwards, -// while a security with a negative drift is said to be trending downwards. Drift can be used by traders to identify potential -// entry and exit points for trades, or to confirm other technical analysis signals. -// It is typically used in conjunction with other indicators to provide a more comprehensive view of the security's price. -type DriftStream struct { - *types.Float64Series - sma *SMAStream - window int -} - -func Drift(source KLineSubscription, window int) *DriftStream { - var ( - diffClose = DiffClose(source) - s = &DriftStream{ - Float64Series: types.NewFloat64Series(), - sma: SMA(diffClose, window), - window: window, - } - ) - source.AddSubscriber(func(v types.KLine) { - var drift float64 - - if source.Length() > s.window { - var stdev = diffClose.Stdev(s.window) - drift = s.sma.Last(0) - stdev*stdev*0.5 - } - - s.PushAndEmit(drift) - }) - - return s -} - -func (s *DriftStream) Truncate() { - s.Slice = s.Slice.Truncate(MaxNumOfMA) -} diff --git a/pkg/indicator/v2/drift_test.go b/pkg/indicator/v2/drift_test.go deleted file mode 100644 index 1389faf9bd..0000000000 --- a/pkg/indicator/v2/drift_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package indicatorv2 - -import ( - "encoding/json" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" -) - -func Test_Drift(t *testing.T) { - var randomPrices = []byte(`[1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 1, 2, 3, 4, 5, 6, 7, 8, 9]`) - var input []fixedpoint.Value - _ = json.Unmarshal(randomPrices, &input) - - tests := []struct { - name string - kLines []types.KLine - all int - }{ - { - name: "random_case", - kLines: buildKLines(input), - all: 47, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := Drift(kLines, 3) - for _, candle := range tt.kLines { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - assert.Equal(t, ind.Length(), tt.all) - for _, v := range ind.Slice { - assert.LessOrEqual(t, v, 1.0) - } - }) - } -} diff --git a/pkg/indicator/v2/loss_gains.go b/pkg/indicator/v2/loss_gains.go deleted file mode 100644 index 10fbe2c72c..0000000000 --- a/pkg/indicator/v2/loss_gains.go +++ /dev/null @@ -1,106 +0,0 @@ -package indicatorv2 - -import ( - "github.com/c9s/bbgo/pkg/types" -) - -// 1 for Gain and -1 for Loss -type Coefficient int - -const ( - GainCoefficient Coefficient = 1 - LossCoefficient Coefficient = -1 -) - -type GainLossStream struct { - *types.Float64Series - coefficient, gainSum float64 -} - -// Gain returns a derivative indicator that returns the gains in the underlying indicator in the last bar, -// if any. If the delta is negative, zero is returned -// Loss returns a derivative indicator that returns the losses in the underlying indicator in the last bar, -// if any. If the delta is positive, zero is returned -func GainLoss(source KLineSubscription, coff Coefficient) *GainLossStream { - c := ClosePrices(source) - s := &GainLossStream{ - Float64Series: types.NewFloat64Series(), - coefficient: float64(coff), - gainSum: 0, - } - source.AddSubscriber(func(kLine types.KLine) { - if source.Length() == 1 { - s.PushAndEmit(Neutral) - } - - var avgGain = s.gainSum / float64(source.Length()) - var gain = c.Last(1) - c.Last(0) - if gain > 0 { - s.gainSum += gain - } - avgGain = avgGain * (float64(source.Length()-1) + gain) / float64(source.Length()) - - s.PushAndEmit(avgGain) - }) - - return s -} - -// type cumulativeIndicator struct { -// Indicator -// window int -// mult decimal.Decimal -// } - -// // NewCumulativeGainsIndicator returns a derivative indicator which returns all gains made in a base indicator for a given -// // window. -// func NewCumulativeGainsIndicator(indicator Indicator, window int) Indicator { -// return cumulativeIndicator{ -// Indicator: indicator, -// window: window, -// mult: decimal.NewFromInt(1), -// } -// } - -// // NewCumulativeLossesIndicator returns a derivative indicator which returns all losses in a base indicator for a given -// // window. -// func NewCumulativeLossesIndicator(indicator Indicator, window int) Indicator { -// return cumulativeIndicator{ -// Indicator: indicator, -// window: window, -// mult: decimal.NewFromInt(1).Neg(), -// } -// } - -// func (ci cumulativeIndicator) Calculate(index int) decimal.Decimal { -// total := decimal.NewFromInt(0.0) - -// for i := Max(1, index-(ci.window-1)); i <= index; i++ { -// diff := ci.Indicator.Calculate(i).Sub(ci.Indicator.Calculate(i - 1)) -// if diff.Mul(ci.mult).GreaterThan(decimal.Zero) { -// total = total.Add(diff.Abs()) -// } -// } - -// return total -// } - -// type percentChangeIndicator struct { -// Indicator -// } - -// // NewPercentChangeIndicator returns a derivative indicator which returns the percent change (positive or negative) -// // made in a base indicator up until the given indicator -// func NewPercentChangeIndicator(indicator Indicator) Indicator { -// return percentChangeIndicator{indicator} -// } - -// func (pgi percentChangeIndicator) Calculate(index int) decimal.Decimal { -// if index == 0 { -// return decimal.Zero -// } - -// cp := pgi.Indicator.Calculate(index) -// cplast := pgi.Indicator.Calculate(index - 1) -// return cp.Div(cplast).Sub(decimal.NewFromInt(1)) -// } diff --git a/pkg/indicator/v2/loss_gains_test.go b/pkg/indicator/v2/loss_gains_test.go deleted file mode 100644 index 33a25ccfe3..0000000000 --- a/pkg/indicator/v2/loss_gains_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package indicatorv2 - -import ( - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/stretchr/testify/assert" - - "github.com/c9s/bbgo/pkg/types" -) - -func TestGainIndicator(t *testing.T) { - - closing := []float64{44.3389, 44.0902, 44.1497, 43.6124, 44.3278, 44.8264, 45.0955, 45.4245, 45.8433, 46.0826, 45.8931, 46.0328, 45.6140, 46.2820, 46.2820, 46.0028, 46.0328, 46.4116, 46.2222, 45.6439, 46.2122, 46.2521, 45.7137, 46.4515, 45.7835, 45.3548, 44.0288, 44.1783, 44.2181, 44.5672, 43.4205, 42.6628, 43.1314} - expected := []float64{.24, .22, .21, .22, 0.20, .19, .22, .20, .19, .23, .21, .20, .18, .18, .17, .18, .17, .16, .18} - - ts := buildKLinesFromC(closing) - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := GainLoss(kLines, GainCoefficient) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - for i, v := range expected { - assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected Gain.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) - } -} - -func TestLossIndicator(t *testing.T) { - ts := []types.KLine{ - {Close: n(1)}, - {Close: n(2)}, - {Close: n(3)}, - {Close: n(3)}, - {Close: n(2)}, - {Close: n(0)}, - } - expected := []float64{0, 0, 0, 0, 1, 2} - - stream := &types.StandardStream{} - kLines := KLines(stream, "", "") - ind := GainLoss(kLines, LossCoefficient) - - for _, candle := range ts { - stream.EmitKLineClosed(candle) - } - spew.Dump(ind) - for i, v := range expected { - assert.InDelta(t, v, ind.Slice[i], 0.01, "Expected Loss.slice[%d] to be %v, but got %v", i, v, ind.Slice[i]) - } -} - -// func TestCumulativeGainsIndicator(t *testing.T) { -// t.Run("Basic", func(t *testing.T) { -// ts := mockTimeSeriesFl(1, 2, 3, 5, 8, 13) - -// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 6) - -// decimalEquals(t, 0, cumGains.Calculate(0)) -// decimalEquals(t, 1, cumGains.Calculate(1)) -// decimalEquals(t, 2, cumGains.Calculate(2)) -// decimalEquals(t, 4, cumGains.Calculate(3)) -// decimalEquals(t, 7, cumGains.Calculate(4)) -// decimalEquals(t, 12, cumGains.Calculate(5)) -// }) - -// t.Run("Oscillating scale", func(t *testing.T) { -// ts := mockTimeSeriesFl(0, 5, 2, 10, 12, 11) - -// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 6) - -// decimalEquals(t, 0, cumGains.Calculate(0)) -// decimalEquals(t, 5, cumGains.Calculate(1)) -// decimalEquals(t, 5, cumGains.Calculate(2)) -// decimalEquals(t, 13, cumGains.Calculate(3)) -// decimalEquals(t, 15, cumGains.Calculate(4)) -// decimalEquals(t, 15, cumGains.Calculate(5)) -// }) - -// t.Run("Rolling timeframe", func(t *testing.T) { -// ts := mockTimeSeriesFl(0, 5, 2, 10, 12, 11) - -// cumGains := NewCumulativeGainsIndicator(NewCloseIndicator(ts), 3) - -// decimalEquals(t, 0, cumGains.Calculate(0)) -// decimalEquals(t, 5, cumGains.Calculate(1)) -// decimalEquals(t, 5, cumGains.Calculate(2)) -// decimalEquals(t, 13, cumGains.Calculate(3)) -// decimalEquals(t, 10, cumGains.Calculate(4)) -// decimalEquals(t, 10, cumGains.Calculate(5)) -// }) -// } - -// func TestCumulativeLossesIndicator(t *testing.T) { -// t.Run("Basic", func(t *testing.T) { -// ts := mockTimeSeriesFl(13, 8, 5, 3, 2, 1) - -// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 6) - -// decimalEquals(t, 0, cumLosses.Calculate(0)) -// decimalEquals(t, 5, cumLosses.Calculate(1)) -// decimalEquals(t, 8, cumLosses.Calculate(2)) -// decimalEquals(t, 10, cumLosses.Calculate(3)) -// decimalEquals(t, 11, cumLosses.Calculate(4)) -// decimalEquals(t, 12, cumLosses.Calculate(5)) -// }) - -// t.Run("Oscillating indicator", func(t *testing.T) { -// ts := mockTimeSeriesFl(13, 16, 10, 8, 9, 8) - -// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 6) - -// decimalEquals(t, 0, cumLosses.Calculate(0)) -// decimalEquals(t, 0, cumLosses.Calculate(1)) -// decimalEquals(t, 6, cumLosses.Calculate(2)) -// decimalEquals(t, 8, cumLosses.Calculate(3)) -// decimalEquals(t, 8, cumLosses.Calculate(4)) -// decimalEquals(t, 9, cumLosses.Calculate(5)) -// }) - -// t.Run("Rolling timeframe", func(t *testing.T) { -// ts := mockTimeSeriesFl(13, 16, 10, 8, 9, 8) - -// cumLosses := NewCumulativeLossesIndicator(NewCloseIndicator(ts), 3) - -// decimalEquals(t, 0, cumLosses.Calculate(0)) -// decimalEquals(t, 0, cumLosses.Calculate(1)) -// decimalEquals(t, 6, cumLosses.Calculate(2)) -// decimalEquals(t, 8, cumLosses.Calculate(3)) -// decimalEquals(t, 8, cumLosses.Calculate(4)) -// decimalEquals(t, 3, cumLosses.Calculate(5)) -// }) -// } - -// func TestPercentGainIndicator(t *testing.T) { -// t.Run("Up", func(t *testing.T) { -// ts := mockTimeSeriesFl(1, 1.5, 2.25, 2.25) - -// pgi := NewPercentChangeIndicator(NewCloseIndicator(ts)) - -// decimalEquals(t, 0, pgi.Calculate(0)) -// decimalEquals(t, .5, pgi.Calculate(1)) -// decimalEquals(t, .5, pgi.Calculate(2)) -// decimalEquals(t, 0, pgi.Calculate(3)) -// }) - -// t.Run("Down", func(t *testing.T) { -// ts := mockTimeSeriesFl(10, 5, 2.5, 2.5) - -// pgi := NewPercentChangeIndicator(NewCloseIndicator(ts)) - -// decimalEquals(t, 0, pgi.Calculate(0)) -// decimalEquals(t, -.5, pgi.Calculate(1)) -// decimalEquals(t, -.5, pgi.Calculate(2)) -// decimalEquals(t, 0, pgi.Calculate(3)) -// }) -// } diff --git a/pkg/types/beta.go b/pkg/types/beta.go deleted file mode 100644 index e54d1b4f17..0000000000 --- a/pkg/types/beta.go +++ /dev/null @@ -1,82 +0,0 @@ -package types - -func Beta(returns, market []float64) float64 { - if len(returns) != len(market) { - return 0.0 - } - - returnsMean := 0.0 - marketMean := 0.0 - numDataPoints := float64(len(returns)) - - for i := 0; i < len(returns); i++ { - returnsMean += returns[i] - marketMean += market[i] - } - - returnsMean /= numDataPoints - marketMean /= numDataPoints - - covar := 0.0 - marketVar := 0.0 - - for i := 0; i < len(returns); i++ { - covar += (returns[i] - returnsMean) * (market[i] - marketMean) - marketVar += (market[i] - marketMean) * (market[i] - marketMean) - } - - if marketVar == 0.0 { - return 0.0 // Avoid division by zero - } - - return covar / marketVar -} - -// func MaxDrawDown(returns []float64) (max, avg float64) { -// maxDrawdown := math.Inf(-1) - -// for i := 0; i < len(returns); i++ { -// drawdown := DrawDown(returns, i) -// if drawdown > maxDrawdown { -// maxDrawdown = drawdown -// } -// } - -// return math.Abs(maxDrawdown) -// } - -// func AverageDrawDown(returns []float64, periods int) float64 { -// drawdowns := make([]float64, len(returns)) - -// for i := 0; i < len(returns); i++ { -// drawdowns[i] = DrawDown(returns, i) -// } - -// sort.Float64s(drawdowns) - -// total_dd := math.Abs(drawdowns[0]) - -// for i := 1; i < periods; i++ { -// total_dd += math.Abs(drawdowns[i]) -// } - -// return total_dd / float64(periods) -// } - -// func AverageDrawDownSquared(returns []float64, periods int) float64 { -// drawdowns := make([]float64, len(returns)) - -// for i := 0; i < len(returns); i++ { -// drawdowns[i] = math.Pow(DrawDown(returns, i), 2.0) -// } - -// sort.Float64s(drawdowns) - -// total_dd := math.Abs(drawdowns[0]) - -// for i := 1; i < periods; i++ { -// total_dd += math.Abs(drawdowns[i]) -// } - -// return total_dd / float64(periods) -// } From ed115252a21690259e631ca0d300b5ebe20bdd32 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 6 Nov 2023 22:59:08 +0100 Subject: [PATCH 15/17] fixedpoint compare --- pkg/fixedpoint/helpers.go | 3 +- pkg/indicator/v2/abondoned_baby.go | 20 +++++----- .../v2/accumulation_distiribution.go | 3 +- pkg/indicator/v2/awseome_osc.go | 2 +- pkg/indicator/v2/belthold.go | 16 ++++---- pkg/indicator/v2/breakaway.go | 22 +++++++---- pkg/indicator/v2/chaikin_money_flow.go | 3 +- pkg/indicator/v2/chaikin_osc.go | 2 +- pkg/indicator/v2/chandelier_exit.go | 2 +- pkg/indicator/v2/dark_cloud.go | 10 ++--- pkg/indicator/v2/doji_dragon_fly.go | 1 - pkg/indicator/v2/doji_long_legged.go | 25 ++++++------ pkg/indicator/v2/doji_star.go | 31 +++++++-------- pkg/indicator/v2/donchian_channel.go | 6 +-- pkg/indicator/v2/downside_tazuki_gap.go | 16 ++++---- pkg/indicator/v2/engulfing.go | 12 +++--- pkg/indicator/v2/harami.go | 12 +++--- pkg/indicator/v2/harami_cross.go | 21 +++++----- pkg/indicator/v2/kicking.go | 12 +++--- pkg/indicator/v2/marubozu.go | 4 +- pkg/indicator/v2/meeting_lines.go | 17 ++++---- pkg/indicator/v2/morning_evening_star.go | 39 +++++++++---------- pkg/indicator/v2/negative_volume_index.go | 3 +- pkg/indicator/v2/obv.go | 6 +-- pkg/indicator/v2/pattern.go | 8 ++-- pkg/indicator/v2/piercing_line.go | 13 ++++--- pkg/indicator/v2/separating_lines.go | 17 ++++---- pkg/indicator/v2/side_by_side_whitelines.go | 29 +++++++------- pkg/indicator/v2/spinning_top.go | 17 ++++---- pkg/indicator/v2/three_crows.go | 22 ++++++----- pkg/indicator/v2/three_line_strike.go | 32 +++++++-------- pkg/indicator/v2/three_white_soldiers.go | 18 ++++----- pkg/indicator/v2/ulcer_index.go | 2 +- pkg/indicator/v2/vwap.go | 2 +- pkg/indicator/v2/williams_r.go | 2 +- 35 files changed, 225 insertions(+), 225 deletions(-) diff --git a/pkg/fixedpoint/helpers.go b/pkg/fixedpoint/helpers.go index 2d3ed53845..5e4e87ae49 100644 --- a/pkg/fixedpoint/helpers.go +++ b/pkg/fixedpoint/helpers.go @@ -23,5 +23,6 @@ func ApproxEqual(a, b Value, maxDiff float64) bool { smallMultiple := a.Mul(NewFromFloat(maxDiff)) // Compare the absolute difference to the small multiple - return diff <= smallMultiple + cmp := diff.Compare(smallMultiple) + return cmp == -1 || cmp == 0 } diff --git a/pkg/indicator/v2/abondoned_baby.go b/pkg/indicator/v2/abondoned_baby.go index f40c78cccb..75751b1ebf 100644 --- a/pkg/indicator/v2/abondoned_baby.go +++ b/pkg/indicator/v2/abondoned_baby.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -32,22 +31,25 @@ func AbondonedBaby(source KLineSubscription) *AbondonedBabyStream { one = source.Last(2) two = source.Last(1) three = source.Last(0) + abs = fixedpoint.Abs((two.Close.Sub(two.Open).Div(two.Open))).Float64() ) - if one.Open < one.Close { - if one.High < two.Low { - if fixedpoint.Abs((two.Close-two.Open)/(two.Open)) < threshold { - if three.Open < two.Low && three.Close < three.Open { + if one.Open.Float64() < one.Close.Float64() { + if one.High.Float64() < two.Low.Float64() { + if abs < threshold { + if three.Open.Float64() < two.Low.Float64() && + three.Close.Float64() < three.Open.Float64() { output = -1.0 } } } } - if one.Open > one.Close { - if one.Low > two.High { - if fixedpoint.Abs((two.Close-two.Open)/two.Open) <= threshold { - if three.Open > two.High && three.Close > three.Open { + if one.Open.Float64() > one.Close.Float64() { + if one.Low.Float64() > two.High.Float64() { + if abs <= threshold { + if three.Open.Float64() > two.High.Float64() && + three.Close.Float64() > three.Open.Float64() { output = 1.0 } } diff --git a/pkg/indicator/v2/accumulation_distiribution.go b/pkg/indicator/v2/accumulation_distiribution.go index e7d246ca23..c635158c21 100644 --- a/pkg/indicator/v2/accumulation_distiribution.go +++ b/pkg/indicator/v2/accumulation_distiribution.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -44,5 +43,5 @@ func AccumulationDistribution(source KLineSubscription) *AccumulationDistributio } func (s *AccumulationDistributionStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/awseome_osc.go b/pkg/indicator/v2/awseome_osc.go index 5a5be23664..e48b4e61cb 100644 --- a/pkg/indicator/v2/awseome_osc.go +++ b/pkg/indicator/v2/awseome_osc.go @@ -57,7 +57,7 @@ func (s *AwesomeOscillatorStream) Calculate(v float64) float64 { } func (s *AwesomeOscillatorStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } // todo move this diff --git a/pkg/indicator/v2/belthold.go b/pkg/indicator/v2/belthold.go index 32cad9781a..f00a5f4289 100644 --- a/pkg/indicator/v2/belthold.go +++ b/pkg/indicator/v2/belthold.go @@ -30,20 +30,20 @@ func Belthold(source KLineSubscription) *BeltholdStream { one = source.Last(0) ) - if two.Close > two.Open { - if two.High < one.Open { - if one.Open == one.High { - if one.Close < one.Open { + if two.Close.Float64() > two.Open.Float64() { + if two.High.Float64() < one.Open.Float64() { + if one.Open.Float64() == one.High.Float64() { + if one.Close.Float64() < one.Open.Float64() { output = Bear } } } } - if two.Close < two.Open { - if two.Low > one.Open { - if one.Open == one.Low { - if one.Close > one.Open { + if two.Close.Float64() < two.Open.Float64() { + if two.Low.Float64() > one.Open.Float64() { + if one.Open.Float64() == one.Low.Float64() { + if one.Close.Float64() > one.Open.Float64() { output = Bull } } diff --git a/pkg/indicator/v2/breakaway.go b/pkg/indicator/v2/breakaway.go index 7e37a38c14..8086efe269 100644 --- a/pkg/indicator/v2/breakaway.go +++ b/pkg/indicator/v2/breakaway.go @@ -33,20 +33,26 @@ func BreakAway(source KLineSubscription) *BreakAwayStream { one = source.Last(0) ) - if five.Open < five.Close { - if four.Open < four.Close && five.Close < four.Open { - if four.Close < three.Close && three.Close < two.Close { - if one.Open > one.Close && one.Close > five.Close { + if five.Open.Float64() < five.Close.Float64() { + if four.Open.Float64() < four.Close.Float64() && + five.Close.Float64() < four.Open.Float64() { + if four.Close.Float64() < three.Close.Float64() && + three.Close.Float64() < two.Close.Float64() { + if one.Open.Float64() > one.Close.Float64() && + one.Close.Float64() > five.Close.Float64() { output = Bear } } } } - if five.Open > five.Close { - if four.Open > four.Close && five.Close > four.Open { - if four.Close > three.Close && three.Close > two.Close { - if one.Open < one.Close && one.Close < five.Close { + if five.Open.Float64() > five.Close.Float64() { + if four.Open.Float64() > four.Close.Float64() && + five.Close.Float64() > four.Open.Float64() { + if four.Close.Float64() > three.Close.Float64() && + three.Close.Float64() > two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() && + one.Close.Float64() < five.Close.Float64() { output = Bull } } diff --git a/pkg/indicator/v2/chaikin_money_flow.go b/pkg/indicator/v2/chaikin_money_flow.go index 29b2f4846e..a028bcaa42 100644 --- a/pkg/indicator/v2/chaikin_money_flow.go +++ b/pkg/indicator/v2/chaikin_money_flow.go @@ -4,7 +4,6 @@ import ( "gonum.org/v1/gonum/floats" bbfloat "github.com/c9s/bbgo/pkg/datatype/floats" - "github.com/c9s/bbgo/pkg/types" ) @@ -50,7 +49,7 @@ func ChaikinMoneyFlow(source KLineSubscription, window int) *ChaikinMoneyFlowStr } func (s *ChaikinMoneyFlowStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } func ChaikinMoneyFlowDefault(source KLineSubscription) *ChaikinMoneyFlowStream { diff --git a/pkg/indicator/v2/chaikin_osc.go b/pkg/indicator/v2/chaikin_osc.go index a78d20cdd6..c32aa81c18 100644 --- a/pkg/indicator/v2/chaikin_osc.go +++ b/pkg/indicator/v2/chaikin_osc.go @@ -32,5 +32,5 @@ func ChaikinOscillator(source KLineSubscription, slow, fast int) *ChaikinOscilla } func (s *ChaikinOscillatorStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/chandelier_exit.go b/pkg/indicator/v2/chandelier_exit.go index cec0623f6f..bac4db2033 100644 --- a/pkg/indicator/v2/chandelier_exit.go +++ b/pkg/indicator/v2/chandelier_exit.go @@ -57,5 +57,5 @@ func ChandelierExitDefault(source KLineSubscription, os OrderSide) *ChandelierEx } func (s *ChandelierExitStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/dark_cloud.go b/pkg/indicator/v2/dark_cloud.go index 5a5939c366..2c8492b02f 100644 --- a/pkg/indicator/v2/dark_cloud.go +++ b/pkg/indicator/v2/dark_cloud.go @@ -34,11 +34,11 @@ func DarkCloud(source KLineSubscription) *DarkCloudStream { var ( two = source.Last(1) one = source.Last(0) - twoMidpoint = (two.Close + two.Open) / 2 - isFirstBullish = two.Close > two.Open - isSecondBearish = one.Close < one.Open - isDarkCloud = one.Open > two.High && - one.Close < twoMidpoint && one.Close > two.Open + twoMidpoint = (two.Close.Float64() + two.Open.Float64()) / 2 + isFirstBullish = two.Close.Float64() > two.Open.Float64() + isSecondBearish = one.Close.Float64() < one.Open.Float64() + isDarkCloud = one.Open.Float64() > two.High.Float64() && + one.Close.Float64() < twoMidpoint && one.Close.Float64() > two.Open.Float64() ) if isFirstBullish && isSecondBearish && isDarkCloud { diff --git a/pkg/indicator/v2/doji_dragon_fly.go b/pkg/indicator/v2/doji_dragon_fly.go index f0dc717ecd..9f63e81b35 100644 --- a/pkg/indicator/v2/doji_dragon_fly.go +++ b/pkg/indicator/v2/doji_dragon_fly.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) diff --git a/pkg/indicator/v2/doji_long_legged.go b/pkg/indicator/v2/doji_long_legged.go index c05f86a4b6..902be5ff86 100644 --- a/pkg/indicator/v2/doji_long_legged.go +++ b/pkg/indicator/v2/doji_long_legged.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -39,12 +38,12 @@ func DojiLongLegged(source KLineSubscription) *DojiLongLeggedStream { one = source.Last(0) ) // BEAR - if four.Close > four.Open { - if three.Close > three.Open { - if two.Close > two.Open { - if fixedpoint.Abs(one.Close.Sub(one.Open).Div(one.Open)) < threshold { - if fixedpoint.Abs(one.High.Sub(one.Open).Div(one.Open)) > limit { - if fixedpoint.Abs(one.Close.Sub(one.Low).Div(one.Low)) > limit { + if four.Close.Float64() > four.Open.Float64() { + if three.Close.Float64() > three.Open.Float64() { + if two.Close.Float64() > two.Open.Float64() { + if fixedpoint.Abs(one.Close.Sub(one.Open).Div(one.Open)).Float64() < threshold { + if fixedpoint.Abs(one.High.Sub(one.Open).Div(one.Open)).Float64() > limit { + if fixedpoint.Abs(one.Close.Sub(one.Low).Div(one.Low)).Float64() > limit { output = Bear } } @@ -54,12 +53,12 @@ func DojiLongLegged(source KLineSubscription) *DojiLongLeggedStream { } // BULL - if four.Close < four.Open { - if three.Close < three.Open { - if two.Close < two.Open { - if fixedpoint.Abs(one.Open.Sub(one.Close).Div(one.Close)) < threshold { - if fixedpoint.Abs(one.Low.Sub(one.Close).Div(one.Close)) > limit { - if fixedpoint.Abs(one.Open.Sub(one.High).Div(one.High)) > limit { + if four.Close.Float64() < four.Open.Float64() { + if three.Close.Float64() < three.Open.Float64() { + if two.Close.Float64() < two.Open.Float64() { + if fixedpoint.Abs(one.Open.Sub(one.Close).Div(one.Close)).Float64() < threshold { + if fixedpoint.Abs(one.Low.Sub(one.Close).Div(one.Close)).Float64() > limit { + if fixedpoint.Abs(one.Open.Sub(one.High).Div(one.High)).Float64() > limit { output = Bull } } diff --git a/pkg/indicator/v2/doji_star.go b/pkg/indicator/v2/doji_star.go index 90455800a9..7baf1dc9cc 100644 --- a/pkg/indicator/v2/doji_star.go +++ b/pkg/indicator/v2/doji_star.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -33,18 +32,18 @@ func DojiStar(source KLineSubscription, direction Direction, maxDiff float64) *D three = source.Last(2) two = source.Last(1) one = source.Last(0) - firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two) + firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two).Float64() dojiExists = doji.Last(1) == Bull ) if direction == Bullish { var ( - isFirstBearish = three.Close < three.Open - isThirdBullish = one.Close > one.Open - gapExists = two.High < three.Low && - two.Low < three.Low && - one.Open > two.High && - two.Close < one.Open - doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + isFirstBearish = three.Close.Float64() < three.Open.Float64() + isThirdBullish = one.Close.Float64() > one.Open.Float64() + gapExists = two.High.Float64() < three.Low.Float64() && + two.Low.Float64() < three.Low.Float64() && + one.Open.Float64() > two.High.Float64() && + two.Close.Float64() < one.Open.Float64() + doesCloseAboveFirstMidpoint = one.Close.Float64() > firstMidpoint ) if isFirstBearish && dojiExists && isThirdBullish && gapExists && doesCloseAboveFirstMidpoint { @@ -52,13 +51,13 @@ func DojiStar(source KLineSubscription, direction Direction, maxDiff float64) *D } } else { var ( - isFirstBullish = three.Close > three.Open - isThirdBearish = one.Open > one.Close - gapExists = two.High > three.High && - two.Low > three.High && - one.Open < two.Low && - two.Close > one.Open - doesCloseBelowFirstMidpoint = one.Close < firstMidpoint + isFirstBullish = three.Close.Float64() > three.Open.Float64() + isThirdBearish = one.Open.Float64() > one.Close.Float64() + gapExists = two.High.Float64() > three.High.Float64() && + two.Low.Float64() > three.High.Float64() && + one.Open.Float64() < two.Low.Float64() && + two.Close.Float64() > one.Open.Float64() + doesCloseBelowFirstMidpoint = one.Close.Float64() < firstMidpoint ) if isFirstBullish && dojiExists && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { diff --git a/pkg/indicator/v2/donchian_channel.go b/pkg/indicator/v2/donchian_channel.go index 4629102368..54eb46b132 100644 --- a/pkg/indicator/v2/donchian_channel.go +++ b/pkg/indicator/v2/donchian_channel.go @@ -42,7 +42,7 @@ func DonchianChannel(source KLineSubscription, window int) *DonchianChannelStrea } func (s *DonchianChannelStream) Truncate() { - s.UpBand.Slice = s.UpBand.Slice.Truncate(5000) - s.DownBand.Slice = s.DownBand.Slice.Truncate(5000) - s.MiddleBand.Slice = s.MiddleBand.Slice.Truncate(5000) + s.UpBand.Slice = s.UpBand.Slice.Truncate(MaxNumOfMA) + s.DownBand.Slice = s.DownBand.Slice.Truncate(MaxNumOfMA) + s.MiddleBand.Slice = s.MiddleBand.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/downside_tazuki_gap.go b/pkg/indicator/v2/downside_tazuki_gap.go index 1d47b752ff..39d22598ca 100644 --- a/pkg/indicator/v2/downside_tazuki_gap.go +++ b/pkg/indicator/v2/downside_tazuki_gap.go @@ -29,14 +29,14 @@ func TazukiGap(source KLineSubscription) *TazukiGapStream { three = source.Last(2) two = source.Last(1) one = source.Last(0) - isFirstBearish = three.Close < three.Open - isSecondBearish = two.Close < two.Open - isThirdBullish = one.Close > one.Open - isFirstGapExists = two.High < three.Low - isTazukiGap = two.Open > one.Open && - two.Close < one.Open && - one.Close > two.Open && - one.Close < three.Close + isFirstBearish = three.Close.Float64() < three.Open.Float64() + isSecondBearish = two.Close.Float64() < two.Open.Float64() + isThirdBullish = one.Close.Float64() > one.Open.Float64() + isFirstGapExists = two.High.Float64() < three.Low.Float64() + isTazukiGap = two.Open.Float64() > one.Open.Float64() && + two.Close.Float64() < one.Open.Float64() && + one.Close.Float64() > two.Open.Float64() && + one.Close.Float64() < three.Close.Float64() ) if isFirstBearish && isSecondBearish && isThirdBullish && isFirstGapExists && isTazukiGap { diff --git a/pkg/indicator/v2/engulfing.go b/pkg/indicator/v2/engulfing.go index 39ad68b107..b0e81af28b 100644 --- a/pkg/indicator/v2/engulfing.go +++ b/pkg/indicator/v2/engulfing.go @@ -32,18 +32,18 @@ func Engulfing(source KLineSubscription) *EngulfingStream { ) // BEAR - if two.Open < two.Close { - if one.Open > two.Close { - if one.Close < two.Open { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() > two.Close.Float64() { + if one.Close.Float64() < two.Open.Float64() { output = Bear } } } // BULL - if two.Open > two.Close { - if one.Open < two.Close { - if one.Close > two.Open { + if two.Open.Float64() > two.Close.Float64() { + if one.Open.Float64() < two.Close.Float64() { + if one.Close.Float64() > two.Open.Float64() { output = Bull } } diff --git a/pkg/indicator/v2/harami.go b/pkg/indicator/v2/harami.go index 4d90aa82be..af95fd1b05 100644 --- a/pkg/indicator/v2/harami.go +++ b/pkg/indicator/v2/harami.go @@ -35,18 +35,18 @@ func Harami(source KLineSubscription) *HaramiStream { ) // BEAR - if two.Open < two.Close { - if one.Open > one.Close { - if one.Open < two.Close && one.Close > two.Open { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() > one.Close.Float64() { + if one.Open.Float64() < two.Close.Float64() && one.Close.Float64() > two.Open.Float64() { output = Bear } } } // BULL - if two.Open > two.Close { - if one.Open < one.Close { - if one.Open > two.Close && one.Close < two.Open { + if two.Open.Float64() > two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if one.Open.Float64() > two.Close.Float64() && one.Close.Float64() < two.Open.Float64() { output = Bull } } diff --git a/pkg/indicator/v2/harami_cross.go b/pkg/indicator/v2/harami_cross.go index 0ad9560a86..ccbf401d73 100644 --- a/pkg/indicator/v2/harami_cross.go +++ b/pkg/indicator/v2/harami_cross.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -45,21 +44,21 @@ func HaramiCross(source KLineSubscription, direction Direction, maxDiff float64) ) if direction == Bullish { var ( - isBullishHaramiCrossPattern = two.Open > one.Open && - two.Close < one.Open && - two.Close < one.Close && - two.Open > one.Low && - two.High > one.High + isBullishHaramiCrossPattern = two.Open.Float64() > one.Open.Float64() && + two.Close.Float64() < one.Open.Float64() && + two.Close.Float64() < one.Close.Float64() && + two.Open.Float64() > one.Low.Float64() && + two.High.Float64() > one.High.Float64() ) if isBullishHaramiCrossPattern && isLastDoji { output = Bull } } else { - var isBearishHaramiCrossPattern = two.Open < one.Open && - two.Close > one.Open && - two.Close > one.Close && - two.Open < one.Low && - two.High > one.High + var isBearishHaramiCrossPattern = two.Open.Float64() < one.Open.Float64() && + two.Close.Float64() > one.Open.Float64() && + two.Close.Float64() > one.Close.Float64() && + two.Open.Float64() < one.Low.Float64() && + two.High.Float64() > one.High.Float64() if isBearishHaramiCrossPattern && isLastDoji { output = Bear } diff --git a/pkg/indicator/v2/kicking.go b/pkg/indicator/v2/kicking.go index 94b080bf0a..9113d683e7 100644 --- a/pkg/indicator/v2/kicking.go +++ b/pkg/indicator/v2/kicking.go @@ -33,9 +33,9 @@ func Kicking(source KLineSubscription, maxDiff float64) *KickingStream { ) // BEAR - if two.Open < two.Close { - if one.Open > one.Close { - if two.Open > one.Open { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() > one.Close.Float64() { + if two.Open.Float64() > one.Open.Float64() { if fixedpoint.ApproxEqual(two.Open, two.Low, maxDiff) && fixedpoint.ApproxEqual(two.Close, two.High, maxDiff) { if fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) && @@ -48,9 +48,9 @@ func Kicking(source KLineSubscription, maxDiff float64) *KickingStream { } // BULL - if two.Open > two.Close { - if one.Open < one.Close { - if two.Open < one.Open { + if two.Open.Float64() > two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if two.Open.Float64() < one.Open.Float64() { if fixedpoint.ApproxEqual(two.Open, two.High, maxDiff) && fixedpoint.ApproxEqual(two.Close, two.Low, maxDiff) { if fixedpoint.ApproxEqual(one.Open, one.Low, maxDiff) && diff --git a/pkg/indicator/v2/marubozu.go b/pkg/indicator/v2/marubozu.go index de1e4a4e3c..93ad35da6d 100644 --- a/pkg/indicator/v2/marubozu.go +++ b/pkg/indicator/v2/marubozu.go @@ -24,7 +24,7 @@ func Marubozu(source KLineSubscription, maxDiff float64) *MarubozuStream { one = source.Last(0) ) // BEAR - if one.Open > one.Close { + if one.Open.Float64() > one.Close.Float64() { if fixedpoint.ApproxEqual(one.High, one.Open, maxDiff) && fixedpoint.ApproxEqual(one.Low, one.Close, maxDiff) { output = Bear @@ -32,7 +32,7 @@ func Marubozu(source KLineSubscription, maxDiff float64) *MarubozuStream { } // BULL - if one.Open < one.Close { + if one.Open.Float64() < one.Close.Float64() { if fixedpoint.ApproxEqual(one.Low, one.Open, maxDiff) && fixedpoint.ApproxEqual(one.High, one.Close, maxDiff) { output = Bull diff --git a/pkg/indicator/v2/meeting_lines.go b/pkg/indicator/v2/meeting_lines.go index 80a9617f20..7de531ec53 100644 --- a/pkg/indicator/v2/meeting_lines.go +++ b/pkg/indicator/v2/meeting_lines.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -34,10 +33,10 @@ func MeetingLines(source KLineSubscription) *MeetingLinesStream { ) // BEAR - if three.Open < three.Close { - if two.Open < two.Close { - if one.Open > one.Close { - if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if three.Open.Float64() < three.Close.Float64() { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() > one.Close.Float64() { + if fixedpoint.Abs(two.Close.Sub(one.Close).Div(one.Close)).Float64() < threshold { output = Bear } } @@ -45,10 +44,10 @@ func MeetingLines(source KLineSubscription) *MeetingLinesStream { } // BULL - if three.Open > three.Close { - if two.Open > two.Close { - if one.Open < one.Close { - if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if three.Open.Float64() > three.Close.Float64() { + if two.Open.Float64() > two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if fixedpoint.Abs(two.Close.Sub(one.Close).Div(one.Close)).Float64() < threshold { output = Bull } } diff --git a/pkg/indicator/v2/morning_evening_star.go b/pkg/indicator/v2/morning_evening_star.go index de58b2a689..723b2598f1 100644 --- a/pkg/indicator/v2/morning_evening_star.go +++ b/pkg/indicator/v2/morning_evening_star.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -36,34 +35,34 @@ func MorningOrEveningStar(source KLineSubscription, direction Direction) *Mornin three = source.Last(2) two = source.Last(1) one = source.Last(0) - firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two) + firstMidpoint = three.Open.Add(three.Close).Div(fixedpoint.Two).Float64() ) if direction == Bullish { var ( - isFirstBearish = three.Close < three.Open - hasSmallBody = three.Low > two.Low && - three.Low > two.High - isThirdBullish = one.Open < one.Close - gapExists = two.High < three.Low && - two.Low < three.Low && - one.Open > two.High && - two.Close < one.Open - doesCloseAboveFirstMidpoint = one.Close > firstMidpoint + isFirstBearish = three.Close.Float64() < three.Open.Float64() + hasSmallBody = three.Low.Float64() > two.Low.Float64() && + three.Low.Float64() > two.High.Float64() + isThirdBullish = one.Open.Float64() < one.Close.Float64() + gapExists = two.High.Float64() < three.Low.Float64() && + two.Low.Float64() < three.Low.Float64() && + one.Open.Float64() > two.High.Float64() && + two.Close.Float64() < one.Open.Float64() + doesCloseAboveFirstMidpoint = one.Close.Float64() > firstMidpoint ) if isFirstBearish && hasSmallBody && gapExists && isThirdBullish && doesCloseAboveFirstMidpoint { output = Bull // morning star } } else { var ( - isFirstBullish = three.Close > three.Open - hasSmallBody = three.High < two.Low && - three.High < two.High - isThirdBearish = one.Open > one.Close - gapExists = two.High > three.High && - two.Low > three.High && - one.Open < two.Low && - two.Close > one.Open - doesCloseBelowFirstMidpoint = one.Close < firstMidpoint + isFirstBullish = three.Close.Float64() > three.Open.Float64() + hasSmallBody = three.High.Float64() < two.Low.Float64() && + three.High.Float64() < two.High.Float64() + isThirdBearish = one.Open.Float64() > one.Close.Float64() + gapExists = two.High.Float64() > three.High.Float64() && + two.Low.Float64() > three.High.Float64() && + one.Open.Float64() < two.Low.Float64() && + two.Close.Float64() > one.Open.Float64() + doesCloseBelowFirstMidpoint = one.Close.Float64() < firstMidpoint ) if isFirstBullish && hasSmallBody && gapExists && isThirdBearish && doesCloseBelowFirstMidpoint { output = Bear // evening star diff --git a/pkg/indicator/v2/negative_volume_index.go b/pkg/indicator/v2/negative_volume_index.go index 62529679d8..e6f4a5de8c 100644 --- a/pkg/indicator/v2/negative_volume_index.go +++ b/pkg/indicator/v2/negative_volume_index.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -51,5 +50,5 @@ func NegativeVolumeIndex(source KLineSubscription) *NVIStream { } func (s *NVIStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/obv.go b/pkg/indicator/v2/obv.go index 9010e02852..6f10c58922 100644 --- a/pkg/indicator/v2/obv.go +++ b/pkg/indicator/v2/obv.go @@ -22,9 +22,9 @@ func OBV(source KLineSubscription) *OBVStream { prev := source.Last(1) obv = s.Slice.Last(0) - if v.Close > prev.Close { + if v.Close.Float64() > prev.Close.Float64() { obv += v.Volume.Float64() - } else if v.Close < prev.Close { + } else if v.Close.Float64() < prev.Close.Float64() { obv -= v.Volume.Float64() } } @@ -36,5 +36,5 @@ func OBV(source KLineSubscription) *OBVStream { } func (s *OBVStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/pattern.go b/pkg/indicator/v2/pattern.go index 0a91e34552..f4e98dc3f2 100644 --- a/pkg/indicator/v2/pattern.go +++ b/pkg/indicator/v2/pattern.go @@ -13,10 +13,10 @@ const ( var ( Neutral = .0 - Bull = 1.0 - Bear = -1.0 - threshold = fixedpoint.NewFromFloat(0.1) - limit = fixedpoint.NewFromFloat(0.2) + Bull = 1. + Bear = -1. + threshold = .1 + limit = .2 ) func n(n float64) fixedpoint.Value { diff --git a/pkg/indicator/v2/piercing_line.go b/pkg/indicator/v2/piercing_line.go index af58e2c5d3..5f618f8fca 100644 --- a/pkg/indicator/v2/piercing_line.go +++ b/pkg/indicator/v2/piercing_line.go @@ -1,6 +1,7 @@ package indicatorv2 import ( + "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) @@ -28,12 +29,12 @@ func PiercingLine(source KLineSubscription) *PiercingLineStream { var ( two = source.Last(1) one = source.Last(0) - firstMidpoint = (two.Open + two.Close) / 2 - isDowntrend = one.Low < two.Low - isFirstBearish = two.Close < two.Open - isSecondBullish = one.Close > one.Open - isPiercingLine = two.Low > one.Open && - one.Close > firstMidpoint + firstMidpoint = two.Open.Add(two.Close).Div(fixedpoint.Two).Float64() + isDowntrend = one.Low.Float64() < two.Low.Float64() + isFirstBearish = two.Close.Float64() < two.Open.Float64() + isSecondBullish = one.Close.Float64() > one.Open.Float64() + isPiercingLine = two.Low.Float64() > one.Open.Float64() && + one.Close.Float64() > firstMidpoint ) if isDowntrend && isFirstBearish && isSecondBullish && isPiercingLine { output = Bull diff --git a/pkg/indicator/v2/separating_lines.go b/pkg/indicator/v2/separating_lines.go index 88ae8ddd15..eb027e7fa4 100644 --- a/pkg/indicator/v2/separating_lines.go +++ b/pkg/indicator/v2/separating_lines.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -34,10 +33,10 @@ func SeparatingLines(source KLineSubscription, maxDiff float64) *SeparatingLines one = source.Last(0) ) // BEAR - if three.Open > three.Close { - if two.Open < two.Close { - if one.Open > one.Close { - if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if three.Open.Float64() > three.Close.Float64() { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() > one.Close.Float64() { + if fixedpoint.Abs(two.Open.Sub(one.Open).Div(one.Open)).Float64() < threshold { if fixedpoint.ApproxEqual(one.Open, one.High, maxDiff) { output = Bear } @@ -47,10 +46,10 @@ func SeparatingLines(source KLineSubscription, maxDiff float64) *SeparatingLines } // BULL - if three.Open < three.Close { - if two.Open > two.Close { - if one.Open < one.Close { - if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { + if three.Open.Float64() < three.Close.Float64() { + if two.Open.Float64() > two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if fixedpoint.Abs(two.Open.Sub(one.Open).Div(one.Open)).Float64() < threshold { if fixedpoint.ApproxEqual(one.Open, one.Low, maxDiff) { output = Bull } diff --git a/pkg/indicator/v2/side_by_side_whitelines.go b/pkg/indicator/v2/side_by_side_whitelines.go index a91faf3876..cc8e57b12c 100644 --- a/pkg/indicator/v2/side_by_side_whitelines.go +++ b/pkg/indicator/v2/side_by_side_whitelines.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -35,13 +34,13 @@ func SideBySideWhiteLines(source KLineSubscription, maxDiff float64) *SideBySide ) // BEAR - if four.Open > four.Close { - if three.Open > three.Close { - if three.Low > two.High { - if two.Open < two.Close { - if one.Open < one.Close { - if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { - if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if four.Open.Float64() > four.Close.Float64() { + if three.Open.Float64() > three.Close.Float64() { + if three.Low.Float64() > two.High.Float64() { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if fixedpoint.Abs(two.Open.Sub(one.Open).Div(one.Open)).Float64() < threshold { + if fixedpoint.Abs(two.Close.Sub(one.Close).Div(one.Close)).Float64() < threshold { if fixedpoint.ApproxEqual(two.Open, one.Open, maxDiff) { output = Bear } @@ -54,13 +53,13 @@ func SideBySideWhiteLines(source KLineSubscription, maxDiff float64) *SideBySide } // BULL - if four.Open < four.Close { - if three.Open < three.Close { - if three.Low < two.High { - if two.Open < two.Close { - if one.Open < one.Close { - if fixedpoint.Abs((two.Open-one.Open)/one.Open) < threshold { - if fixedpoint.Abs((two.Close-one.Close)/one.Close) < threshold { + if four.Open.Float64() < four.Close.Float64() { + if three.Open.Float64() < three.Close.Float64() { + if three.Low.Float64() < two.High.Float64() { + if two.Open.Float64() < two.Close.Float64() { + if one.Open.Float64() < one.Close.Float64() { + if fixedpoint.Abs(two.Open.Sub(one.Open).Div(one.Open)).Float64() < threshold { + if fixedpoint.Abs(two.Close.Sub(one.Close).Div(one.Close)).Float64() < threshold { if fixedpoint.ApproxEqual(two.Open, one.Open, maxDiff) { output = Bull } diff --git a/pkg/indicator/v2/spinning_top.go b/pkg/indicator/v2/spinning_top.go index 6399879771..78f84eab26 100644 --- a/pkg/indicator/v2/spinning_top.go +++ b/pkg/indicator/v2/spinning_top.go @@ -2,7 +2,6 @@ package indicatorv2 import ( "github.com/c9s/bbgo/pkg/fixedpoint" - "github.com/c9s/bbgo/pkg/types" ) @@ -28,10 +27,10 @@ func SpinningTop(source KLineSubscription, direction Direction) *SpinningTopStre ) if direction == Bullish { var ( - upperShadowLength = fixedpoint.Abs(one.High - one.Close) - lowerShadowLength = fixedpoint.Abs(one.Open - one.Low) - isSpinningTop = bodyLength < upperShadowLength && - bodyLength < lowerShadowLength + upperShadowLength = fixedpoint.Abs(one.High - one.Close).Float64() + lowerShadowLength = fixedpoint.Abs(one.Open - one.Low).Float64() + isSpinningTop = bodyLength.Float64() < upperShadowLength && + bodyLength.Float64() < lowerShadowLength ) if isSpinningTop { @@ -39,10 +38,10 @@ func SpinningTop(source KLineSubscription, direction Direction) *SpinningTopStre } } else { var ( - upperShadowLength = fixedpoint.Abs(one.High - one.Open) - lowerShadowLength = fixedpoint.Abs(one.High - one.Low) - isBearishSpinningTop = bodyLength < upperShadowLength && - bodyLength < lowerShadowLength + upperShadowLength = fixedpoint.Abs(one.High - one.Open).Float64() + lowerShadowLength = fixedpoint.Abs(one.High - one.Low).Float64() + isBearishSpinningTop = bodyLength.Float64() < upperShadowLength && + bodyLength.Float64() < lowerShadowLength ) if isBearishSpinningTop { output = Bear diff --git a/pkg/indicator/v2/three_crows.go b/pkg/indicator/v2/three_crows.go index b519adf7bd..f3c69d4afc 100644 --- a/pkg/indicator/v2/three_crows.go +++ b/pkg/indicator/v2/three_crows.go @@ -33,16 +33,18 @@ func ThreeCrows(source KLineSubscription) *ThreeCrowsStream { } var ( - three = source.Last(2) - two = source.Last(1) - one = source.Last(0) - isDownTrend = three.Low > two.Low && two.Low > one.Low - isAllBearish = three.Open > three.Close && - two.Open > two.Close && one.Open > one.Close - opensWithinPreviousBody = three.Open > two.Open && - two.Open > three.Close && - two.Open > one.Open && - one.Open > two.Close + three = source.Last(2) + two = source.Last(1) + one = source.Last(0) + isDownTrend = three.Low.Float64() > two.Low.Float64() && + two.Low.Float64() > one.Low.Float64() + isAllBearish = three.Open.Float64() > three.Close.Float64() && + two.Open.Float64() > two.Close.Float64() && + one.Open.Float64() > one.Close.Float64() + opensWithinPreviousBody = three.Open.Float64() > two.Open.Float64() && + two.Open.Float64() > three.Close.Float64() && + two.Open.Float64() > one.Open.Float64() && + one.Open.Float64() > two.Close.Float64() ) if isDownTrend && isAllBearish && opensWithinPreviousBody { diff --git a/pkg/indicator/v2/three_line_strike.go b/pkg/indicator/v2/three_line_strike.go index 138f7e15ae..89e7925e58 100644 --- a/pkg/indicator/v2/three_line_strike.go +++ b/pkg/indicator/v2/three_line_strike.go @@ -33,39 +33,39 @@ func ThreeLineStrike(source KLineSubscription) *ThreeLineStrikeStream { one = source.Last(0) ) // BEAR - if three.Close < four.Close { - if two.Close < three.Close { - if four.Close < three.Open && three.Open < four.Open { - if three.Close < two.Open && two.Open < three.Open { - if one.Open < two.Close { - if one.Close > four.Open { + if three.Close.Float64() < four.Close.Float64() { + if two.Close.Float64() < three.Close.Float64() { + if four.Close.Float64() < three.Open.Float64() && + three.Open.Float64() < four.Open.Float64() { + if three.Close.Float64() < two.Open.Float64() && + two.Open.Float64() < three.Open.Float64() { + if one.Open.Float64() < two.Close.Float64() { + if one.Close.Float64() > four.Open.Float64() { output = Bear } } } } - } } - // BULL - if three.Close > four.Close { - if two.Close > three.Close { - if four.Close > three.Open && three.Open > four.Open { - if three.Close > two.Open && two.Open > three.Open { - if one.Open > two.Close { - if one.Close < four.Open { + if three.Close.Float64() > four.Close.Float64() { + if two.Close.Float64() > three.Close.Float64() { + if four.Close.Float64() > three.Open.Float64() && + three.Open.Float64() > four.Open.Float64() { + if three.Close.Float64() > two.Open.Float64() && + two.Open.Float64() > three.Open.Float64() { + if one.Open.Float64() > two.Close.Float64() { + if one.Close.Float64() < four.Open.Float64() { output = Bull } } } } - } } s.PushAndEmit(output) - }) return s diff --git a/pkg/indicator/v2/three_white_soldiers.go b/pkg/indicator/v2/three_white_soldiers.go index 197aa2f156..2321992990 100644 --- a/pkg/indicator/v2/three_white_soldiers.go +++ b/pkg/indicator/v2/three_white_soldiers.go @@ -29,15 +29,15 @@ func ThreeWhiteSoldiers(source KLineSubscription) *ThreeWhiteSoldiersStream { three = source.Last(2) two = source.Last(1) one = source.Last(0) - isUpTrend = two.High > three.High && - one.High > two.High - isAllBullish = three.Open < three.Close && - two.Open < two.Close && - one.Open < one.Close - doesOpenWithinPreviousBody = three.Close > two.Open && - two.Open < three.High && - two.High > one.Open && - one.Open < two.Close + isUpTrend = two.High.Float64() > three.High.Float64() && + one.High.Float64() > two.High.Float64() + isAllBullish = three.Open.Float64() < three.Close.Float64() && + two.Open.Float64() < two.Close.Float64() && + one.Open.Float64() < one.Close.Float64() + doesOpenWithinPreviousBody = three.Close.Float64() > two.Open.Float64() && + two.Open.Float64() < three.High.Float64() && + two.High.Float64() > one.Open.Float64() && + one.Open.Float64() < two.Close.Float64() ) if isUpTrend && isAllBullish && doesOpenWithinPreviousBody { diff --git a/pkg/indicator/v2/ulcer_index.go b/pkg/indicator/v2/ulcer_index.go index 2475d53ef5..97e3089738 100644 --- a/pkg/indicator/v2/ulcer_index.go +++ b/pkg/indicator/v2/ulcer_index.go @@ -42,5 +42,5 @@ func (s *UlcerIndexStream) Calculate(_ float64) float64 { } func (s *UlcerIndexStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/vwap.go b/pkg/indicator/v2/vwap.go index d48a4142f7..7cc8fea59c 100644 --- a/pkg/indicator/v2/vwap.go +++ b/pkg/indicator/v2/vwap.go @@ -37,5 +37,5 @@ func VwapDefault(source KLineSubscription) *VWAPStream { } func (s *VWAPStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } diff --git a/pkg/indicator/v2/williams_r.go b/pkg/indicator/v2/williams_r.go index f25c6c3aba..082c804d3b 100644 --- a/pkg/indicator/v2/williams_r.go +++ b/pkg/indicator/v2/williams_r.go @@ -50,5 +50,5 @@ func WilliamsR(source KLineSubscription, window int) *WilliamsRStream { } func (s *WilliamsRStream) Truncate() { - s.Slice = s.Slice.Truncate(5000) + s.Slice = s.Slice.Truncate(MaxNumOfMA) } From f63fd8fe8409621758dc0eda154bd1343ae6ed8d Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 6 Nov 2023 23:26:42 +0100 Subject: [PATCH 16/17] rename to BOLL --- pkg/bbgo/indicator_set.go | 4 ++-- pkg/indicator/v2/bollinger_band.go | 12 ++++++------ pkg/indicator/v2/bollinger_band_test.go | 2 +- pkg/strategy/bollmaker/dynamic_spread.go | 6 +++--- pkg/strategy/bollmaker/strategy.go | 4 ++-- pkg/strategy/bollmaker/trend.go | 2 +- pkg/strategy/scmaker/strategy.go | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/bbgo/indicator_set.go b/pkg/bbgo/indicator_set.go index 5a608af7cd..eb15722128 100644 --- a/pkg/bbgo/indicator_set.go +++ b/pkg/bbgo/indicator_set.go @@ -89,8 +89,8 @@ func (i *IndicatorSet) STOCH(iw types.IntervalWindow, dPeriod int) *indicatorv2. return indicatorv2.Stoch(i.KLines(iw.Interval), iw.Window, dPeriod) } -func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BollingerStream { - return indicatorv2.BollingerBand(i.CLOSE(iw.Interval), iw.Window, k) +func (i *IndicatorSet) BOLL(iw types.IntervalWindow, k float64) *indicatorv2.BOLLStream { + return indicatorv2.BOLL(i.CLOSE(iw.Interval), iw.Window, k) } func (i *IndicatorSet) MACD(interval types.Interval, shortWindow, longWindow, signalWindow int) *indicatorv2.MACDStream { diff --git a/pkg/indicator/v2/bollinger_band.go b/pkg/indicator/v2/bollinger_band.go index 68ec80a4e3..53337aa831 100644 --- a/pkg/indicator/v2/bollinger_band.go +++ b/pkg/indicator/v2/bollinger_band.go @@ -4,7 +4,7 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -type BollingerStream struct { +type BOLLStream struct { // the band series *types.Float64Series @@ -16,19 +16,19 @@ type BollingerStream struct { StdDev *StdDevStream } -// BOOL2 is bollinger indicator +// BOLL2 is bollinger indicator // the data flow: // // priceSource -> // // -> calculate SMA // -> calculate stdDev -> calculate bandWidth -> get latest SMA -> upBand, downBand -func BollingerBand(source types.Float64Source, window int, k float64) *BollingerStream { +func BOLL(source types.Float64Source, window int, k float64) *BOLLStream { // bind these indicators before our main calculator sma := SMA(source, window) stdDev := StdDev(source, window) - s := &BollingerStream{ + s := &BOLLStream{ Float64Series: types.NewFloat64Series(), UpBand: types.NewFloat64Series(), DownBand: types.NewFloat64Series(), @@ -47,13 +47,13 @@ func BollingerBand(source types.Float64Source, window int, k float64) *Bollinger return s } -func (s *BollingerStream) Calculate(v float64) float64 { +func (s *BOLLStream) Calculate(v float64) float64 { stdDev := s.StdDev.Last(0) band := stdDev * s.k return band } -func (s *BollingerStream) Truncate() { +func (s *BOLLStream) Truncate() { s.UpBand.Slice = s.UpBand.Slice.Truncate(5000) s.DownBand.Slice = s.DownBand.Slice.Truncate(5000) } diff --git a/pkg/indicator/v2/bollinger_band_test.go b/pkg/indicator/v2/bollinger_band_test.go index 6d8de18060..b17ed9d527 100644 --- a/pkg/indicator/v2/bollinger_band_test.go +++ b/pkg/indicator/v2/bollinger_band_test.go @@ -100,7 +100,7 @@ func TestBollingerBand(t *testing.T) { sigma := 2.0 source := types.NewFloat64Series() - ind := BollingerBand(source, window, sigma) + ind := BOLL(source, window, sigma) for _, d := range ts { source.PushAndEmit(d) diff --git a/pkg/strategy/bollmaker/dynamic_spread.go b/pkg/strategy/bollmaker/dynamic_spread.go index 0f9ceb0f3d..f236c34eaa 100644 --- a/pkg/strategy/bollmaker/dynamic_spread.go +++ b/pkg/strategy/bollmaker/dynamic_spread.go @@ -29,7 +29,7 @@ type DynamicSpreadSettings struct { } // Initialize dynamic spreads and preload SMAs -func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *indicatorv2.BollingerStream) { +func (ds *DynamicSpreadSettings) Initialize(symbol string, session *bbgo.ExchangeSession, neutralBoll, defaultBoll *indicatorv2.BOLLStream) { switch { case ds.AmpSpreadSettings != nil: ds.AmpSpreadSettings.initialize(symbol, session) @@ -165,10 +165,10 @@ type DynamicSpreadBollWidthRatioSettings struct { // A positive number. The greater factor, the sharper weighting function. Default set to 1.0 . Sensitivity float64 `json:"sensitivity"` - defaultBoll, neutralBoll *indicatorv2.BollingerStream + defaultBoll, neutralBoll *indicatorv2.BOLLStream } -func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *indicatorv2.BollingerStream) { +func (ds *DynamicSpreadBollWidthRatioSettings) initialize(neutralBoll, defaultBoll *indicatorv2.BOLLStream) { ds.neutralBoll = neutralBoll ds.defaultBoll = defaultBoll if ds.Sensitivity <= 0. { diff --git a/pkg/strategy/bollmaker/strategy.go b/pkg/strategy/bollmaker/strategy.go index 6ffc3c6b85..6dcbf5ab14 100644 --- a/pkg/strategy/bollmaker/strategy.go +++ b/pkg/strategy/bollmaker/strategy.go @@ -157,10 +157,10 @@ type Strategy struct { groupID uint32 // defaultBoll is the BOLLINGER indicator we used for predicting the price. - defaultBoll *indicatorv2.BollingerStream + defaultBoll *indicatorv2.BOLLStream // neutralBoll is the neutral price section - neutralBoll *indicatorv2.BollingerStream + neutralBoll *indicatorv2.BOLLStream // StrategyController bbgo.StrategyController diff --git a/pkg/strategy/bollmaker/trend.go b/pkg/strategy/bollmaker/trend.go index 150fedd9b2..a3faac0b10 100644 --- a/pkg/strategy/bollmaker/trend.go +++ b/pkg/strategy/bollmaker/trend.go @@ -11,7 +11,7 @@ const ( UnknownTrend PriceTrend = "unknown" ) -func detectPriceTrend(inc *indicatorv2.BollingerStream, price float64) PriceTrend { +func detectPriceTrend(inc *indicatorv2.BOLLStream, price float64) PriceTrend { if inBetween(price, inc.DownBand.Last(0), inc.UpBand.Last(0)) { return NeutralTrend } diff --git a/pkg/strategy/scmaker/strategy.go b/pkg/strategy/scmaker/strategy.go index 4165fe549f..2dbbab2ea2 100644 --- a/pkg/strategy/scmaker/strategy.go +++ b/pkg/strategy/scmaker/strategy.go @@ -75,7 +75,7 @@ type Strategy struct { // indicators ewma *indicatorv2.EWMAStream - boll *indicatorv2.BollingerStream + boll *indicatorv2.BOLLStream intensity *IntensityStream positionRiskControl *riskcontrol.PositionRiskControl @@ -201,7 +201,7 @@ func (s *Strategy) initializeIntensityIndicator(session *bbgo.ExchangeSession) { func (s *Strategy) initializePriceRangeBollinger(session *bbgo.ExchangeSession) { kLines := indicatorv2.KLines(session.MarketDataStream, s.Symbol, s.PriceRangeBollinger.Interval) closePrices := indicatorv2.ClosePrices(kLines) - s.boll = indicatorv2.BollingerBand(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) + s.boll = indicatorv2.BOLL(closePrices, s.PriceRangeBollinger.Window, s.PriceRangeBollinger.K) s.preloadKLines(kLines, session, s.Symbol, s.PriceRangeBollinger.Interval) } From cfd54409b5e113ae922c607eb4c7e72855f978f3 Mon Sep 17 00:00:00 2001 From: Sven Woldt Date: Mon, 6 Nov 2023 23:28:41 +0100 Subject: [PATCH 17/17] bump go compiler to 1.20 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 91eca5f8be..a5de5e7e4d 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/c9s/bbgo -go 1.18 +go 1.20 require ( github.com/DATA-DOG/go-sqlmock v1.5.0