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();