feat(FEAT-MO-005): 增加全市场成交额趋势接口
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
import { BadRequestException, Controller, Get, Query } from '@nestjs/common';
|
import { BadRequestException, Controller, Get, Query } from '@nestjs/common';
|
||||||
import { ApiOkResponse, ApiQuery, ApiTags } from '@nestjs/swagger';
|
import { ApiOkResponse, ApiQuery, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { CapitalFlowResponseDto, SectorRankingsResponseDto } from './market-structure.dto';
|
import {
|
||||||
|
CapitalFlowResponseDto,
|
||||||
|
SectorRankingsResponseDto,
|
||||||
|
TurnoverTrendResponseDto,
|
||||||
|
} from './market-structure.dto';
|
||||||
import {
|
import {
|
||||||
MarketStructureService,
|
MarketStructureService,
|
||||||
parseCapitalFlowQuery,
|
parseCapitalFlowQuery,
|
||||||
parseSectorRankingQuery,
|
parseSectorRankingQuery,
|
||||||
|
parseTurnoverTrendQuery,
|
||||||
} from './market-structure.service';
|
} from './market-structure.service';
|
||||||
|
|
||||||
@ApiTags('market-overview-structure')
|
@ApiTags('market-overview-structure')
|
||||||
@@ -46,4 +51,19 @@ export class MarketStructureController {
|
|||||||
throw new BadRequestException(error instanceof Error ? error.message : '资金流参数无效');
|
throw new BadRequestException(error instanceof Error ? error.message : '资金流参数无效');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('turnover-trend')
|
||||||
|
@ApiQuery({ name: 'interval', required: false, enum: ['5', '15'] })
|
||||||
|
@ApiQuery({ name: 'tradeDate', required: false, type: String, pattern: '^\\d{8}$' })
|
||||||
|
@ApiOkResponse({ type: TurnoverTrendResponseDto })
|
||||||
|
getTurnoverTrend(
|
||||||
|
@Query('interval') interval?: string,
|
||||||
|
@Query('tradeDate') tradeDate?: string,
|
||||||
|
): Promise<TurnoverTrendResponseDto> {
|
||||||
|
try {
|
||||||
|
return this.service.getTurnoverTrend(parseTurnoverTrendQuery(interval, tradeDate));
|
||||||
|
} catch (error) {
|
||||||
|
throw new BadRequestException(error instanceof Error ? error.message : '成交额趋势参数无效');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,3 +89,36 @@ export class CapitalFlowResponseDto extends MarketOverviewMetaDto {
|
|||||||
@ApiProperty({ type: () => CapitalFlowDataDto, nullable: true })
|
@ApiProperty({ type: () => CapitalFlowDataDto, nullable: true })
|
||||||
data!: CapitalFlowDataDto | null;
|
data!: CapitalFlowDataDto | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TurnoverPointDto {
|
||||||
|
@ApiProperty({ type: String, format: 'date-time' })
|
||||||
|
time!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number, description: '该时间区间成交额,单位亿元' })
|
||||||
|
amount!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number, description: '当日累计成交额,单位亿元' })
|
||||||
|
cumulativeAmount!: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoverTrendDataDto {
|
||||||
|
@ApiProperty({ type: [TurnoverPointDto] })
|
||||||
|
points!: TurnoverPointDto[];
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['5', '15'] })
|
||||||
|
granularity!: '5' | '15';
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, example: '亿元' })
|
||||||
|
unit!: '亿元';
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number, minimum: 1, maximum: 3 })
|
||||||
|
marketCount!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
invalidPointCount!: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TurnoverTrendResponseDto extends MarketOverviewMetaDto {
|
||||||
|
@ApiProperty({ type: () => TurnoverTrendDataDto, nullable: true })
|
||||||
|
data!: TurnoverTrendDataDto | null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import {
|
|||||||
MarketStructureService,
|
MarketStructureService,
|
||||||
parseCapitalFlowQuery,
|
parseCapitalFlowQuery,
|
||||||
parseSectorRankingQuery,
|
parseSectorRankingQuery,
|
||||||
|
parseTurnoverTrendQuery,
|
||||||
} from './market-structure.service';
|
} from './market-structure.service';
|
||||||
import type { MarketStructureSourceClient } from './market-structure.types';
|
import type { MarketStructureSourceClient } from './market-structure.types';
|
||||||
|
import type { TdxClient } from '../tdx/tdx.client';
|
||||||
|
|
||||||
const source: MarketStructureSourceClient = {
|
const source: MarketStructureSourceClient = {
|
||||||
getSectorRows: async () => [
|
getSectorRows: async () => [
|
||||||
@@ -103,4 +105,52 @@ describe('行业题材排行服务', () => {
|
|||||||
flowDefinition: 'unavailable',
|
flowDefinition: 'unavailable',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('校验成交额趋势粒度和交易日期', () => {
|
||||||
|
expect(parseTurnoverTrendQuery('15', '20260824')).toEqual({
|
||||||
|
interval: '15',
|
||||||
|
tradeDate: '20260824',
|
||||||
|
});
|
||||||
|
expect(() => parseTurnoverTrendQuery('1', '20260824')).toThrow('粒度参数无效');
|
||||||
|
expect(() => parseTurnoverTrendQuery('5', '20260231')).toThrow('交易日期参数无效');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('聚合多个市场的 TDX 分时成交额并计算累计值', async () => {
|
||||||
|
const tdxClient: TdxClient = {
|
||||||
|
request: async <TResponse>() =>
|
||||||
|
({
|
||||||
|
ErrorId: '0',
|
||||||
|
Value: {
|
||||||
|
'000001.SH': {
|
||||||
|
Date: ['2026-08-24 09:30:00', '2026-08-24 09:35:00'],
|
||||||
|
Amount: ['10000', '20000'],
|
||||||
|
},
|
||||||
|
'399001.SZ': {
|
||||||
|
Date: ['2026-08-24 09:30:00', '2026-08-24 09:35:00'],
|
||||||
|
Amount: ['30000', '40000'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}) as TResponse,
|
||||||
|
};
|
||||||
|
const response = await new MarketStructureService(source, tdxClient).getTurnoverTrend({
|
||||||
|
interval: '5',
|
||||||
|
tradeDate: '20260824',
|
||||||
|
});
|
||||||
|
expect(response.status).toBe('partial');
|
||||||
|
expect(response.data?.points).toEqual([
|
||||||
|
{ time: '2026-08-24 09:30:00', amount: 4, cumulativeAmount: 4 },
|
||||||
|
{ time: '2026-08-24 09:35:00', amount: 6, cumulativeAmount: 10 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('TDX 分时序列为空时返回不可用', async () => {
|
||||||
|
const tdxClient: TdxClient = {
|
||||||
|
request: async <TResponse>() => ({ ErrorId: '0', Value: {} }) as TResponse,
|
||||||
|
};
|
||||||
|
const response = await new MarketStructureService(source, tdxClient).getTurnoverTrend({
|
||||||
|
interval: '5',
|
||||||
|
tradeDate: '20260824',
|
||||||
|
});
|
||||||
|
expect(response).toMatchObject({ status: 'unavailable', data: null });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable, Optional } from '@nestjs/common';
|
||||||
|
|
||||||
import type { MarketOverviewStatus } from '../market-overview.dto';
|
import type { MarketOverviewStatus } from '../market-overview.dto';
|
||||||
|
import { TDX_CLIENT_PORT } from '../market-overview.service';
|
||||||
|
import type { TdxClient } from '../tdx/tdx.client';
|
||||||
|
import { TURNOVER_INDEXES, type TdxKlineSeries, type TdxMarketDataResult } from '../tdx/tdx.types';
|
||||||
import { mapCapitalFlow, mapSectorRanking } from './market-structure.mapper';
|
import { mapCapitalFlow, mapSectorRanking } from './market-structure.mapper';
|
||||||
|
import { mapTurnoverPoints } from './market-structure.mapper';
|
||||||
import type {
|
import type {
|
||||||
CapitalFlowRecord,
|
CapitalFlowRecord,
|
||||||
SectorRankingRecord,
|
SectorRankingRecord,
|
||||||
@@ -9,7 +13,11 @@ import type {
|
|||||||
StructureSort,
|
StructureSort,
|
||||||
MarketStructureSourceClient,
|
MarketStructureSourceClient,
|
||||||
} from './market-structure.types';
|
} from './market-structure.types';
|
||||||
import type { CapitalFlowResponseDto, SectorRankingsResponseDto } from './market-structure.dto';
|
import type {
|
||||||
|
CapitalFlowResponseDto,
|
||||||
|
SectorRankingsResponseDto,
|
||||||
|
TurnoverTrendResponseDto,
|
||||||
|
} from './market-structure.dto';
|
||||||
|
|
||||||
export const MARKET_STRUCTURE_SOURCE_PORT = Symbol('MARKET_STRUCTURE_SOURCE_PORT');
|
export const MARKET_STRUCTURE_SOURCE_PORT = Symbol('MARKET_STRUCTURE_SOURCE_PORT');
|
||||||
|
|
||||||
@@ -25,6 +33,11 @@ export interface CapitalFlowQuery {
|
|||||||
limit: number;
|
limit: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TurnoverTrendQuery {
|
||||||
|
interval: '5' | '15';
|
||||||
|
tradeDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
const CATEGORIES = new Set<StructureCategory>(['industry', 'concept', 'board']);
|
const CATEGORIES = new Set<StructureCategory>(['industry', 'concept', 'board']);
|
||||||
const SORTS = new Set<SectorRankingQuery['sort']>(['rise', 'fall', 'turnover']);
|
const SORTS = new Set<SectorRankingQuery['sort']>(['rise', 'fall', 'turnover']);
|
||||||
const FLOW_SORTS = new Set<CapitalFlowQuery['sort']>(['inflow', 'outflow']);
|
const FLOW_SORTS = new Set<CapitalFlowQuery['sort']>(['inflow', 'outflow']);
|
||||||
@@ -67,6 +80,36 @@ export function parseCapitalFlowQuery(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidDate(value: string): boolean {
|
||||||
|
if (!/^\d{8}$/.test(value)) return false;
|
||||||
|
const date = new Date(`${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00Z`);
|
||||||
|
return (
|
||||||
|
date.getUTCFullYear() === Number(value.slice(0, 4)) &&
|
||||||
|
date.getUTCMonth() + 1 === Number(value.slice(4, 6)) &&
|
||||||
|
date.getUTCDate() === Number(value.slice(6, 8))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseTurnoverTrendQuery(
|
||||||
|
interval = '5',
|
||||||
|
tradeDate = currentShanghaiDate(),
|
||||||
|
): TurnoverTrendQuery {
|
||||||
|
if (interval !== '5' && interval !== '15') throw new Error('粒度参数无效');
|
||||||
|
if (!isValidDate(tradeDate)) throw new Error('交易日期参数无效');
|
||||||
|
return { interval, tradeDate };
|
||||||
|
}
|
||||||
|
|
||||||
|
function currentShanghaiDate(now = new Date()): string {
|
||||||
|
const values = new Intl.DateTimeFormat('en-CA', {
|
||||||
|
timeZone: 'Asia/Shanghai',
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
}).formatToParts(now);
|
||||||
|
const parts = Object.fromEntries(values.map((item) => [item.type, item.value]));
|
||||||
|
return `${parts.year}${parts.month}${parts.day}`;
|
||||||
|
}
|
||||||
|
|
||||||
function snapshotMeta(
|
function snapshotMeta(
|
||||||
source: 'aktools',
|
source: 'aktools',
|
||||||
): Pick<SectorRankingsResponseDto, 'snapshotId' | 'asOf' | 'source'> {
|
): Pick<SectorRankingsResponseDto, 'snapshotId' | 'asOf' | 'source'> {
|
||||||
@@ -125,11 +168,50 @@ function flowStatusFor(
|
|||||||
return 'fresh';
|
return 'fresh';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function aggregateTdxSeries(
|
||||||
|
result: TdxMarketDataResult,
|
||||||
|
tradeDate: string,
|
||||||
|
): { rows: Array<{ 时间: string; 成交额: number }>; marketCount: number } {
|
||||||
|
const amountsByTime = new Map<string, number>();
|
||||||
|
let marketCount = 0;
|
||||||
|
for (const definition of TURNOVER_INDEXES) {
|
||||||
|
const series: TdxKlineSeries | undefined = result.Value?.[definition.code];
|
||||||
|
if (!series || !Array.isArray(series.Date) || !Array.isArray(series.Amount)) continue;
|
||||||
|
if (series.Date.length === 0 || series.Date.length !== series.Amount.length) continue;
|
||||||
|
const validRows = series.Date.flatMap((time, index) => {
|
||||||
|
if (
|
||||||
|
typeof time !== 'string' ||
|
||||||
|
!time.startsWith(
|
||||||
|
`${tradeDate.slice(0, 4)}-${tradeDate.slice(4, 6)}-${tradeDate.slice(6, 8)}`,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return [];
|
||||||
|
const amount = Number(series.Amount[index]);
|
||||||
|
return Number.isFinite(amount) && amount >= 0 ? [{ time, amount: amount * 10_000 }] : [];
|
||||||
|
});
|
||||||
|
if (!validRows.length) continue;
|
||||||
|
marketCount += 1;
|
||||||
|
for (const row of validRows)
|
||||||
|
amountsByTime.set(row.time, (amountsByTime.get(row.time) ?? 0) + row.amount);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
rows: [...amountsByTime.entries()]
|
||||||
|
.sort(([left], [right]) => left.localeCompare(right))
|
||||||
|
.map(([时间, 成交额]) => ({ 时间, 成交额 })),
|
||||||
|
marketCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MarketStructureService {
|
export class MarketStructureService {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(MARKET_STRUCTURE_SOURCE_PORT)
|
@Inject(MARKET_STRUCTURE_SOURCE_PORT)
|
||||||
private readonly source: MarketStructureSourceClient,
|
private readonly source: MarketStructureSourceClient,
|
||||||
|
@Optional()
|
||||||
|
@Inject(TDX_CLIENT_PORT)
|
||||||
|
private readonly tdxClient: TdxClient = {
|
||||||
|
request: async <TResponse>() => ({}) as TResponse,
|
||||||
|
},
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getSectorRankings(query: SectorRankingQuery): Promise<SectorRankingsResponseDto> {
|
async getSectorRankings(query: SectorRankingQuery): Promise<SectorRankingsResponseDto> {
|
||||||
@@ -199,6 +281,53 @@ export class MarketStructureService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTurnoverTrend(query: TurnoverTrendQuery): Promise<TurnoverTrendResponseDto> {
|
||||||
|
const asOf = new Date().toISOString();
|
||||||
|
const meta = {
|
||||||
|
snapshotId: asOf.replace(/[-:TZ.]/g, '').slice(0, 15),
|
||||||
|
asOf,
|
||||||
|
source: 'tdx' as const,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const result = await this.tdxClient.request<TdxMarketDataResult>('get_market_data', {
|
||||||
|
stock_list: TURNOVER_INDEXES.map((item) => item.code),
|
||||||
|
count: 240,
|
||||||
|
dividend_type: 'none',
|
||||||
|
period: `${query.interval}m`,
|
||||||
|
});
|
||||||
|
const aggregated = aggregateTdxSeries(result, query.tradeDate);
|
||||||
|
const mapped = mapTurnoverPoints(aggregated.rows);
|
||||||
|
if (!mapped.points.length) {
|
||||||
|
return { ...meta, status: 'unavailable', data: null, warnings: ['成交额趋势数据不可用'] };
|
||||||
|
}
|
||||||
|
const dateStatus: MarketOverviewStatus =
|
||||||
|
query.tradeDate === currentShanghaiDate() ? 'fresh' : 'delayed';
|
||||||
|
const status: MarketOverviewStatus =
|
||||||
|
aggregated.marketCount < TURNOVER_INDEXES.length || mapped.invalidCount > 0
|
||||||
|
? 'partial'
|
||||||
|
: dateStatus;
|
||||||
|
return {
|
||||||
|
...meta,
|
||||||
|
status,
|
||||||
|
data: {
|
||||||
|
points: mapped.points,
|
||||||
|
granularity: query.interval,
|
||||||
|
unit: '亿元',
|
||||||
|
marketCount: aggregated.marketCount,
|
||||||
|
invalidPointCount: mapped.invalidCount,
|
||||||
|
},
|
||||||
|
warnings:
|
||||||
|
status === 'fresh'
|
||||||
|
? []
|
||||||
|
: status === 'partial'
|
||||||
|
? ['部分市场或成交额点不可用']
|
||||||
|
: [`成交额交易日期为 ${query.tradeDate},非当前日期`],
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return { ...meta, status: 'unavailable', data: null, warnings: ['成交额趋势数据不可用'] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readTradeDate(row: Readonly<Record<string, unknown>>): string | null {
|
private readTradeDate(row: Readonly<Record<string, unknown>>): string | null {
|
||||||
const value = row['日期'] ?? row['交易日期'] ?? row['tradeDate'];
|
const value = row['日期'] ?? row['交易日期'] ?? row['tradeDate'];
|
||||||
return typeof value === 'string' && /^\d{8}$/.test(value) ? value : null;
|
return typeof value === 'string' && /^\d{8}$/.test(value) ? value : null;
|
||||||
|
|||||||
@@ -545,6 +545,54 @@
|
|||||||
},
|
},
|
||||||
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
},
|
||||||
|
"TurnoverPointDto": {
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"description": "该时间区间成交额,单位亿元",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"cumulativeAmount": {
|
||||||
|
"description": "当日累计成交额,单位亿元",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"time": { "format": "date-time", "type": "string" }
|
||||||
|
},
|
||||||
|
"required": ["time", "amount", "cumulativeAmount"],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"TurnoverTrendDataDto": {
|
||||||
|
"properties": {
|
||||||
|
"granularity": { "enum": ["5", "15"], "type": "string" },
|
||||||
|
"invalidPointCount": { "type": "number" },
|
||||||
|
"marketCount": { "maximum": 3, "minimum": 1, "type": "number" },
|
||||||
|
"points": {
|
||||||
|
"items": { "$ref": "#/components/schemas/TurnoverPointDto" },
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"unit": { "example": "亿元", "type": "string" }
|
||||||
|
},
|
||||||
|
"required": ["points", "granularity", "unit", "marketCount", "invalidPointCount"],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"TurnoverTrendResponseDto": {
|
||||||
|
"properties": {
|
||||||
|
"asOf": { "format": "date-time", "type": "string" },
|
||||||
|
"data": {
|
||||||
|
"allOf": [{ "$ref": "#/components/schemas/TurnoverTrendDataDto" }],
|
||||||
|
"nullable": true,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"snapshotId": { "type": "string" },
|
||||||
|
"source": { "enum": ["tdx", "aktools", "mixed"], "type": "string" },
|
||||||
|
"status": {
|
||||||
|
"enum": ["fresh", "delayed", "partial", "unavailable"],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
|
},
|
||||||
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -873,6 +921,38 @@
|
|||||||
},
|
},
|
||||||
"tags": ["market-overview"]
|
"tags": ["market-overview"]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/market-overview/turnover-trend": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "MarketStructureController_getTurnoverTrend",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "tradeDate",
|
||||||
|
"required": false,
|
||||||
|
"schema": { "pattern": "^\\d{8}$", "type": "string" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "interval",
|
||||||
|
"required": false,
|
||||||
|
"schema": { "enum": ["5", "15"], "type": "string" }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/TurnoverTrendResponseDto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": ["market-overview-structure"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"servers": [],
|
"servers": [],
|
||||||
|
|||||||
@@ -196,6 +196,22 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
'/api/v1/market-overview/turnover-trend': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketStructureController_getTurnoverTrend'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export type webhooks = Record<string, never>;
|
export type webhooks = Record<string, never>;
|
||||||
export interface components {
|
export interface components {
|
||||||
@@ -502,6 +518,34 @@ export interface components {
|
|||||||
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
warnings: string[];
|
warnings: string[];
|
||||||
};
|
};
|
||||||
|
TurnoverPointDto: {
|
||||||
|
/** @description 该时间区间成交额,单位亿元 */
|
||||||
|
amount: number;
|
||||||
|
/** @description 当日累计成交额,单位亿元 */
|
||||||
|
cumulativeAmount: number;
|
||||||
|
/** Format: date-time */
|
||||||
|
time: string;
|
||||||
|
};
|
||||||
|
TurnoverTrendDataDto: {
|
||||||
|
/** @enum {string} */
|
||||||
|
granularity: '5' | '15';
|
||||||
|
invalidPointCount: number;
|
||||||
|
marketCount: number;
|
||||||
|
points: components['schemas']['TurnoverPointDto'][];
|
||||||
|
/** @example 亿元 */
|
||||||
|
unit: string;
|
||||||
|
};
|
||||||
|
TurnoverTrendResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['TurnoverTrendDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx' | 'aktools' | 'mixed';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
@@ -767,4 +811,26 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
MarketStructureController_getTurnoverTrend: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
tradeDate?: string;
|
||||||
|
interval?: '5' | '15';
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['TurnoverTrendResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user