You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

201 lines
5.6 KiB

import { DATE_RANGE_PATTERN } from '@ghostfolio/api/dtos/date-range-filter.dto';
import { isValidEncodedDataSource } from '@ghostfolio/api/helper/data-source.helper';
import {
COMMENT_MAXIMUM_LENGTH,
DATE_RANGES,
DEFAULT_DATE_RANGE,
MCP_MAX_ACCOUNTS,
MCP_MAX_ACTIVITIES,
SEARCH_QUERY_MAXIMUM_LENGTH,
SEARCH_QUERY_MINIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import {
isValidAccountBalanceDate,
isValidCurrencyCode,
isValidDateAfter1970
} from '@ghostfolio/common/helper';
import { AssetClass, DataSource, Type as ActivityType } from '@prisma/client';
import { z } from 'zod';
const DATA_SOURCE_PARAMETER_ERROR = `Invalid option: expected one of ${Object.values(DataSource).join('|')} or a data source as given by a tool`;
const DATA_SOURCE_PARAMETER = z
.union(
[
z.enum(DataSource),
z.string().refine(isValidEncodedDataSource, {
error: DATA_SOURCE_PARAMETER_ERROR
})
],
{ error: DATA_SOURCE_PARAMETER_ERROR }
)
.describe('The data source of the asset profile');
const SYMBOL_PARAMETER = z
.string()
.trim()
.min(1)
.max(SYMBOL_MAXIMUM_LENGTH)
.describe('The symbol of the asset profile');
const HOLDING_PARAMETER = z.object({
dataSource: DATA_SOURCE_PARAMETER,
symbol: SYMBOL_PARAMETER
});
export const GET_ACCOUNTS_PARAMETERS = z.object({
accountIds: z
.array(z.string().min(1))
.min(1)
.max(MCP_MAX_ACCOUNTS)
.optional()
.describe(
`The identifiers of the accounts to get, at most ${MCP_MAX_ACCOUNTS}`
),
assetClasses: z
.array(z.enum(AssetClass))
.min(1)
.optional()
.describe('The asset classes of the accounts to get'),
holding: HOLDING_PARAMETER.optional().describe(
'The asset profile of the accounts to get'
)
});
export const GET_ACTIVITIES_PARAMETERS = z.object({
activityTypes: z
.array(z.enum(ActivityType))
.min(1)
.optional()
.describe('The types of the activities to get'),
assetClasses: z
.array(z.enum(AssetClass))
.min(1)
.optional()
.describe('The asset classes of the activities to get'),
holding: HOLDING_PARAMETER.optional().describe(
'The asset profile of the activities to get'
),
range: z
.string()
.regex(DATE_RANGE_PATTERN)
.optional()
.describe(
`The date range of the activities to get, either ${DATE_RANGES.join(
', '
)} or a calendar year like 2024`
),
skip: z
.number()
.int()
.min(0)
.optional()
.describe('The number of activities to skip'),
take: z
.number()
.int()
.min(1)
.max(MCP_MAX_ACTIVITIES)
.default(MCP_MAX_ACTIVITIES)
.describe(`The number of activities to get, at most ${MCP_MAX_ACTIVITIES}`)
});
export const GET_PERFORMANCE_PARAMETERS = z.object({
accountIds: z
.array(z.string().min(1))
.min(1)
.max(MCP_MAX_ACCOUNTS)
.optional()
.describe(
`The identifiers of the accounts of the performance, at most ${MCP_MAX_ACCOUNTS}`
),
assetClasses: z
.array(z.enum(AssetClass))
.min(1)
.optional()
.describe('The asset classes of the performance'),
holding: HOLDING_PARAMETER.optional().describe(
'The asset profile of the performance'
),
range: z
.string()
.regex(DATE_RANGE_PATTERN)
.default(DEFAULT_DATE_RANGE)
.describe(
`The date range of the performance, either ${DATE_RANGES.join(
', '
)} or a calendar year like 2024`
)
});
export const IMPORT_ACTIVITIES_PARAMETERS = z.object({
activities: z
.array(
z.object({
accountId: z
.string()
.min(1)
.optional()
.describe('The identifier of the account of the activity'),
comment: z
.string()
.trim()
.max(COMMENT_MAXIMUM_LENGTH)
.optional()
.describe('The comment of the activity'),
currency: z
.string()
.refine(isValidCurrencyCode)
.describe(
'The currency of the fee and of the unit price, as an ISO 4217 code in upper case'
),
dataSource: DATA_SOURCE_PARAMETER.optional(),
date: z
.string()
.refine(isValidDateAfter1970)
.describe(
'The date of the activity, as an ISO 8601 date or date and time'
),
fee: z.number().min(0).describe('The fee of the activity'),
quantity: z.number().min(0).describe('The quantity of the activity'),
symbol: SYMBOL_PARAMETER,
type: z.enum(ActivityType).describe('The type of the activity'),
unitPrice: z.number().min(0).describe('The unit price of the activity')
})
)
.min(1)
.max(MCP_MAX_ACTIVITIES)
.describe(`The activities to import, at most ${MCP_MAX_ACTIVITIES}`)
});
export const SEARCH_ASSET_PROFILES_PARAMETERS = z.object({
query: z
.string()
.trim()
.min(SEARCH_QUERY_MINIMUM_LENGTH)
.max(SEARCH_QUERY_MAXIMUM_LENGTH)
.describe(
'The name, ticker symbol or ISIN of the financial asset, for example Apple, AAPL, Bitcoin or US0378331005'
)
});
export const UPDATE_ACCOUNT_BALANCE_PARAMETERS = z.object({
accountId: z.string().min(1).describe('The identifier of the account'),
balance: z
.number()
.describe('The cash balance of the account in the currency of the account'),
date: z.iso
.date({
abort: true,
error: 'The date must be an ISO 8601 date, for example 2024-01-01'
})
.refine(isValidDateAfter1970, {
error: 'The date must be after 1970-01-01'
})
.refine(isValidAccountBalanceDate, {
error: 'The date must not be in the future'
})
.describe('The date of the cash balance, as an ISO 8601 date')
});