Skip to content

Commit

Permalink
cleanup UX for adding indicators (#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaveSkender authored Jan 24, 2021
1 parent 8371dd4 commit 6b117e9
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 29 deletions.
15 changes: 7 additions & 8 deletions Client/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
<p class="noselect center">
This is a demo of the <a href="https://www.nuget.org/packages/Skender.Stock.Indicators" target="_blank"
rel="noopener noreferrer">Skender.Stock.Indicators</a> .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.
</p>

<!-- CHART STACK -->
<a #chartsTop></a>
<mat-card class="container">

<!-- loading -->
Expand All @@ -33,14 +34,13 @@
</div>

<!-- CHART (RSI) -->
<div class="chart-label" *ngIf="chartRsiOn && chartRsiLabel">Relative Strength Index</div>
<div class="chart-label" *ngIf="chartRsiOn && chartRsiLabel">Relative Strength Index - {{ chartRsiLabel }}</div>
<div class="chart-container-oscillator" [hidden]="!chartRsiOn">
<canvas #chartRsi></canvas>
</div>

<!-- CHART (STOCH) -->
<div class="chart-label" *ngIf="chartStochOn && chartStochLabel">Stochastic Oscillator
</div>
<div class="chart-label" *ngIf="chartStochOn && chartStochLabel">Stochastic Oscillator - {{ chartStochLabel }}</div>
<div class="chart-container-oscillator" [hidden]="!chartStochOn">
<canvas #chartStoch></canvas>
</div>
Expand Down Expand Up @@ -69,7 +69,7 @@
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>

<mat-chip selected color="default" (click)="pickIndicator=true" *ngIf="!pickIndicator"
<mat-chip selected color="default" (click)="startAdd()" *ngIf="!pickIndicator"
matTooltip="add new indicator">
<mat-icon>add</mat-icon>
</mat-chip>
Expand All @@ -80,12 +80,11 @@


<!-- PICKER -->
<div class="container" *ngIf="pickIndicator" style="margin-bottom:50px;">
<div class="container" *ngIf="pickIndicator" style="padding-bottom:25px;" #picker>

<!-- pick indicator type -->
<div *ngIf="!pickedType.code">

<mat-chip-list></mat-chip-list>
<p class="center">Pick and indicator type:</p>
<mat-chip-list>

Expand Down Expand Up @@ -292,4 +291,4 @@

</div>

</div>
</div>
3 changes: 2 additions & 1 deletion Client/src/app/app.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
83 changes: 72 additions & 11 deletions Client/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = [];

Expand Down Expand Up @@ -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())
Expand All @@ -124,7 +124,6 @@ export class AppComponent implements OnInit {
}, (error: HttpErrorResponse) => { console.log(error); });
}


addBaseOverlayChart() {

const myChart: HTMLCanvasElement = this.chartOverlayRef.nativeElement as HTMLCanvasElement;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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[]) => {

Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -555,14 +582,19 @@ export class AppComponent implements OnInit {
}, (error: HttpErrorResponse) => { console.log(error); });
}


rsiChange(event: MatRadioChange) {
const rsi: RsiConfig = event.value;
this.pickedParams.parameterOne = rsi.lookbackPeriod;
}

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[]) => {

Expand Down Expand Up @@ -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;
Expand All @@ -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[]) => {

Expand Down Expand Up @@ -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); });
}

Expand Down Expand Up @@ -714,7 +761,6 @@ export class AppComponent implements OnInit {
this.legend.splice(idxLegend, 1);
}


requestHeader(): { headers?: HttpHeaders } {

const simpleHeaders = new HttpHeaders()
Expand All @@ -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);
}
}
9 changes: 0 additions & 9 deletions Client/src/app/chart.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -76,7 +68,6 @@ export class ChartService {
return config;
}


baseOverlayConfig(): ChartConfiguration {

const config = this.baseConfig();
Expand Down

0 comments on commit 6b117e9

Please sign in to comment.