83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { MoexClientService } from '../moex-client/moex-client.service';
|
|
import { CacheService } from '../cache/cache.service';
|
|
import { SecurityType } from './dto/search-query.dto';
|
|
|
|
export interface SearchResultItem {
|
|
secid: string;
|
|
isin: string;
|
|
shortName: string;
|
|
type: 'share' | 'bond';
|
|
listLevel: number;
|
|
currency: string | null;
|
|
price: number | null;
|
|
}
|
|
|
|
@Injectable()
|
|
export class SecuritiesService {
|
|
constructor(
|
|
private readonly moexClient: MoexClientService,
|
|
private readonly cache: CacheService,
|
|
) {}
|
|
|
|
async search(query: string, type: SecurityType, limit: number): Promise<SearchResultItem[]> {
|
|
const { data } = await this.cache.getOrFetch(
|
|
'search',
|
|
[query.toLowerCase()],
|
|
async () => {
|
|
const results = await this.moexClient.searchSecurities(query);
|
|
return results
|
|
.map((s): SearchResultItem | null => {
|
|
const type =
|
|
s.group === 'stock_shares' ||
|
|
s.type === 'common_share' ||
|
|
s.type === 'preferred_share'
|
|
? ('share' as const)
|
|
: s.group === 'stock_bonds'
|
|
? ('bond' as const)
|
|
: null;
|
|
if (!type) return null;
|
|
return {
|
|
secid: s.secid,
|
|
isin: s.isin,
|
|
shortName: s.shortName,
|
|
type,
|
|
listLevel: s.listLevel,
|
|
currency: s.faceUnit === 'SUR' ? 'RUB' : s.faceUnit || null,
|
|
price: null,
|
|
};
|
|
})
|
|
.filter((r): r is SearchResultItem => r !== null);
|
|
},
|
|
'searchTtl',
|
|
);
|
|
|
|
let filtered = data;
|
|
if (type === SecurityType.SHARE) {
|
|
filtered = data.filter((r) => r.type === 'share');
|
|
} else if (type === SecurityType.BOND) {
|
|
filtered = data.filter((r) => r.type === 'bond');
|
|
}
|
|
|
|
return filtered.slice(0, limit);
|
|
}
|
|
|
|
async getShareBrief(secid: string): Promise<SearchResultItem | null> {
|
|
try {
|
|
const desc = await this.moexClient.getSecurityDescription(secid);
|
|
if (!desc) return null;
|
|
return {
|
|
secid: desc.secid,
|
|
isin: desc.isin,
|
|
shortName: desc.shortName,
|
|
type: 'share',
|
|
listLevel: desc.listLevel,
|
|
currency: desc.faceUnit === 'SUR' ? 'RUB' : desc.faceUnit,
|
|
price: null,
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
}
|