Angular Google Charts копирует отдельные серии данных в отдельные массивы - PullRequest
0 голосов
/ 29 января 2020

У меня есть следующий график:

enter image description here

Он состоит из трех серий: свечного графика, точечного графика для ордеров на покупку и другого точечного графика для ордеров на продажу.

enter image description here

Если вы посмотрите на изображение выше или мой код ниже, я заполняю свечную диаграмму и диаграммы разброса одновременно время в том же массиве. Первые 5 аргументов this.chartData.push относятся к свечному графику, а два других числа (0,0174 и 0,0173) относятся к точечным графикам. То, что я хочу сделать, - это сначала загрузить данные свечей, как я делаю сейчас, и всякий раз, когда он завершает тестирование на истории (занимает около 20 секунд), а затем получает ордера от бэкенда, он должен добавить данные диаграммы рассеяния после этого. Другими словами, я хочу разделить эти аргументы на 3 массива или, по крайней мере, добавить информацию о заказе отдельно, потому что заказы - это трудоемкая операция, а отображение свечей - это не так.

Что-то в этом роде:

for (let i = 0; i < candlesticks.length; i++) {
    // get all orders with candlesticks[i].openTime

    this.chartData.push([
    null,
    candlesticks[i].low,
    candlesticks[i].open,
    candlesticks[i].close,
    candlesticks[i].high,
    this.customTooltip(candlesticks[i])
    ]);
}

...

this.orders$ = this.backtestingService.performTest();
this.orders$
    .pipe(takeUntil(this.componentDestroyed$))
    .subscribe(orders => {
        this.chartData.push(orders);        
    });

Мой код:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { KlineInterval } from 'src/app/core/types/bot';
import { DatePipe } from '@angular/common';
import { BinanceKline } from 'src/app/core/types/binance';
import { BinanceService } from 'src/app/core/services/binance.service';
import { BacktestingService } from 'src/app/core/services/backtesting.service';
import { Order } from 'src/app/core/types/order';

@Component({
  selector: 'app-backtesting',
  templateUrl: './backtesting.component.html',
  styleUrls: ['./backtesting.component.css']
})
export class BacktestingComponent implements OnInit, OnDestroy {
  binances$: Observable<BinanceKline[]>;
  orders$: Observable<Order[]>;

  private componentDestroyed$ = new Subject<boolean>();

  // Angular Google Charts
  chartDrawn = false;
  chartData = [];
  chartOptions = {
    tooltip: { isHtml: true },
    title: 'Backtesting',
    height: 500,
    chartArea: { width: '80%', height: '80%' },
    legend: { position: 'right', textStyle: { color: 'black', fontSize: 16 } },
    seriesType: 'candlesticks',
    series: {
      1: { type: 'scatter', color: 'green' },
      2: { type: 'scatter', color: 'red' }
    }
  };
  chartColumnNames = [
    'Label', 'Low', 'Open', 'Close', 'High',
    { type: 'string', role: 'tooltip', p: { html: true } },
    { label: 'Buy', type: 'number' },
    { label: 'Sell', type: 'number' }
  ];

  constructor(
    private binanceService: BinanceService,
    private backtestingService: BacktestingService) { }

  ngOnInit() {
    this.getAllKlines();
  }

  ngOnDestroy() {
    this.componentDestroyed$.next(true);
    this.componentDestroyed$.complete();
  }

  private customTooltip(candlestick: BinanceKline): string {
    let pipe = new DatePipe('en-US');
    let openTime = pipe.transform(candlestick.openTime, 'HH:mm');
    let closeTime = pipe.transform(candlestick.closeTime, 'HH:mm');

    return `<div style="font-size: 14px; white-space: nowrap; padding: 10px;">
    <b>Open Time:</b> ${openTime}<br /><b>Close Time:</b> ${closeTime}<br />
    <b>Open:</b> ${candlestick.open}<br /><b>Close:</b> ${candlestick.close}<br />
    <b>High:</b> ${candlestick.high}<br /><b>Low:</b> ${candlestick.low}<br />
    <b>VOL:</b> ${candlestick.volume}
    </div>`;
  }

  private getAllKlines() {
    this.orders$ = this.backtestingService.performTest();
    this.orders$
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe(orders => {
        console.log(orders);
      });

    this.binances$ = this.binanceService.getAllKlines("TRXUSDT", KlineInterval.OneHour);

    this.chartDrawn = false;
    this.chartData = [];

    this.binances$
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe(candlesticks => {
        for (let i = 0; i < candlesticks.length; i++) {
          // get all orders with candlesticks[i].openTime

          this.chartData.push([
            null,
            candlesticks[i].low,
            candlesticks[i].open,
            candlesticks[i].close,
            candlesticks[i].high,
            this.customTooltip(candlesticks[i]),
            0.0174,
            0.0173
          ]);
        }

        this.chartDrawn = true;
      });
  }
}
<section id="backtesting">
  <div class="container">
    <div class="row">

      <ng-container *ngIf="chartDrawn">
        <div class="col-lg-12">
          <google-chart class="mb-1" type="ComboChart" [data]="chartData" [options]="chartOptions"
            [columnNames]="chartColumnNames">
          </google-chart>
        </div>
      </ng-container>

    </div>
  </div>
</section>

backtesting.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';

import { Order } from '../types/order';

@Injectable({
  providedIn: 'root'
})
export class BacktestingService {
  private actionUrl: string;

  constructor(private httpClient: HttpClient) {
    this.actionUrl = `${environment.baseUrls.server}api/backtesting`;
  }

  performTest() {
    return this.httpClient.get<Order[]>(`${this.actionUrl}`);
  }
}

Order.cs

using Binance.Net.Objects;
using System;
using System.ComponentModel.DataAnnotations.Schema;

namespace Binance.Entity
{
    public class Order
    {
        public int Id { get; set; }
        public OrderSide OrderSide { get; set; }
        public OrderType OrderType { get; set; }
        public DateTime PlacedAt { get; set; }
        public DateTime OpenTime { get; set; }

        [Column(TypeName = "decimal(10,1)")]
        public decimal Quantity { get; set; }

        [Column(TypeName = "decimal(10,10)")]
        public decimal Price { get; set; }

        public int BotId { get; set; }
        public Bot Bot { get; set; }
    }
}

BinanceKlineDto. CS

using CryptoExchange.Net.Converters;
using Newtonsoft.Json;
using System;

namespace Binance.Dtos
{
    public class BinanceKlineDto
    {
        [JsonConverter(typeof(TimestampConverter))]
        public DateTime OpenTime { get; set; }

        public decimal Open { get; set; }

        public decimal High { get; set; }

        public decimal Low { get; set; }

        public decimal Close { get; set; }

        public decimal Volume { get; set; }

        [JsonConverter(typeof(TimestampConverter))]
        public DateTime CloseTime { get; set; }
    }
}
...