Add ability to search for indices and fix gf-symbol-autocomplete validation (#2094)
* Bugfix/Fix gf-symbol-autocomplete validation * Feature/Add ability to search for indices * Update changelog
This commit is contained in:
parent
51ca26bb4d
commit
6a802a62a0
10
CHANGELOG.md
10
CHANGELOG.md
@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Added the ability to add an index for benchmarks as an asset profile in the admin control panel
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an issue with the clone functionality of a transaction caused by the symbol search component
|
||||
|
||||
## 1.283.5 - 2023-06-25
|
||||
|
||||
### Added
|
||||
|
@ -36,10 +36,12 @@ export class SymbolController {
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
||||
public async lookupSymbol(
|
||||
@Query() { query = '' }
|
||||
@Query('includeIndices') includeIndices: boolean = false,
|
||||
@Query('query') query = ''
|
||||
): Promise<{ items: LookupItem[] }> {
|
||||
try {
|
||||
return this.symbolService.lookup({
|
||||
includeIndices,
|
||||
query: query.toLowerCase(),
|
||||
user: this.request.user
|
||||
});
|
||||
|
@ -81,9 +81,11 @@ export class SymbolService {
|
||||
}
|
||||
|
||||
public async lookup({
|
||||
includeIndices = false,
|
||||
query,
|
||||
user
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
user: UserWithSettings;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
@ -95,6 +97,7 @@ export class SymbolService {
|
||||
|
||||
try {
|
||||
const { items } = await this.dataProviderService.search({
|
||||
includeIndices,
|
||||
query,
|
||||
user
|
||||
});
|
||||
|
@ -114,8 +114,14 @@ export class AlphaVantageService implements DataProviderInterface {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
const result = await this.alphaVantage.data.search(aQuery);
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
const result = await this.alphaVantage.data.search(query);
|
||||
|
||||
return {
|
||||
items: result?.bestMatches?.map((bestMatch) => {
|
||||
|
@ -164,16 +164,17 @@ export class CoinGeckoService implements DataProviderInterface {
|
||||
return 'bitcoin';
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
let items: LookupItem[] = [];
|
||||
|
||||
try {
|
||||
const get = bent(
|
||||
`${this.URL}/search?query=${aQuery}`,
|
||||
'GET',
|
||||
'json',
|
||||
200
|
||||
);
|
||||
const get = bent(`${this.URL}/search?query=${query}`, 'GET', 'json', 200);
|
||||
const { coins } = await get();
|
||||
|
||||
items = coins.map(({ id: symbol, name }) => {
|
||||
|
@ -367,9 +367,11 @@ export class DataProviderService {
|
||||
}
|
||||
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query,
|
||||
user
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
user: UserWithSettings;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
@ -392,7 +394,12 @@ export class DataProviderService {
|
||||
}
|
||||
|
||||
for (const dataSource of dataSources) {
|
||||
promises.push(this.getDataProvider(DataSource[dataSource]).search(query));
|
||||
promises.push(
|
||||
this.getDataProvider(DataSource[dataSource]).search({
|
||||
includeIndices,
|
||||
query
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const searchResults = await Promise.all(promises);
|
||||
|
@ -156,7 +156,7 @@ export class EodHistoricalDataService implements DataProviderInterface {
|
||||
return !symbol.endsWith('.FOREX');
|
||||
})
|
||||
.map((symbol) => {
|
||||
return this.search(symbol);
|
||||
return this.search({ query: symbol });
|
||||
})
|
||||
);
|
||||
|
||||
@ -219,8 +219,14 @@ export class EodHistoricalDataService implements DataProviderInterface {
|
||||
return 'AAPL.US';
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
const searchResult = await this.getSearchResult(aQuery);
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
const searchResult = await this.getSearchResult(query);
|
||||
|
||||
return {
|
||||
items: searchResult
|
||||
|
@ -143,12 +143,18 @@ export class FinancialModelingPrepService implements DataProviderInterface {
|
||||
return 'AAPL';
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
let items: LookupItem[] = [];
|
||||
|
||||
try {
|
||||
const get = bent(
|
||||
`${this.URL}/search?query=${aQuery}&apikey=${this.apiKey}`,
|
||||
`${this.URL}/search?query=${query}&apikey=${this.apiKey}`,
|
||||
'GET',
|
||||
'json',
|
||||
200
|
||||
|
@ -153,7 +153,13 @@ export class GoogleSheetsService implements DataProviderInterface {
|
||||
return 'INDEXSP:.INX';
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
const items = await this.prismaService.symbolProfile.findMany({
|
||||
select: {
|
||||
assetClass: true,
|
||||
@ -169,14 +175,14 @@ export class GoogleSheetsService implements DataProviderInterface {
|
||||
dataSource: this.getName(),
|
||||
name: {
|
||||
mode: 'insensitive',
|
||||
startsWith: aQuery
|
||||
startsWith: query
|
||||
}
|
||||
},
|
||||
{
|
||||
dataSource: this.getName(),
|
||||
symbol: {
|
||||
mode: 'insensitive',
|
||||
startsWith: aQuery
|
||||
startsWith: query
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -42,5 +42,11 @@ export interface DataProviderInterface {
|
||||
|
||||
getTestSymbol(): string;
|
||||
|
||||
search(aQuery: string): Promise<{ items: LookupItem[] }>;
|
||||
search({
|
||||
includeIndices,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }>;
|
||||
}
|
||||
|
@ -171,7 +171,13 @@ export class ManualService implements DataProviderInterface {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
let items = await this.prismaService.symbolProfile.findMany({
|
||||
select: {
|
||||
assetClass: true,
|
||||
@ -187,14 +193,14 @@ export class ManualService implements DataProviderInterface {
|
||||
dataSource: this.getName(),
|
||||
name: {
|
||||
mode: 'insensitive',
|
||||
startsWith: aQuery
|
||||
startsWith: query
|
||||
}
|
||||
},
|
||||
{
|
||||
dataSource: this.getName(),
|
||||
symbol: {
|
||||
mode: 'insensitive',
|
||||
startsWith: aQuery
|
||||
startsWith: query
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -117,7 +117,13 @@ export class RapidApiService implements DataProviderInterface {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
return { items: [] };
|
||||
}
|
||||
|
||||
|
@ -275,11 +275,23 @@ export class YahooFinanceService implements DataProviderInterface {
|
||||
return 'AAPL';
|
||||
}
|
||||
|
||||
public async search(aQuery: string): Promise<{ items: LookupItem[] }> {
|
||||
public async search({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}): Promise<{ items: LookupItem[] }> {
|
||||
const items: LookupItem[] = [];
|
||||
|
||||
try {
|
||||
const searchResult = await yahooFinance.search(aQuery);
|
||||
const quoteTypes = ['EQUITY', 'ETF', 'FUTURE', 'MUTUALFUND'];
|
||||
|
||||
if (includeIndices) {
|
||||
quoteTypes.push('INDEX');
|
||||
}
|
||||
|
||||
const searchResult = await yahooFinance.search(query);
|
||||
|
||||
const quotes = searchResult.quotes
|
||||
.filter((quote) => {
|
||||
@ -295,7 +307,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
||||
this.baseCurrency
|
||||
)
|
||||
)) ||
|
||||
['EQUITY', 'ETF', 'FUTURE', 'MUTUALFUND'].includes(quoteType)
|
||||
quoteTypes.includes(quoteType)
|
||||
);
|
||||
})
|
||||
.filter(({ quoteType, symbol }) => {
|
||||
|
@ -8,7 +8,10 @@
|
||||
<div class="flex-grow-1 py-3" mat-dialog-content>
|
||||
<mat-form-field appearance="outline" class="w-100">
|
||||
<mat-label i18n>Name, symbol or ISIN</mat-label>
|
||||
<gf-symbol-autocomplete formControlName="searchSymbol" />
|
||||
<gf-symbol-autocomplete
|
||||
formControlName="searchSymbol"
|
||||
[includeIndices]="true"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end" mat-dialog-actions>
|
||||
|
@ -261,9 +261,21 @@ export class DataService {
|
||||
});
|
||||
}
|
||||
|
||||
public fetchSymbols(aQuery: string) {
|
||||
public fetchSymbols({
|
||||
includeIndices = false,
|
||||
query
|
||||
}: {
|
||||
includeIndices?: boolean;
|
||||
query: string;
|
||||
}) {
|
||||
let params = new HttpParams().set('query', query);
|
||||
|
||||
if (includeIndices) {
|
||||
params = params.append('includeIndices', includeIndices);
|
||||
}
|
||||
|
||||
return this.http
|
||||
.get<{ items: LookupItem[] }>(`/api/v1/symbol/lookup?query=${aQuery}`)
|
||||
.get<{ items: LookupItem[] }>('/api/v1/symbol/lookup', { params })
|
||||
.pipe(
|
||||
map((respose) => {
|
||||
return respose.items;
|
||||
|
@ -50,6 +50,7 @@ export class SymbolAutocompleteComponent
|
||||
extends AbstractMatFormField<LookupItem>
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
@Input() private includeIndices = false;
|
||||
@Input() public isLoading = false;
|
||||
|
||||
@ViewChild(MatInput, { static: false }) private input: MatInput;
|
||||
@ -94,7 +95,10 @@ export class SymbolAutocompleteComponent
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}),
|
||||
switchMap((query: string) => {
|
||||
return this.dataService.fetchSymbols(query);
|
||||
return this.dataService.fetchSymbols({
|
||||
query,
|
||||
includeIndices: this.includeIndices
|
||||
});
|
||||
})
|
||||
)
|
||||
.subscribe((filteredLookupItems) => {
|
||||
@ -132,7 +136,11 @@ export class SymbolAutocompleteComponent
|
||||
public ngDoCheck() {
|
||||
if (this.ngControl) {
|
||||
this.validateRequired();
|
||||
this.validateSelection();
|
||||
|
||||
if (this.control.touched) {
|
||||
this.validateSelection();
|
||||
}
|
||||
|
||||
this.errorState = this.ngControl.invalid && this.ngControl.touched;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user