From 5f46bd167f81f7ec72f3932c1845771a68eabc45 Mon Sep 17 00:00:00 2001 From: Daniel Scheidle Date: Wed, 9 Nov 2022 19:13:18 +0100 Subject: [PATCH] Implemented features. --- src/app/app-routing.module.ts | 4 +- src/app/app.component.css | 4 ++ src/app/app.component.html | 4 +- src/app/app.module.ts | 17 ++++-- .../sentiment-card.component.css | 12 ++++ .../sentiment-card.component.html | 21 +++++++ .../sentiment-card.component.spec.ts | 23 +++++++ .../sentiment-card.component.ts | 46 ++++++++++++++ .../sentinment/sentiment.component.css | 10 +++ .../sentinment/sentiment.component.html | 11 ++++ .../sentinment}/sentiment.component.spec.ts | 2 +- .../sentinment}/sentiment.component.ts | 17 ++++-- .../stock-card/stock-card.component.css | 20 ++++-- .../stock-card/stock-card.component.html | 61 +++++++++++++------ .../stock-card/stock-card.component.ts | 26 +++++--- .../tendency/tendency.component.css | 6 ++ .../tendency/tendency.component.html | 3 + .../tendency/tendency.component.spec.ts | 23 +++++++ .../components/tendency/tendency.component.ts | 19 ++++++ src/app/model/company-data.ts | 15 +++++ .../landing-page/landing-page.component.css | 12 ++-- .../landing-page/landing-page.component.html | 34 ++++++----- .../landing-page/landing-page.component.ts | 29 +++------ .../sentiment-page.component.css | 3 + .../sentiment-page.component.html | 5 ++ .../sentiment-page.component.spec.ts | 23 +++++++ .../sentiment-page.component.ts | 25 ++++++++ .../pages/sentiment/sentiment.component.css | 0 .../pages/sentiment/sentiment.component.html | 4 -- src/app/pipes/month.pipe.spec.ts | 8 +++ src/app/pipes/month.pipe.ts | 16 +++++ src/app/services/finnhub.service.ts | 37 +++++++++-- src/app/services/storage.service.ts | 14 ++--- src/styles.css | 10 ++- 34 files changed, 460 insertions(+), 104 deletions(-) create mode 100644 src/app/components/sentiment-card/sentiment-card.component.css create mode 100644 src/app/components/sentiment-card/sentiment-card.component.html create mode 100644 src/app/components/sentiment-card/sentiment-card.component.spec.ts create mode 100644 src/app/components/sentiment-card/sentiment-card.component.ts create mode 100644 src/app/components/sentinment/sentiment.component.css create mode 100644 src/app/components/sentinment/sentiment.component.html rename src/app/{pages/sentiment => components/sentinment}/sentiment.component.spec.ts (93%) rename src/app/{pages/sentiment => components/sentinment}/sentiment.component.ts (55%) create mode 100644 src/app/components/tendency/tendency.component.css create mode 100644 src/app/components/tendency/tendency.component.html create mode 100644 src/app/components/tendency/tendency.component.spec.ts create mode 100644 src/app/components/tendency/tendency.component.ts create mode 100644 src/app/pages/sentiment-page/sentiment-page.component.css create mode 100644 src/app/pages/sentiment-page/sentiment-page.component.html create mode 100644 src/app/pages/sentiment-page/sentiment-page.component.spec.ts create mode 100644 src/app/pages/sentiment-page/sentiment-page.component.ts delete mode 100644 src/app/pages/sentiment/sentiment.component.css delete mode 100644 src/app/pages/sentiment/sentiment.component.html create mode 100644 src/app/pipes/month.pipe.spec.ts create mode 100644 src/app/pipes/month.pipe.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 14066e1..2434325 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,11 +1,11 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; -import {SentimentComponent} from "./pages/sentiment/sentiment.component"; +import {SentimentPageComponent} from "./pages/sentiment-page/sentiment-page.component"; import {LandingPageComponent} from "./pages/landing-page/landing-page.component"; const routes: Routes = [ - {path: 'sentiment/:symbol', component: SentimentComponent}, + {path: 'sentiment/:symbol', component: SentimentPageComponent}, {path: '**', component: LandingPageComponent} ]; diff --git a/src/app/app.component.css b/src/app/app.component.css index e69de29..fbe6443 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -0,0 +1,4 @@ +.content { + max-width: 60rem; + margin: auto; + } diff --git a/src/app/app.component.html b/src/app/app.component.html index 0680b43..5ce7f79 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1 +1,3 @@ - +
+ +
diff --git a/src/app/app.module.ts b/src/app/app.module.ts index bf87211..03aa306 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -4,7 +4,7 @@ import {BrowserModule} from '@angular/platform-browser'; import {AppRoutingModule} from './app-routing.module'; import {AppComponent} from './app.component'; import {HttpClientModule} from "@angular/common/http"; -import {SentimentComponent} from './pages/sentiment/sentiment.component'; +import {SentimentPageComponent} from './pages/sentiment-page/sentiment-page.component'; import {LandingPageComponent} from './pages/landing-page/landing-page.component'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatCardModule} from "@angular/material/card"; @@ -13,18 +13,25 @@ import {MatButtonModule} from "@angular/material/button"; import {MatInputModule} from "@angular/material/input"; import {MatDividerModule} from "@angular/material/divider"; import {FormsModule} from "@angular/forms"; -import {MatProgressSpinnerModule} from "@angular/material/progress-spinner"; import {MatSnackBarModule} from "@angular/material/snack-bar"; import {MatGridListModule} from "@angular/material/grid-list"; -import { StockCardComponent } from './components/stock-card/stock-card.component'; +import {StockCardComponent} from './components/stock-card/stock-card.component'; import {MatIconModule} from "@angular/material/icon"; +import {SentimentCardComponent} from './components/sentiment-card/sentiment-card.component'; +import {TendencyComponent} from './components/tendency/tendency.component'; +import {SentimentComponent} from './components/sentinment/sentiment.component'; +import { MonthPipe } from './pipes/month.pipe'; @NgModule({ declarations: [ AppComponent, - SentimentComponent, + SentimentPageComponent, LandingPageComponent, - StockCardComponent + StockCardComponent, + SentimentCardComponent, + TendencyComponent, + SentimentComponent, + MonthPipe ], imports: [ FormsModule, diff --git a/src/app/components/sentiment-card/sentiment-card.component.css b/src/app/components/sentiment-card/sentiment-card.component.css new file mode 100644 index 0000000..e79a368 --- /dev/null +++ b/src/app/components/sentiment-card/sentiment-card.component.css @@ -0,0 +1,12 @@ +.mat-card { + margin: 1rem 0; + height: 14rem; + line-height: 2rem; + font-size: 16px; +} + +.grid-container { + display: grid; + grid-template-columns: auto auto auto; + padding: 10px; +} diff --git a/src/app/components/sentiment-card/sentiment-card.component.html b/src/app/components/sentiment-card/sentiment-card.component.html new file mode 100644 index 0000000..1a6ec8a --- /dev/null +++ b/src/app/components/sentiment-card/sentiment-card.component.html @@ -0,0 +1,21 @@ + + + {{company.description}} ({{company.symbol}}) + +
+
+ +
+
+
+
+
+ + + + Loading... + + + diff --git a/src/app/components/sentiment-card/sentiment-card.component.spec.ts b/src/app/components/sentiment-card/sentiment-card.component.spec.ts new file mode 100644 index 0000000..7d25a15 --- /dev/null +++ b/src/app/components/sentiment-card/sentiment-card.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SentimentCardComponent } from './sentiment-card.component'; + +describe('SentimentCardComponent', () => { + let component: SentimentCardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SentimentCardComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SentimentCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/sentiment-card/sentiment-card.component.ts b/src/app/components/sentiment-card/sentiment-card.component.ts new file mode 100644 index 0000000..ade0c68 --- /dev/null +++ b/src/app/components/sentiment-card/sentiment-card.component.ts @@ -0,0 +1,46 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {Company, InsiderSentimentData} from "../../model/company-data"; +import {FinnhubService} from "../../services/finnhub.service"; +import {Subscription} from "rxjs"; + +@Component({ + selector: 'app-sentiment-card', + templateUrl: './sentiment-card.component.html', + styleUrls: ['./sentiment-card.component.css'] +}) +export class SentimentCardComponent implements OnInit, OnDestroy { + + @Input() + symbol = ''; + + loaded = false; + company!: Company; + insiderSentiments!: Array; + + private loadedSubs = 0; + private subs: Subscription[] = []; + + constructor(private finnhubService: FinnhubService) { + + } + + ngOnInit(): void { + this.subs.push(this.finnhubService.getCompany(this.symbol).subscribe(value => { + this.company = value; + this.loaded = ++this.loadedSubs == this.subs.length; + })); + + let current = new Date() + let from = new Date(current.getFullYear(), current.getMonth() - 3, 1); + let to = new Date(current.getFullYear(), current.getMonth() - 1, 1); + + this.subs.push(this.finnhubService.getInsideSentiment(this.symbol, from, to).subscribe(value => { + this.insiderSentiments = value.data; + this.loaded = ++this.loadedSubs == this.subs.length; + })); + } + + ngOnDestroy(): void { + this.subs.forEach(s => s.unsubscribe()); + } +} diff --git a/src/app/components/sentinment/sentiment.component.css b/src/app/components/sentinment/sentiment.component.css new file mode 100644 index 0000000..d37aed2 --- /dev/null +++ b/src/app/components/sentinment/sentiment.component.css @@ -0,0 +1,10 @@ +.grid-container { + display: grid; + grid-template-columns: auto auto; + padding: 10px; +} + +.grid-item .label { + font-weight: bold; + margin: 1rem; +} diff --git a/src/app/components/sentinment/sentiment.component.html b/src/app/components/sentinment/sentiment.component.html new file mode 100644 index 0000000..93c889a --- /dev/null +++ b/src/app/components/sentinment/sentiment.component.html @@ -0,0 +1,11 @@ +
+
+

{{month | month }}

+

Change:{{change | number: '1.0-0'}}

+

MSPR:{{mspr | number: '1.2-2'}}

+
+
+ +
+
+ diff --git a/src/app/pages/sentiment/sentiment.component.spec.ts b/src/app/components/sentinment/sentiment.component.spec.ts similarity index 93% rename from src/app/pages/sentiment/sentiment.component.spec.ts rename to src/app/components/sentinment/sentiment.component.spec.ts index bf32a62..b50e882 100644 --- a/src/app/pages/sentiment/sentiment.component.spec.ts +++ b/src/app/components/sentinment/sentiment.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SentimentComponent } from './sentiment.component'; -describe('SentimentComponent', () => { +describe('SentinmentComponent', () => { let component: SentimentComponent; let fixture: ComponentFixture; diff --git a/src/app/pages/sentiment/sentiment.component.ts b/src/app/components/sentinment/sentiment.component.ts similarity index 55% rename from src/app/pages/sentiment/sentiment.component.ts rename to src/app/components/sentinment/sentiment.component.ts index 37b4d78..eecdb55 100644 --- a/src/app/pages/sentiment/sentiment.component.ts +++ b/src/app/components/sentinment/sentiment.component.ts @@ -1,5 +1,4 @@ -import { Component, OnInit } from '@angular/core'; -import {FinnhubService} from "../../services/finnhub.service"; +import {Component, Input, OnInit} from '@angular/core'; @Component({ selector: 'app-sentiment', @@ -8,9 +7,19 @@ import {FinnhubService} from "../../services/finnhub.service"; }) export class SentimentComponent implements OnInit { - constructor(private finnhubService: FinnhubService) { } + @Input() + month!: number; + + @Input() + change!: number; + + @Input() + mspr!: number; + + + constructor() { } ngOnInit(): void { - } + } } diff --git a/src/app/components/stock-card/stock-card.component.css b/src/app/components/stock-card/stock-card.component.css index f3cd274..283513a 100644 --- a/src/app/components/stock-card/stock-card.component.css +++ b/src/app/components/stock-card/stock-card.component.css @@ -1,16 +1,24 @@ .mat-card { - margin: 1rem; + margin: 1rem 0; + height: 14rem; + line-height: 2rem; + font-size: 16px; } -.mat-card-title .mat-icon { +a.remove { cursor: pointer; float: right; } -.mat-grid-tile .mat-icon { - font-size: 4rem; - height: 4rem; - width: 4rem; +.grid-container { + display: grid; + grid-template-columns: auto auto; + padding: 10px; +} + +.grid-item .label { + font-weight: bold; + margin: 1rem; } diff --git a/src/app/components/stock-card/stock-card.component.html b/src/app/components/stock-card/stock-card.component.html index 2c9c8fa..095a905 100644 --- a/src/app/components/stock-card/stock-card.component.html +++ b/src/app/components/stock-card/stock-card.component.html @@ -1,27 +1,54 @@ - + + {{company.description}} ({{company.symbol}}) - + + + + + - - - - - - - - +
+
+
+
+ Change today: + {{quote.dp / 100 | percent: '1.1-1'}} +
+
+ Opening price: + {{quote.o | currency: 'USD'}} +
+
+ Current price: + {{quote.c | currency: 'USD'}} +
+
+ High price: + {{quote.h | currency: 'USD'}} +
-

Change today: {{quote.dp / 100 | percent: '1.1-1'}}

-

Opening price: {{quote.o | currency: 'USD'}}

-

Current price: {{quote.c | currency: 'USD'}}

-

High price: {{quote.h | currency: 'USD'}}

- - +
+
+
+ +
+
- + +
+ + + + Loading... + + + diff --git a/src/app/components/stock-card/stock-card.component.ts b/src/app/components/stock-card/stock-card.component.ts index de2b376..95b383a 100644 --- a/src/app/components/stock-card/stock-card.component.ts +++ b/src/app/components/stock-card/stock-card.component.ts @@ -1,7 +1,7 @@ import {Component, Input, OnDestroy, OnInit} from '@angular/core'; import {FinnhubService} from "../../services/finnhub.service"; import {Company, QuoteResponse} from "../../model/company-data"; -import {Subject, Subscription} from "rxjs"; +import {Subscription} from "rxjs"; import {StorageService} from "../../services/storage.service"; @Component({ @@ -12,9 +12,14 @@ import {StorageService} from "../../services/storage.service"; export class StockCardComponent implements OnInit, OnDestroy { @Input() - company = {} as Company; + symbol = ''; - private _quote$ = new Subject(); + loaded = false; + company!: Company; + quote!: QuoteResponse; + + + private loadedSubs = 0; private subs: Subscription[] = []; constructor(public finnhubService: FinnhubService, @@ -22,19 +27,22 @@ export class StockCardComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.subs.push(this.finnhubService.getQuote(this.company.symbol).subscribe(value => this._quote$.next(value))); + this.subs.push(this.finnhubService.getCompany(this.symbol).subscribe(value => { + this.company = value; + this.loaded = ++this.loadedSubs == this.subs.length; + })); + this.subs.push(this.finnhubService.getQuote(this.symbol).subscribe(value => { + this.quote = value; + this.loaded = ++this.loadedSubs == this.subs.length; + })); } - getQuote(): Subject { - return this._quote$; - } ngOnDestroy(): void { this.subs.forEach(s => s.unsubscribe()); - this._quote$.complete(); } remove() { - this.storageService.remove(this.company.symbol); + this.storageService.remove(this.symbol); } } diff --git a/src/app/components/tendency/tendency.component.css b/src/app/components/tendency/tendency.component.css new file mode 100644 index 0000000..f251cc1 --- /dev/null +++ b/src/app/components/tendency/tendency.component.css @@ -0,0 +1,6 @@ +.mat-icon { + font-size: 6rem; + height: 100%; + width: 100%; + text-align: center; +} diff --git a/src/app/components/tendency/tendency.component.html b/src/app/components/tendency/tendency.component.html new file mode 100644 index 0000000..f2fc3cd --- /dev/null +++ b/src/app/components/tendency/tendency.component.html @@ -0,0 +1,3 @@ + + + diff --git a/src/app/components/tendency/tendency.component.spec.ts b/src/app/components/tendency/tendency.component.spec.ts new file mode 100644 index 0000000..3f3963f --- /dev/null +++ b/src/app/components/tendency/tendency.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TendencyComponent } from './tendency.component'; + +describe('TendencyComponent', () => { + let component: TendencyComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TendencyComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TendencyComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/tendency/tendency.component.ts b/src/app/components/tendency/tendency.component.ts new file mode 100644 index 0000000..3dce4f3 --- /dev/null +++ b/src/app/components/tendency/tendency.component.ts @@ -0,0 +1,19 @@ +import {Component, Input, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-tendency', + templateUrl: './tendency.component.html', + styleUrls: ['./tendency.component.css'] +}) +export class TendencyComponent implements OnInit { + + @Input() + value!: number; + + constructor() { } + + ngOnInit(): void { + + } + +} diff --git a/src/app/model/company-data.ts b/src/app/model/company-data.ts index 37b7e19..d5648a9 100644 --- a/src/app/model/company-data.ts +++ b/src/app/model/company-data.ts @@ -19,3 +19,18 @@ export interface QuoteResponse { o: number; pc: number; } + +export interface InsiderSentimentData { + symbol: string; + year: number; + month: number; + change: number; + mspr: number; +} + +export interface InsiderSentimentResponse { + data: Array; + symbol: string; +} + + diff --git a/src/app/pages/landing-page/landing-page.component.css b/src/app/pages/landing-page/landing-page.component.css index 97e66a7..c9a6195 100644 --- a/src/app/pages/landing-page/landing-page.component.css +++ b/src/app/pages/landing-page/landing-page.component.css @@ -1,7 +1,11 @@ -.mat-card { - margin: 1rem; +.search-box { + padding: 0; } -.mat-divider { - margin: 0 1rem; +.mat-form-field { + margin-right: 1rem; +} + +.mat-card { + margin: 1rem 0; } diff --git a/src/app/pages/landing-page/landing-page.component.html b/src/app/pages/landing-page/landing-page.component.html index 600b8a1..11c2c09 100644 --- a/src/app/pages/landing-page/landing-page.component.html +++ b/src/app/pages/landing-page/landing-page.component.html @@ -1,26 +1,28 @@ -

- Enter the symbol of a stock to track (i.e. AAPL, TSLA, GOOGL) -

+
- - + + diff --git a/src/app/pages/landing-page/landing-page.component.ts b/src/app/pages/landing-page/landing-page.component.ts index 09045b4..f9d3ddc 100644 --- a/src/app/pages/landing-page/landing-page.component.ts +++ b/src/app/pages/landing-page/landing-page.component.ts @@ -10,7 +10,7 @@ import {MatSnackBar} from "@angular/material/snack-bar"; }) export class LandingPageComponent implements OnInit { - symbol = ''; + symbolInput = ''; disabled = false; constructor(public finnhubService: FinnhubService, @@ -24,29 +24,16 @@ export class LandingPageComponent implements OnInit { addSymbol() { - console.log('search for ' + this.symbol) // start loading... this.disabled = true; - this.finnhubService.searchSymbol(this.symbol).subscribe(value => { - - if (value.count > 0) { - - let company = value.result.find(company => company.symbol == this.symbol); - if (company) { - this.storageService.add(company); - this.symbol = ''; - } else { - this.snackBar.open('No unique result', 'close', {duration: 10000}); - } - - this.disabled = false - } else { - this.snackBar.open('No result', 'close', {duration: 10000}); - this.disabled = false - } - }, (error) => { - this.snackBar.open('Communication error', 'close', {duration: 10000}); + this.finnhubService.getCompany(this.symbolInput).subscribe(value => { + this.storageService.add(value.symbol); + this.symbolInput = ''; + this.disabled = false; + }, (error: string) => { + this.snackBar.open(error, 'close', {duration: 10000}); + this.disabled = false; }); } } diff --git a/src/app/pages/sentiment-page/sentiment-page.component.css b/src/app/pages/sentiment-page/sentiment-page.component.css new file mode 100644 index 0000000..6f74bb6 --- /dev/null +++ b/src/app/pages/sentiment-page/sentiment-page.component.css @@ -0,0 +1,3 @@ +.mat-card { + margin: 1rem 0; +} diff --git a/src/app/pages/sentiment-page/sentiment-page.component.html b/src/app/pages/sentiment-page/sentiment-page.component.html new file mode 100644 index 0000000..95cc359 --- /dev/null +++ b/src/app/pages/sentiment-page/sentiment-page.component.html @@ -0,0 +1,5 @@ + + + + + diff --git a/src/app/pages/sentiment-page/sentiment-page.component.spec.ts b/src/app/pages/sentiment-page/sentiment-page.component.spec.ts new file mode 100644 index 0000000..bf73772 --- /dev/null +++ b/src/app/pages/sentiment-page/sentiment-page.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SentimentPageComponent } from './sentiment-page.component'; + +describe('SentimentComponent', () => { + let component: SentimentPageComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SentimentPageComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(SentimentPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/pages/sentiment-page/sentiment-page.component.ts b/src/app/pages/sentiment-page/sentiment-page.component.ts new file mode 100644 index 0000000..d413d87 --- /dev/null +++ b/src/app/pages/sentiment-page/sentiment-page.component.ts @@ -0,0 +1,25 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from "@angular/router"; +import {BehaviorSubject} from "rxjs"; +import {StorageService} from "../../services/storage.service"; + +@Component({ + selector: 'app-sentiment-page', + templateUrl: './sentiment-page.component.html', + styleUrls: ['./sentiment-page.component.css'] +}) +export class SentimentPageComponent implements OnInit { + + _symbols$ = new BehaviorSubject([]); + + constructor(private route: ActivatedRoute, + private storageService: StorageService) { + } + + ngOnInit(): void { + + this.route.params.subscribe(params => { + this._symbols$.next([params['symbol']]); + }); + } +} diff --git a/src/app/pages/sentiment/sentiment.component.css b/src/app/pages/sentiment/sentiment.component.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/pages/sentiment/sentiment.component.html b/src/app/pages/sentiment/sentiment.component.html deleted file mode 100644 index 1ddfe4d..0000000 --- a/src/app/pages/sentiment/sentiment.component.html +++ /dev/null @@ -1,4 +0,0 @@ -

sentiment works!

- - - diff --git a/src/app/pipes/month.pipe.spec.ts b/src/app/pipes/month.pipe.spec.ts new file mode 100644 index 0000000..d2f2162 --- /dev/null +++ b/src/app/pipes/month.pipe.spec.ts @@ -0,0 +1,8 @@ +import { MonthPipe } from './month.pipe'; + +describe('MonthPipe', () => { + it('create an instance', () => { + const pipe = new MonthPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/pipes/month.pipe.ts b/src/app/pipes/month.pipe.ts new file mode 100644 index 0000000..06fca53 --- /dev/null +++ b/src/app/pipes/month.pipe.ts @@ -0,0 +1,16 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import {formatDate} from "@angular/common"; + +@Pipe({ + name: 'month' +}) +export class MonthPipe implements PipeTransform { + + transform(value: number): unknown { + + let date = new Date(); + date.setMonth(value); + return formatDate(date, 'MMMM','en-US'); + } + +} diff --git a/src/app/services/finnhub.service.ts b/src/app/services/finnhub.service.ts index 7041218..e8b53fc 100644 --- a/src/app/services/finnhub.service.ts +++ b/src/app/services/finnhub.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@angular/core'; import {HttpClient} from "@angular/common/http"; -import {Observable} from "rxjs"; -import {QuoteResponse, SearchResponse} from "../model/company-data"; +import {catchError, from, map, Observable} from "rxjs"; +import {Company, InsiderSentimentResponse, QuoteResponse, SearchResponse} from "../model/company-data"; +import {formatDate} from "@angular/common"; @Injectable({ providedIn: 'root' @@ -12,7 +13,7 @@ export class FinnhubService { private readonly api = 'https://finnhub.io/api/v1'; private readonly apiQuote = this.api + '/quote'; private readonly apiSearch = this.api + '/search'; - + private readonly apiSentiment = this.api + '/stock/insider-sentiment'; constructor(private httpClient: HttpClient) { } @@ -21,9 +22,37 @@ export class FinnhubService { return this.httpClient.get(this.apiSearch, {params: { ...this.token, q }}); } - getQuote(symbol: string) { + getCompany(symbol: string): Observable { + return this.searchSymbol(symbol).pipe(map(value => { + if (value.count > 0) { + let company = value.result.find(company => company.symbol == symbol); + if (company) { + return company; + } else { + throw new Error('No unique result'); + } + } else { + throw new Error('No result'); + } + }), catchError((err: Error, caught) => { + throw new Error(err.message); + })); + } + + getQuote(symbol: string): Observable { return this.httpClient.get(this.apiQuote, {params: { ...this.token, symbol }}); } + + getInsideSentiment(symbol: string, fromDate: Date, toDate: Date): Observable { + + + + + let from = formatDate(fromDate,'yyyy-MM-dd','en-US'); + let to = formatDate(toDate,'yyyy-MM-dd','en-US'); + + return this.httpClient.get(this.apiSentiment, {params: { ...this.token, symbol, from, to }}); + } } diff --git a/src/app/services/storage.service.ts b/src/app/services/storage.service.ts index 84c6ec9..43aa23c 100644 --- a/src/app/services/storage.service.ts +++ b/src/app/services/storage.service.ts @@ -1,28 +1,26 @@ import {Injectable, OnDestroy} from '@angular/core'; import {BehaviorSubject} from "rxjs"; -import {Company} from "../model/company-data"; @Injectable({ providedIn: 'root' }) export class StorageService implements OnDestroy { - private storage: Company[] = []; - - private _storage$ = new BehaviorSubject([]); + private storage: string[] = []; + private _storage$ = new BehaviorSubject([]); constructor() { } - add(company: Company): void { - this.storage.push(company); + add(symbol: string): void { + this.storage.push(symbol); this._storage$.next(this.storage) } remove(symbol: string): void { console.log('Remove ' + symbol) - let index = this.storage.findIndex(company => company.symbol == symbol); + let index = this.storage.findIndex(item => item == symbol); if (index > -1) { this.storage.splice(index, 1); } @@ -31,7 +29,7 @@ export class StorageService implements OnDestroy { this._storage$.next(this.storage) } - get(): BehaviorSubject { + get(): BehaviorSubject { return this._storage$; } diff --git a/src/styles.css b/src/styles.css index 7e7239a..fa39552 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,4 +1,10 @@ /* You can add global styles to this file, and also import other style files */ -html, body { height: 100%; } -body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } +html, body { + height: 100%; +} + +body { + margin: 0; + font-family: Roboto, "Helvetica Neue", sans-serif; +}