This commit was merged in pull request #84.
This commit is contained in:
@@ -9,9 +9,7 @@ import { StructuredLogger } from '../../../../common/logging/structured-logger.s
|
|||||||
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
|
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
|
||||||
import {
|
import {
|
||||||
TbankAccessService,
|
TbankAccessService,
|
||||||
type TbankBond,
|
|
||||||
TbankClient,
|
TbankClient,
|
||||||
type TbankShare,
|
|
||||||
tbankSourceTtlMs,
|
tbankSourceTtlMs,
|
||||||
type TbankSyncAttempt,
|
type TbankSyncAttempt,
|
||||||
} from '../../../../integrations/tbank/tbank.api';
|
} from '../../../../integrations/tbank/tbank.api';
|
||||||
@@ -28,6 +26,7 @@ import {
|
|||||||
catalogSearchLimit,
|
catalogSearchLimit,
|
||||||
selectCatalogInstruments,
|
selectCatalogInstruments,
|
||||||
} from './catalog-selection';
|
} from './catalog-selection';
|
||||||
|
import { publicInstrument } from './public-instrument';
|
||||||
|
|
||||||
const UNAMBIGUOUS_MATCH_COUNT = 1;
|
const UNAMBIGUOUS_MATCH_COUNT = 1;
|
||||||
const NO_MATCHES = 0;
|
const NO_MATCHES = 0;
|
||||||
@@ -495,37 +494,3 @@ export class CatalogDiscoveryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function publicInstrument(value: TbankBond | TbankShare) {
|
|
||||||
const bond = value as TbankBond;
|
|
||||||
const share = value as TbankShare;
|
|
||||||
return {
|
|
||||||
uid: value.uid,
|
|
||||||
figi: value.figi,
|
|
||||||
assetUid: value.assetUid,
|
|
||||||
name: value.name,
|
|
||||||
ticker: value.ticker,
|
|
||||||
isin: value.isin,
|
|
||||||
classCode: value.classCode,
|
|
||||||
realExchange: value.realExchange,
|
|
||||||
apiTradeAvailableFlag: value.apiTradeAvailableFlag,
|
|
||||||
currency: value.currency,
|
|
||||||
shareType: share.shareType,
|
|
||||||
sector: value.sector,
|
|
||||||
lot: value.lot,
|
|
||||||
brand: value.brand ? { logoName: value.brand.logoName } : undefined,
|
|
||||||
first_1dayCandleDate: value.first_1dayCandleDate,
|
|
||||||
nominal: bond.nominal,
|
|
||||||
initialNominal: bond.initialNominal,
|
|
||||||
aciValue: bond.aciValue,
|
|
||||||
maturityDate: bond.maturityDate,
|
|
||||||
callDate: bond.callDate,
|
|
||||||
couponQuantityPerYear: bond.couponQuantityPerYear,
|
|
||||||
floatingCouponFlag: bond.floatingCouponFlag,
|
|
||||||
perpetualFlag: bond.perpetualFlag,
|
|
||||||
amortizationFlag: bond.amortizationFlag,
|
|
||||||
subordinatedFlag: bond.subordinatedFlag,
|
|
||||||
bondType: bond.bondType,
|
|
||||||
riskLevel: bond.riskLevel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
import { toSavedCandle } from '../infrastructure/tbank-candle.mapper';
|
import { toSavedCandle } from '../infrastructure/tbank-candle.mapper';
|
||||||
import { catalogSearchLimit } from './catalog-selection';
|
import { catalogSearchLimit } from './catalog-selection';
|
||||||
import { previousClose, timestamp } from './instrument-market';
|
import { previousClose, timestamp } from './instrument-market';
|
||||||
|
import { publicInstrument } from './public-instrument';
|
||||||
|
|
||||||
const MISSING_DATA_REVISION = 0;
|
const MISSING_DATA_REVISION = 0;
|
||||||
const FIRST_QUEUE_INDEX = 0;
|
const FIRST_QUEUE_INDEX = 0;
|
||||||
@@ -651,39 +652,6 @@ export type CatalogPayload = {
|
|||||||
tradingStatus?: null | string;
|
tradingStatus?: null | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function publicInstrument(value: TbankBond | TbankShare) {
|
|
||||||
const bond = value as TbankBond;
|
|
||||||
const share = value as TbankShare;
|
|
||||||
return {
|
|
||||||
uid: value.uid,
|
|
||||||
figi: value.figi,
|
|
||||||
assetUid: value.assetUid,
|
|
||||||
name: value.name,
|
|
||||||
ticker: value.ticker,
|
|
||||||
isin: value.isin,
|
|
||||||
classCode: value.classCode,
|
|
||||||
realExchange: value.realExchange,
|
|
||||||
apiTradeAvailableFlag: value.apiTradeAvailableFlag,
|
|
||||||
currency: value.currency,
|
|
||||||
shareType: share.shareType,
|
|
||||||
sector: value.sector,
|
|
||||||
lot: value.lot,
|
|
||||||
brand: value.brand ? { logoName: value.brand.logoName } : undefined,
|
|
||||||
first_1dayCandleDate: value.first_1dayCandleDate,
|
|
||||||
nominal: bond.nominal,
|
|
||||||
initialNominal: bond.initialNominal,
|
|
||||||
aciValue: bond.aciValue,
|
|
||||||
maturityDate: bond.maturityDate,
|
|
||||||
callDate: bond.callDate,
|
|
||||||
couponQuantityPerYear: bond.couponQuantityPerYear,
|
|
||||||
floatingCouponFlag: bond.floatingCouponFlag,
|
|
||||||
perpetualFlag: bond.perpetualFlag,
|
|
||||||
amortizationFlag: bond.amortizationFlag,
|
|
||||||
subordinatedFlag: bond.subordinatedFlag,
|
|
||||||
bondType: bond.bondType,
|
|
||||||
riskLevel: bond.riskLevel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function sourcePolicy(kind: CatalogSource['kind']) {
|
function sourcePolicy(kind: CatalogSource['kind']) {
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import type {
|
||||||
|
TbankBond,
|
||||||
|
TbankShare,
|
||||||
|
} from '../../../../integrations/tbank/tbank.api';
|
||||||
|
|
||||||
|
import { publicInstrument } from './public-instrument';
|
||||||
|
|
||||||
|
const share = {
|
||||||
|
uid: 'share-uid',
|
||||||
|
figi: 'FIGI1',
|
||||||
|
assetUid: 'asset-1',
|
||||||
|
name: 'Share',
|
||||||
|
ticker: 'SHAR',
|
||||||
|
isin: 'US000',
|
||||||
|
classCode: 'TQBR',
|
||||||
|
realExchange: 'REAL_EXCHANGE_MOEX',
|
||||||
|
apiTradeAvailableFlag: true,
|
||||||
|
currency: 'rub',
|
||||||
|
shareType: 'SHARE_TYPE_COMMON',
|
||||||
|
sector: 'Finance',
|
||||||
|
lot: 1,
|
||||||
|
brand: { logoName: 'logo.png', title: 'Brand', id: 'brand-1' },
|
||||||
|
first_1dayCandleDate: '2020-01-01T00:00:00Z',
|
||||||
|
privateField: 'must-not-leak',
|
||||||
|
} as unknown as TbankShare;
|
||||||
|
|
||||||
|
const bond = {
|
||||||
|
uid: 'bond-uid',
|
||||||
|
figi: 'FIGI2',
|
||||||
|
assetUid: 'asset-2',
|
||||||
|
name: 'Bond',
|
||||||
|
ticker: 'BOND',
|
||||||
|
classCode: 'TQOB',
|
||||||
|
currency: 'rub',
|
||||||
|
lot: 1,
|
||||||
|
nominal: { value: '1000', currency: 'rub' },
|
||||||
|
initialNominal: { value: '1000', currency: 'rub' },
|
||||||
|
aciValue: { value: '10', currency: 'rub' },
|
||||||
|
maturityDate: '2030-01-01T00:00:00Z',
|
||||||
|
couponQuantityPerYear: 2,
|
||||||
|
bondType: 'BOND_TYPE_EXPIRING',
|
||||||
|
brand: null,
|
||||||
|
privateField: 'must-not-leak',
|
||||||
|
} as unknown as TbankBond;
|
||||||
|
|
||||||
|
describe('publicInstrument projection', () => {
|
||||||
|
it('keeps approved share fields, trims brand, drops private extras', () => {
|
||||||
|
const result = publicInstrument(share);
|
||||||
|
expect(result.uid).toBe('share-uid');
|
||||||
|
expect(result.shareType).toBe('SHARE_TYPE_COMMON');
|
||||||
|
expect(result.brand).toEqual({ logoName: 'logo.png' });
|
||||||
|
expect(result).not.toHaveProperty('privateField');
|
||||||
|
expect(result).not.toHaveProperty('brand.title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('projects bonds with missing optional fields and null brand', () => {
|
||||||
|
const result = publicInstrument(bond);
|
||||||
|
expect(result.nominal).toEqual({ value: '1000', currency: 'rub' });
|
||||||
|
expect(result.shareType).toBeUndefined();
|
||||||
|
expect(result.brand).toBeUndefined();
|
||||||
|
expect(result.isin).toBeUndefined();
|
||||||
|
expect(result).not.toHaveProperty('privateField');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import type {
|
||||||
|
TbankBond,
|
||||||
|
TbankShare,
|
||||||
|
} from '../../../../integrations/tbank/tbank.api';
|
||||||
|
|
||||||
|
export function publicInstrument(value: TbankBond | TbankShare) {
|
||||||
|
const bond = value as TbankBond;
|
||||||
|
const share = value as TbankShare;
|
||||||
|
return {
|
||||||
|
uid: value.uid,
|
||||||
|
figi: value.figi,
|
||||||
|
assetUid: value.assetUid,
|
||||||
|
name: value.name,
|
||||||
|
ticker: value.ticker,
|
||||||
|
isin: value.isin,
|
||||||
|
classCode: value.classCode,
|
||||||
|
realExchange: value.realExchange,
|
||||||
|
apiTradeAvailableFlag: value.apiTradeAvailableFlag,
|
||||||
|
currency: value.currency,
|
||||||
|
shareType: share.shareType,
|
||||||
|
sector: value.sector,
|
||||||
|
lot: value.lot,
|
||||||
|
brand: value.brand ? { logoName: value.brand.logoName } : undefined,
|
||||||
|
first_1dayCandleDate: value.first_1dayCandleDate,
|
||||||
|
nominal: bond.nominal,
|
||||||
|
initialNominal: bond.initialNominal,
|
||||||
|
aciValue: bond.aciValue,
|
||||||
|
maturityDate: bond.maturityDate,
|
||||||
|
callDate: bond.callDate,
|
||||||
|
couponQuantityPerYear: bond.couponQuantityPerYear,
|
||||||
|
floatingCouponFlag: bond.floatingCouponFlag,
|
||||||
|
perpetualFlag: bond.perpetualFlag,
|
||||||
|
amortizationFlag: bond.amortizationFlag,
|
||||||
|
subordinatedFlag: bond.subordinatedFlag,
|
||||||
|
bondType: bond.bondType,
|
||||||
|
riskLevel: bond.riskLevel,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user