Created
June 26, 2025 20:47
-
-
Save carloswm85/c1d2c4ef097bb6b59f9d9596a3b46bdf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<mat-card class="mb4"> | |
<mat-list> | |
<mat-list-item> | |
<span class="underline-and-strong">ERC</span>: | |
<span class="low-ranking">LR-1</span> • | |
<span class="low-ranking">LR-2</span> • | |
<span class="medium-low-ranking">MLR-1</span> • | |
<span class="medium-low-ranking border-bottom">MLR-2</span> • | |
<span class="medium-high-ranking">MHR-1</span> • | |
<span class="medium-high-ranking">MHR-2</span> • | |
<span class="high-ranking">HR-1</span> • | |
<span class="high-ranking">HR-2</span> • | |
<span class=""> | |
<i>MLR-2 seems to be the best analysis starting point.</i> | |
</span> | |
</mat-list-item> | |
</mat-list> | |
</mat-card> | |
<app-progress-bar *ngIf="isLoading"></app-progress-bar> | |
<ng-container *ngIf="!isLoading"> | |
<div> | |
<!-- BUTTONS --> | |
<!-- <div class="buttons"> | |
<span class="buttons-title">EMAc Ranking Filtering:</span> | |
<button mat-flat-button class="low-ranking-button">Low: 0-50</button> | |
<button mat-flat-button class="medium-low-ranking-button">Medium-low: 50-100</button> | |
<button mat-flat-button class="medium-high-ranking-button">Medium-high: 100-150</button> | |
<button mat-flat-button class="high-ranking-button">High: 150-200</button> | |
</div> --> | |
<!-- Filters and Actions --> | |
<mat-card class="mb4"> | |
<mat-list> | |
<mat-list-item> | |
Server Time: <strong> {{ emacDescription?.serverTime }} </strong> • | |
Request Duration: <strong> {{ emacDescription?.requestDuration }} </strong> • | |
Symbols Count: <strong> {{ emacDescription?.symbolsCount }} </strong> • | |
Requests Count: <strong> {{ emacDescription?.requestsMadeCount }} </strong> • | |
EMAc Positions Data Errors: <strong> {{ emacDescription?.errorsCount }} </strong> • | |
EMA Length: <strong> {{ emacDescription?.emaLength }} </strong> | |
</mat-list-item> | |
</mat-list> | |
</mat-card> | |
<!-- Search/Filter --> | |
<mat-card class="mb4"> | |
<mat-card-content> | |
<!-- FIELD --> | |
<mat-form-field appearance="outline" ngClass="mr4"> | |
<mat-label>Search or Filter</mat-label> | |
<input matInput (input)="applyFilter($event)" placeholder="Type to filter data" #input> | |
<mat-icon matSuffix>search</mat-icon> | |
</mat-form-field> | |
<!-- FIELD --> | |
<mat-form-field appearance="outline" ngClass="mr4"> | |
<mat-label>Ranking Code</mat-label> | |
<mat-select [(value)]="selectedRankingCode" (selectionChange)="applyFilter()"> | |
<mat-option>None</mat-option> | |
<mat-option *ngFor="let rankingCode of validFilters" [value]="rankingCode"> | |
<span [appAddEmacRankingCodeClass]="rankingCode"> | |
{{ rankingCode | uppercase }} | |
</span> | |
</mat-option> | |
</mat-select> | |
</mat-form-field> | |
<!-- FIELD --> | |
<mat-form-field class="filter-field" appearance="outline"> | |
<mat-label>Amount Symbols</mat-label> | |
<input matInput type="number" [(ngModel)]="symbolsSliceEnd" (keydown.enter)="onEnterKey()" | |
placeholder="PRESS ENTER" /> | |
<mat-icon matSuffix>input</mat-icon> | |
</mat-form-field> | |
</mat-card-content> | |
</mat-card> | |
</div> | |
<!-- DATA TABLE --> | |
<div class="table-responsive mat-elevation-z8"> | |
<table mat-table [dataSource]="dataSource" matSort> | |
<!-- Number Column --> | |
<ng-container matColumnDef="position"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by position in the list" class="custom-header"> Nº </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
{{element.rowPosition}} | |
</td> | |
</ng-container> | |
<!-- Reviewed Row with Checkbox --> | |
<ng-container matColumnDef="reviewedCheck"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> Reviewed </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<mat-checkbox [(ngModel)]="element.reviewedCheck"></mat-checkbox> | |
</td> | |
</ng-container> | |
<!-- Symbol Column --> | |
<ng-container matColumnDef="symbol"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> Symbol </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
{{element.symbol}} | |
</td> | |
</ng-container> | |
<!-- EMAc Column 15m --> | |
<ng-container matColumnDef="strategyData15m"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header">15m</th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData15m.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData15m[prop]" class="border element-inline-block"> | |
{{ element.strategyData15m[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 30m --> | |
<ng-container matColumnDef="strategyData30m"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header">30m</th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData30m.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData30m[prop]" class="border element-inline-block"> | |
{{ element.strategyData30m[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 1h --> | |
<ng-container matColumnDef="strategyData1h"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> 1h </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData1h.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData1h[prop]" class="border element-inline-block"> | |
{{ element.strategyData1h[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 4h --> | |
<ng-container matColumnDef="strategyData4h"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> 4h </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData4h.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData4h[prop]" class="border element-inline-block"> | |
{{ element.strategyData4h[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 1D --> | |
<ng-container matColumnDef="strategyData1D"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> 1D </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData1D.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData1D[prop]" class="border element-inline-block"> | |
{{ element.strategyData1D[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 1W --> | |
<ng-container matColumnDef="strategyData1W"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> 1W </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData1W.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData1W[prop]" class="border element-inline-block"> | |
{{ element.strategyData1W[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- EMAc Column 1M --> | |
<ng-container matColumnDef="strategyData1M"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header"> 1M </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span class="border element-block"> | |
{{ element.strategyData1M.emacHighLowDistanceIncremental | percent: '1.2-4' }} | |
</span> | |
<ng-container *ngFor="let prop of ['emasTrend', 'emacPosition']"> | |
<span [appAddEmacPositionClass]="element.strategyData1M[prop]" class="border element-inline-block"> | |
{{ element.strategyData1M[prop] }} | |
</span> | |
</ng-container> | |
</td> | |
</ng-container> | |
<!-- Price Column --> | |
<ng-container matColumnDef="price"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header" | |
matTooltip="Last price in Tether Stable Coin, or USD" [matTooltipPosition]="tooltipPosition.value!"> | |
USDT<mat-icon class="mat-icon-small">help</mat-icon></th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<i> $ {{ element.price | currency:'':'':'1.2-4' }} </i> | |
</td> | |
</ng-container> | |
<!-- EMAc Ranking Points Column --> | |
<ng-container matColumnDef="emacRankingPoints"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header" | |
matTooltip="EMAc Position Ranking Points" [matTooltipPosition]="tooltipPosition.value!">EPRP<mat-icon | |
class="mat-icon-small">help</mat-icon></th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<span [appAddEmacRankingClass]="element.emacRankingPoints"> | |
{{element.emacRankingPoints}} | |
</span> | |
</td> | |
</ng-container> | |
<!-- EMAc Ranking Code Column --> | |
<ng-container matColumnDef="emacRankingCode"> | |
<th mat-header-cell *matHeaderCellDef mat-sort-header class="custom-header" | |
matTooltip="EMAc Position Ranking Code" [matTooltipPosition]="tooltipPosition.value!">EPRC | |
<mat-icon class="mat-icon-small">help</mat-icon> | |
</th> | |
<td mat-cell *matCellDef="let element" [ngClass]="element.emacRankingCode" class="custom-cell"> | |
<span [appAddEmacRankingClass]="element.emacRankingCode"> | |
{{element.emacRankingCode}} | |
</span> | |
</td> | |
</ng-container> | |
<!-- Links Column --> | |
<ng-container matColumnDef="urls"> | |
<th mat-header-cell *matHeaderCellDef class="custom-header"> Links </th> | |
<td mat-cell *matCellDef="let element" class="custom-cell"> | |
<ng-container *ngFor="let link of element.urls"> | |
<!-- Render additional content if the link contains 'tradingview' --> | |
<a *ngIf="link && link.includes('tradingview')" [href]="link" target="_blank" class="link-clean"> | |
<img src="assets/icons/tradingview-dark.svg" alt="TradingView Icon" class="link-icon" /> | |
</a> | |
<!-- Render content for links that do not contain 'tradingview' --> | |
<a [href]="link" target="_blank" class="link-clean" *ngIf="link && !link.includes('tradingview')"> | |
<img src="assets/icons/binance.svg" alt="Link Icon" class="link-icon" /> | |
</a> | |
</ng-container> | |
<a [href]="element.symbol" target="_blank" class="link-clean"> | |
<img src="assets/icons/open_in_new.svg" alt="Link Icon" class="link-icon" /> | |
</a> | |
</td> | |
</ng-container> | |
<!-- ? --> | |
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> | |
<!-- Table Row --> | |
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [class.highlighted-row]="row.reviewedCheck"> | |
</tr> | |
<!-- Row shown when there is no matching data. --> | |
<tr class="mat-row" *matNoDataRow> | |
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td> | |
</tr> | |
</table> | |
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" aria-label="Select page of users"></mat-paginator> | |
</div> | |
</ng-container> | |
<mat-card class="mb4 mt4"> | |
<mat-card-header> | |
<mat-card-title>Trading Strategy Instructions</mat-card-title> | |
<mat-card-subtitle>EMAc Strategy</mat-card-subtitle> | |
</mat-card-header> | |
<mat-card-content> | |
<mat-list> | |
<mat-list-item>Amount Symbols = 0, return all available symbols.</mat-list-item> | |
</mat-list> | |
</mat-card-content> | |
<!-- <mat-card-actions> | |
<button mat-button>LIKE</button> | |
<button mat-button>SHARE</button> | |
</mat-card-actions> --> | |
</mat-card> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component, ViewChild, AfterViewInit, ElementRef } from '@angular/core'; | |
import { MatPaginator } from '@angular/material/paginator'; | |
import { MatSort, MatSortModule } from '@angular/material/sort'; | |
import { MatTableDataSource, MatTableModule } from '@angular/material/table'; | |
import { BinanceRestService } from '../../../core/services/binance-rest.service'; | |
import { | |
BinanceDescription, | |
BinanceEmacDatatable, | |
BinanceEmacDatatableMode, | |
} from '../../../core/interfaces/binance.interface'; | |
import { AddEmacPositionClassDirective } from '../../../shared/directives/add-emac-position-class/add-emac-position-class.directive'; | |
import { AddEmacRankingClassDirective } from '../../../shared/directives/add-emac-ranking-class/add-emac-ranking-class.directive'; | |
import { ProgressBarComponent } from '../../../shared/components/progress-bar/progress-bar.component'; | |
import { MaterialModule } from '../../../core/material/material.module'; | |
import { FormControl, FormsModule } from '@angular/forms'; | |
import { AddEmacRankingCodeClassDirective } from '../../../shared/directives/add-emac-ranking-code-class/add-emac-ranking-code-class.directive'; | |
import { TooltipPosition } from '@angular/material/tooltip'; | |
import { CommonModule } from '@angular/common'; | |
@Component({ | |
selector: 'app-binance-emac-datatable', | |
standalone: true, | |
imports: [ | |
MatSortModule, | |
MatTableModule, | |
CommonModule, | |
AddEmacPositionClassDirective, | |
AddEmacRankingClassDirective, | |
AddEmacRankingCodeClassDirective, | |
ProgressBarComponent, | |
MaterialModule, | |
FormsModule, | |
], | |
templateUrl: './binance-emac-datatable.component.html', | |
styleUrl: './binance-emac-datatable.component.css', | |
}) | |
export class BinanceEmacDatatableComponent implements AfterViewInit { | |
displayedColumns: string[] = [ | |
'position', | |
'reviewedCheck', | |
'symbol', | |
'strategyData15m', | |
'strategyData30m', | |
'strategyData1h', | |
'strategyData4h', | |
'strategyData1D', | |
'strategyData1W', | |
'strategyData1M', | |
'price', | |
'emacRankingPoints', | |
'emacRankingCode', | |
'urls', | |
]; | |
emacDatatableData: BinanceEmacDatatableMode | null = null; | |
dataSource = new MatTableDataSource<BinanceEmacDatatable>([]); // Updated to MatTableDataSource | |
isLoading = true; | |
symbolsSliceEnd = 9; | |
emacDescription: BinanceDescription | undefined; | |
// Define the valid ranking codes for quick lookup | |
validFilters = [ | |
'lr-1', | |
'lr-2', | |
'mlr-1', | |
'mlr-2', | |
'mhr-1', | |
'mhr-2', | |
'hr-1', | |
'hr-2', | |
]; | |
selectedRankingCode: string | null = null; | |
positionOptions: TooltipPosition[] = ['below', 'above', 'left', 'right']; | |
tooltipPosition = new FormControl(this.positionOptions[1]); // 'above' is selected | |
@ViewChild(MatPaginator) paginator!: MatPaginator; | |
@ViewChild(MatSort) sort: MatSort; | |
@ViewChild('input', { static: true }) inputFilter!: ElementRef; | |
constructor(private binanceRestService: BinanceRestService) { | |
this.fetchEmacData(this.symbolsSliceEnd); | |
this.sort = new MatSort(); | |
// Customize filter logic | |
this.dataSource.filterPredicate = ( | |
data: BinanceEmacDatatable, | |
filter: string | |
) => { | |
const lowerCaseFilter = filter.trim().toLowerCase(); | |
// Check if the filter matches one of the valid ranking codes | |
if (this.validFilters.includes(lowerCaseFilter)) { | |
return data.emacRankingCode.toLowerCase() === lowerCaseFilter; | |
} | |
// Default filter logic for other cases | |
return ( | |
data.symbol.toLowerCase().includes(lowerCaseFilter) || | |
data.emacRankingPoints.toString().includes(lowerCaseFilter) | |
); | |
}; | |
} | |
ngAfterViewInit(): void { | |
// Set paginator and sort after view initialization | |
this.dataSource.paginator = this.paginator; | |
this.dataSource.sort = this.sort; | |
} | |
private fetchEmacData(symbolsSliceEnd: number): void { | |
this.binanceRestService.getEmacDataTable(symbolsSliceEnd).subscribe({ | |
next: (data) => { | |
this.processEmacData(data); | |
}, | |
error: (err) => { | |
console.error('Error fetching EMAc data:', err); | |
this.isLoading = false; | |
}, | |
}); | |
} | |
private processEmacData(data: BinanceEmacDatatableMode): void { | |
this.emacDatatableData = data; | |
this.emacDescription = data.description; | |
console.log(data.description.serverTime); | |
const sortedData = this.emacDatatableData.data | |
.sort((a, b) => a.emacRankingPoints - b.emacRankingPoints) | |
.map((item) => ({ | |
...item, | |
reviewedCheck: false, | |
})); | |
this.dataSource.data = sortedData; | |
this.isLoading = false; | |
} | |
applyFilter(event?: Event): void { | |
// Get the text input value if the event is triggered from the input field | |
const filterInputValue = event | |
? (event.target as HTMLInputElement).value.trim().toLowerCase() | |
: ''; | |
// Get the dropdown filter value | |
const rankingCodeFilter = this.selectedRankingCode | |
? this.selectedRankingCode.toLowerCase() | |
: ''; | |
console.log(filterInputValue); | |
console.log(rankingCodeFilter); | |
// Combine both filters | |
const combinedFilter = `${filterInputValue} ${rankingCodeFilter}`; | |
this.dataSource.filter = combinedFilter; | |
if (this.dataSource.paginator) { | |
this.dataSource.paginator.firstPage(); | |
} | |
} | |
onEnterKey(): void { | |
this.isLoading = true; | |
console.log('Enter pressed with value:', this.symbolsSliceEnd); | |
// Trigger the data fetch and redraw table with the specified number of symbols | |
this.fetchEmacData(this.symbolsSliceEnd); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment