diff --git a/Client/src/app/app.component.html b/Client/src/app/app.component.html index da924efd..d8b208de 100644 --- a/Client/src/app/app.component.html +++ b/Client/src/app/app.component.html @@ -12,10 +12,11 @@

This is a demo of the Skender.Stock.Indicators .NET library. - It generates stock indicators in the server-side API, then adds it to the chart. + It generates stock indicators in a server-side API, then adds it to the chart.

+ @@ -33,14 +34,13 @@ -
Relative Strength Index
+
Relative Strength Index - {{ chartRsiLabel }}
-
Stochastic Oscillator -
+
Stochastic Oscillator - {{ chartStochLabel }}
@@ -69,7 +69,7 @@ cancel - add @@ -80,12 +80,11 @@ -
+
-

Pick and indicator type:

@@ -292,4 +291,4 @@
-
\ No newline at end of file +
diff --git a/Client/src/app/app.component.scss b/Client/src/app/app.component.scss index 06d8ba0b..0d8d29a8 100644 --- a/Client/src/app/app.component.scss +++ b/Client/src/app/app.component.scss @@ -13,13 +13,14 @@ .page-container { margin: 16px; + padding-bottom: 16px; } .container { position: relative; margin: auto; max-width: 950px; - text-align:center; + text-align: center; } .chart-label { diff --git a/Client/src/app/app.component.ts b/Client/src/app/app.component.ts index 2f08bae1..b4e2a014 100644 --- a/Client/src/app/app.component.ts +++ b/Client/src/app/app.component.ts @@ -55,6 +55,9 @@ export class AppComponent implements OnInit { chartStochLabel: string; chartStochOn = true; // required ON due to card, likely? + @ViewChild('chartsTop') chartRef: ElementRef; + @ViewChild('picker') pickerRef: ElementRef; + history: Quote[] = []; legend: Indicator[] = []; @@ -97,19 +100,16 @@ export class AppComponent implements OnInit { { label: 'STOCH(20,5)', lookbackPeriod: 20, signalPeriod: 5 }, ]; - constructor( private readonly http: HttpClient, private readonly cs: ChartService ) { } - ngOnInit() { this.cancelAdd(); this.getHistory(); } - getHistory() { this.http.get(`${env.api}/history`, this.requestHeader()) @@ -124,7 +124,6 @@ export class AppComponent implements OnInit { }, (error: HttpErrorResponse) => { console.log(error); }); } - addBaseOverlayChart() { const myChart: HTMLCanvasElement = this.chartOverlayRef.nativeElement as HTMLCanvasElement; @@ -187,10 +186,9 @@ export class AppComponent implements OnInit { // add initial samples this.addIndicatorEMA({ parameterOne: 18, color: 'darkOrange' }); - this.addIndicatorEMA({ parameterOne: 150, color: 'darkGreen' }); + this.addIndicatorEMA({ parameterOne: 150, color: 'blue' }); } - addBaseRsiChart() { // construct chart @@ -327,6 +325,16 @@ export class AppComponent implements OnInit { // EDIT INDICATORS + startAdd() { + this.pickIndicator = true; + + // hide oscillators + this.chartRsiOn = false; + this.chartStochOn = false; + + this.scrollToBottomOfPicker(); + } + cancelAdd() { this.pickIndicator = false; @@ -338,20 +346,35 @@ export class AppComponent implements OnInit { parameterThree: undefined, color: undefined }; + + this.showOscillators(); } + showOscillators() { + this.legend + .filter(g => g.chart === 'rsi' || g.chart === 'stoch') + .forEach((i: Indicator) => { + if (i.chart === 'rsi') this.chartRsiOn = true; + if (i.chart === 'stoch') this.chartStochOn = true; + }); + } pickType(t: IndicatorType) { + this.pickedType = t; if (this.pickedType.code === 'BB') this.pickedParams.color = 'darkGray'; if (this.pickedType.code === 'PSAR') this.pickedParams.color = 'purple'; if (this.pickedType.code === 'RSI') this.pickedParams.color = 'black'; if (this.pickedType.code === 'STOCH') this.pickedParams.color = 'black'; + + this.scrollToBottomOfPicker(); } addIndicator() { + this.showOscillators(); + // sorted alphabetically // bollinger bands @@ -393,6 +416,8 @@ export class AppComponent implements OnInit { addIndicatorBB(params: IndicatorParameters) { + this.scrollToChartTop(); + // remove old to clear chart this.legend.filter(x => x.label.startsWith('BB')).forEach(x => { this.deleteIndicator(x); @@ -467,9 +492,10 @@ export class AppComponent implements OnInit { }, (error: HttpErrorResponse) => { console.log(error); }); } - addIndicatorEMA(params: IndicatorParameters) { + this.scrollToChartTop(); + this.http.get(`${env.api}/EMA/${params.parameterOne}`, this.requestHeader()) .subscribe((ema: EmaResult[]) => { @@ -505,7 +531,6 @@ export class AppComponent implements OnInit { }, (error: HttpErrorResponse) => { console.log(error); }); } - psarChange(event: MatRadioChange) { const psar: ParabolicSarConfig = event.value; this.pickedParams.parameterOne = psar.accelerationStep; @@ -514,6 +539,8 @@ export class AppComponent implements OnInit { addIndicatorPSAR(params: IndicatorParameters) { + this.scrollToChartTop(); + // remove old to clear chart this.legend.filter(x => x.label.startsWith('PSAR')).forEach(x => { this.deleteIndicator(x); @@ -555,7 +582,6 @@ export class AppComponent implements OnInit { }, (error: HttpErrorResponse) => { console.log(error); }); } - rsiChange(event: MatRadioChange) { const rsi: RsiConfig = event.value; this.pickedParams.parameterOne = rsi.lookbackPeriod; @@ -563,6 +589,12 @@ export class AppComponent implements OnInit { addIndicatorRSI(params: IndicatorParameters) { + // remove old indicators + this.legend + .filter(g => g.chart === 'rsi') + .forEach((i: Indicator) => this.deleteIndicator(i)); + + // fetch new indicator this.http.get(`${env.api}/RSI/${params.parameterOne}`, this.requestHeader()) .subscribe((rsi: RsiResult[]) => { @@ -597,10 +629,14 @@ export class AppComponent implements OnInit { // add to legend this.legend.push({ label: label, chart: 'rsi', color: params.color, lines: [rsiDataset] }); + // scroll to chart + setTimeout(() => { + this.chartRsiRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'start' }); + }, 200); + }, (error: HttpErrorResponse) => { console.log(error); }); } - stochChange(event: MatRadioChange) { const stoch: StochConfig = event.value; this.pickedParams.parameterOne = stoch.lookbackPeriod; @@ -609,6 +645,12 @@ export class AppComponent implements OnInit { addIndicatorSTOCH(params: IndicatorParameters) { + // remove old indicators + this.legend + .filter(g => g.chart === 'stoch') + .forEach((i: Indicator) => this.deleteIndicator(i)); + + // add new indicator this.http.get(`${env.api}/STOCH/${params.parameterOne}/${params.parameterTwo}`, this.requestHeader()) .subscribe((stoch: StochResult[]) => { @@ -660,6 +702,11 @@ export class AppComponent implements OnInit { // add to legend this.legend.push({ label: label, chart: 'stoch', color: params.color, lines: [oscDataset, sigDataset] }); + // scroll to chart + setTimeout(() => { + this.chartStochRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'start' }); + }, 200); + }, (error: HttpErrorResponse) => { console.log(error); }); } @@ -714,7 +761,6 @@ export class AppComponent implements OnInit { this.legend.splice(idxLegend, 1); } - requestHeader(): { headers?: HttpHeaders } { const simpleHeaders = new HttpHeaders() @@ -723,8 +769,23 @@ export class AppComponent implements OnInit { return { headers: simpleHeaders }; } + + // HELPER FUNCTIONS + toDecimals(value: number, decimalPlaces: number): number { if (value === null) return null; return value.toFixed(decimalPlaces) as unknown as number; } + + scrollToChartTop() { + setTimeout(() => { + this.chartRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'start' }); + }, 200); + } + + scrollToBottomOfPicker() { + setTimeout(() => { + this.pickerRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'end' }); + }, 200); + } } diff --git a/Client/src/app/chart.service.ts b/Client/src/app/chart.service.ts index 34e8e657..c4f144a8 100644 --- a/Client/src/app/chart.service.ts +++ b/Client/src/app/chart.service.ts @@ -32,14 +32,6 @@ export class ChartService { }, maintainAspectRatio: false, responsive: true, - // animation: { - // duration: 0 - // }, - // elements: { - // line: { - // tension: 0 // disables bezier curves - // } - // }, tooltips: { enabled: true, mode: 'index', @@ -76,7 +68,6 @@ export class ChartService { return config; } - baseOverlayConfig(): ChartConfiguration { const config = this.baseConfig();