Compare commits
4
Commits
206e6b3fa4
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87d105b7b8 | ||
|
|
56f70eb599 | ||
|
|
999abd1d1e | ||
|
|
bbaeacb1cb |
No files matched your search
+89
-16
@@ -960,7 +960,7 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- profit
|
- profit
|
||||||
summary: Get the daily profit series for a single ledger
|
summary: Get the daily profit series for a single or combined ledger
|
||||||
operationId: profitPerDayInLedger
|
operationId: profitPerDayInLedger
|
||||||
parameters:
|
parameters:
|
||||||
- name: ledgerId
|
- name: ledgerId
|
||||||
@@ -972,8 +972,8 @@ paths:
|
|||||||
format: uuid
|
format: uuid
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: "Daily profit for the ledger, ascending by date, only for days\
|
description: "Daily profit for the ledger, ascending by date. For a combined\
|
||||||
\ with ISK activity"
|
\ ledger, per-date values are merged across its covered main ledgers."
|
||||||
content:
|
content:
|
||||||
'*/*':
|
'*/*':
|
||||||
schema:
|
schema:
|
||||||
@@ -981,14 +981,15 @@ paths:
|
|||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/DailyProfitResponse"
|
$ref: "#/components/schemas/DailyProfitResponse"
|
||||||
"400":
|
"400":
|
||||||
description: The ledger is the system ledger or a combined ledger
|
description: The ledger is the system ledger
|
||||||
"404":
|
"404":
|
||||||
description: No ledger with this id
|
description: No ledger with this id
|
||||||
/ledgers/{ledgerId}/margin:
|
/ledgers/{ledgerId}/margin:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- profit
|
- profit
|
||||||
summary: Get the daily FIFO-realized margin series for a single ledger
|
summary: Get the daily FIFO-realized margin series for a single or combined
|
||||||
|
ledger
|
||||||
operationId: marginPerDayInLedger
|
operationId: marginPerDayInLedger
|
||||||
parameters:
|
parameters:
|
||||||
- name: ledgerId
|
- name: ledgerId
|
||||||
@@ -1000,10 +1001,11 @@ paths:
|
|||||||
format: uuid
|
format: uuid
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: "Daily FIFO-realized margin for the ledger, ascending by date,\
|
description: "Daily FIFO-realized margin for the ledger, ascending by date.\
|
||||||
\ only for days with a consumption. iskIn is the sum of that day's profitable\
|
\ iskIn is the sum of that day's profitable consumptions, iskOut is the\
|
||||||
\ consumptions, iskOut is the sum of that day's losing consumptions (as\
|
\ sum of that day's losing consumptions (as a positive deficit); profit\
|
||||||
\ a positive deficit); profit is iskIn minus iskOut."
|
\ is iskIn minus iskOut. For a combined ledger, per-date values are merged\
|
||||||
|
\ across its covered main ledgers."
|
||||||
content:
|
content:
|
||||||
'*/*':
|
'*/*':
|
||||||
schema:
|
schema:
|
||||||
@@ -1011,7 +1013,7 @@ paths:
|
|||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/DailyProfitResponse"
|
$ref: "#/components/schemas/DailyProfitResponse"
|
||||||
"400":
|
"400":
|
||||||
description: The ledger is the system ledger or a combined ledger
|
description: The ledger is the system ledger
|
||||||
"404":
|
"404":
|
||||||
description: No ledger with this id
|
description: No ledger with this id
|
||||||
/ledgers/{ledgerId}/balance:
|
/ledgers/{ledgerId}/balance:
|
||||||
@@ -1037,12 +1039,41 @@ paths:
|
|||||||
$ref: "#/components/schemas/BalanceResponse"
|
$ref: "#/components/schemas/BalanceResponse"
|
||||||
"404":
|
"404":
|
||||||
description: No ledger with this id
|
description: No ledger with this id
|
||||||
|
/ledgers/{ledgerId}/balance/daily-valuation:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- ledger
|
||||||
|
summary: Get the daily mark-to-market valuation series of a ledger's held balance
|
||||||
|
(items and ISK)
|
||||||
|
operationId: dailyValuationForLedger
|
||||||
|
parameters:
|
||||||
|
- name: ledgerId
|
||||||
|
in: path
|
||||||
|
description: Id of the ledger
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "Daily average/highest/lowest valuation for the ledger, ascending\
|
||||||
|
\ by date. For a combined ledger, this is the per-date sum of its covered\
|
||||||
|
\ main ledgers' valuations."
|
||||||
|
content:
|
||||||
|
'*/*':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/DailyBalanceResponse"
|
||||||
|
"400":
|
||||||
|
description: The ledger is the system ledger
|
||||||
|
"404":
|
||||||
|
description: No ledger with this id
|
||||||
/corporations:
|
/corporations:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- corporation
|
- corporation
|
||||||
summary: "Resolve public information for several corporation ids at once, silently\
|
summary: Resolve public information for several corporation ids at once
|
||||||
\ omitting ids ESI cannot resolve"
|
|
||||||
operationId: findCorporations
|
operationId: findCorporations
|
||||||
parameters:
|
parameters:
|
||||||
- name: ids
|
- name: ids
|
||||||
@@ -1056,13 +1087,15 @@ paths:
|
|||||||
format: int64
|
format: int64
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: The corporations that resolved; unknown ids are omitted
|
description: The resolved corporations
|
||||||
content:
|
content:
|
||||||
'*/*':
|
'*/*':
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/CorporationResponse"
|
$ref: "#/components/schemas/CorporationResponse"
|
||||||
|
"404":
|
||||||
|
description: Returned when no corporation exists for one of the given ids
|
||||||
/corporations/{corporationId}:
|
/corporations/{corporationId}:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1086,7 +1119,7 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/CorporationResponse"
|
$ref: "#/components/schemas/CorporationResponse"
|
||||||
"404":
|
"404":
|
||||||
description: Returned when ESI has no corporation with the given id
|
description: Returned when no corporation exists with the given id
|
||||||
/characters:
|
/characters:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -1119,17 +1152,27 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- acquisition
|
- acquisition
|
||||||
summary: "Find the caller's acquisitions, optionally filtered by ledger, market\
|
summary: "Find the caller's acquisitions, optionally filtered by ledgers, market\
|
||||||
\ type and consumption state"
|
\ type and consumption state"
|
||||||
operationId: findAllAcquisitions
|
operationId: findAllAcquisitions
|
||||||
parameters:
|
parameters:
|
||||||
- name: ledgerId
|
- name: ledgerId
|
||||||
in: query
|
in: query
|
||||||
description: Only return acquisitions held in this ledger
|
description: "Only return acquisitions held in this ledger (deprecated, use\
|
||||||
|
\ ledgerIds)"
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
- name: ledgerIds
|
||||||
|
in: query
|
||||||
|
description: Only return acquisitions held in these ledgers
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
- name: marketTypeId
|
- name: marketTypeId
|
||||||
in: query
|
in: query
|
||||||
description: Only return acquisitions of this market type
|
description: Only return acquisitions of this market type
|
||||||
@@ -2260,6 +2303,36 @@ components:
|
|||||||
required:
|
required:
|
||||||
- quantity
|
- quantity
|
||||||
- typeId
|
- typeId
|
||||||
|
DailyBalanceResponse:
|
||||||
|
type: object
|
||||||
|
description: "Mark-to-market value of a ledger's held balance (items and ISK)\
|
||||||
|
\ for a single day: average, highest and lowest."
|
||||||
|
properties:
|
||||||
|
date:
|
||||||
|
type: string
|
||||||
|
format: date
|
||||||
|
description: The UTC (EVE) day this valuation is for.
|
||||||
|
example: 2026-06-22
|
||||||
|
averageValue:
|
||||||
|
type: number
|
||||||
|
description: ISK balance plus held item balance valued at that day's average
|
||||||
|
price.
|
||||||
|
example: 1.5E8
|
||||||
|
highestValue:
|
||||||
|
type: number
|
||||||
|
description: ISK balance plus held item balance valued at that day's highest
|
||||||
|
price.
|
||||||
|
example: 1.6E8
|
||||||
|
lowestValue:
|
||||||
|
type: number
|
||||||
|
description: ISK balance plus held item balance valued at that day's lowest
|
||||||
|
price.
|
||||||
|
example: 1.4E8
|
||||||
|
required:
|
||||||
|
- averageValue
|
||||||
|
- date
|
||||||
|
- highestValue
|
||||||
|
- lowestValue
|
||||||
CorporationResponse:
|
CorporationResponse:
|
||||||
type: object
|
type: object
|
||||||
description: An EVE Online corporation.
|
description: An EVE Online corporation.
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const select = (item?: T) => {
|
|||||||
const submit = () => {
|
const submit = () => {
|
||||||
if (currentIndex.value >= 0 && currentIndex.value < props.items.length) {
|
if (currentIndex.value >= 0 && currentIndex.value < props.items.length) {
|
||||||
select(props.items[currentIndex.value]);
|
select(props.items[currentIndex.value]);
|
||||||
} else if (modelValue.value === undefined && props.items.length > 0) {
|
} else if (props.items.length > 0) {
|
||||||
select(props.items[0]);
|
select(props.items[0]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+124
-27
@@ -207,6 +207,27 @@ export interface CreateMainLedgerRequest {
|
|||||||
*/
|
*/
|
||||||
'name': string;
|
'name': string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Mark-to-market value of a ledger\'s held balance (items and ISK) for a single day: average, highest and lowest.
|
||||||
|
*/
|
||||||
|
export interface DailyBalanceResponse {
|
||||||
|
/**
|
||||||
|
* The UTC (EVE) day this valuation is for.
|
||||||
|
*/
|
||||||
|
'date': string;
|
||||||
|
/**
|
||||||
|
* ISK balance plus held item balance valued at that day\'s average price.
|
||||||
|
*/
|
||||||
|
'averageValue': number;
|
||||||
|
/**
|
||||||
|
* ISK balance plus held item balance valued at that day\'s highest price.
|
||||||
|
*/
|
||||||
|
'highestValue': number;
|
||||||
|
/**
|
||||||
|
* ISK balance plus held item balance valued at that day\'s lowest price.
|
||||||
|
*/
|
||||||
|
'lowestValue': number;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Profit for a single day: ISK in, ISK out, and their difference.
|
* Profit for a single day: ISK in, ISK out, and their difference.
|
||||||
*/
|
*/
|
||||||
@@ -915,14 +936,15 @@ export const AcquisitionApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find the caller\'s acquisitions, optionally filtered by ledger, market type and consumption state
|
* @summary Find the caller\'s acquisitions, optionally filtered by ledgers, market type and consumption state
|
||||||
* @param {string} [ledgerId] Only return acquisitions held in this ledger
|
* @param {string} [ledgerId] Only return acquisitions held in this ledger (deprecated, use ledgerIds)
|
||||||
|
* @param {Array<string>} [ledgerIds] Only return acquisitions held in these ledgers
|
||||||
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
||||||
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
findAllAcquisitions: async (ledgerId?: string, marketTypeId?: number, includeConsumed?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
findAllAcquisitions: async (ledgerId?: string, ledgerIds?: Array<string>, marketTypeId?: number, includeConsumed?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/acquisitions`;
|
const localVarPath = `/acquisitions`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
@@ -939,6 +961,10 @@ export const AcquisitionApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
localVarQueryParameter['ledgerId'] = ledgerId;
|
localVarQueryParameter['ledgerId'] = ledgerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ledgerIds) {
|
||||||
|
localVarQueryParameter['ledgerIds'] = ledgerIds;
|
||||||
|
}
|
||||||
|
|
||||||
if (marketTypeId !== undefined) {
|
if (marketTypeId !== undefined) {
|
||||||
localVarQueryParameter['marketTypeId'] = marketTypeId;
|
localVarQueryParameter['marketTypeId'] = marketTypeId;
|
||||||
}
|
}
|
||||||
@@ -969,15 +995,16 @@ export const AcquisitionApiFp = function(configuration?: Configuration) {
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find the caller\'s acquisitions, optionally filtered by ledger, market type and consumption state
|
* @summary Find the caller\'s acquisitions, optionally filtered by ledgers, market type and consumption state
|
||||||
* @param {string} [ledgerId] Only return acquisitions held in this ledger
|
* @param {string} [ledgerId] Only return acquisitions held in this ledger (deprecated, use ledgerIds)
|
||||||
|
* @param {Array<string>} [ledgerIds] Only return acquisitions held in these ledgers
|
||||||
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
||||||
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async findAllAcquisitions(ledgerId?: string, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<AcquisitionResponse>>> {
|
async findAllAcquisitions(ledgerId?: string, ledgerIds?: Array<string>, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<AcquisitionResponse>>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.findAllAcquisitions(ledgerId, marketTypeId, includeConsumed, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.findAllAcquisitions(ledgerId, ledgerIds, marketTypeId, includeConsumed, options);
|
||||||
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
const localVarOperationServerBasePath = operationServerMap['AcquisitionApi.findAllAcquisitions']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['AcquisitionApi.findAllAcquisitions']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
@@ -993,15 +1020,16 @@ export const AcquisitionApiFactory = function (configuration?: Configuration, ba
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find the caller\'s acquisitions, optionally filtered by ledger, market type and consumption state
|
* @summary Find the caller\'s acquisitions, optionally filtered by ledgers, market type and consumption state
|
||||||
* @param {string} [ledgerId] Only return acquisitions held in this ledger
|
* @param {string} [ledgerId] Only return acquisitions held in this ledger (deprecated, use ledgerIds)
|
||||||
|
* @param {Array<string>} [ledgerIds] Only return acquisitions held in these ledgers
|
||||||
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
||||||
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
findAllAcquisitions(ledgerId?: string, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig): AxiosPromise<Array<AcquisitionResponse>> {
|
findAllAcquisitions(ledgerId?: string, ledgerIds?: Array<string>, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig): AxiosPromise<Array<AcquisitionResponse>> {
|
||||||
return localVarFp.findAllAcquisitions(ledgerId, marketTypeId, includeConsumed, options).then((request) => request(axios, basePath));
|
return localVarFp.findAllAcquisitions(ledgerId, ledgerIds, marketTypeId, includeConsumed, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -1012,15 +1040,16 @@ export const AcquisitionApiFactory = function (configuration?: Configuration, ba
|
|||||||
export class AcquisitionApi extends BaseAPI {
|
export class AcquisitionApi extends BaseAPI {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find the caller\'s acquisitions, optionally filtered by ledger, market type and consumption state
|
* @summary Find the caller\'s acquisitions, optionally filtered by ledgers, market type and consumption state
|
||||||
* @param {string} [ledgerId] Only return acquisitions held in this ledger
|
* @param {string} [ledgerId] Only return acquisitions held in this ledger (deprecated, use ledgerIds)
|
||||||
|
* @param {Array<string>} [ledgerIds] Only return acquisitions held in these ledgers
|
||||||
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
* @param {number} [marketTypeId] Only return acquisitions of this market type
|
||||||
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
* @param {boolean} [includeConsumed] Include fully consumed acquisitions (no remaining stock)
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
public findAllAcquisitions(ledgerId?: string, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig) {
|
public findAllAcquisitions(ledgerId?: string, ledgerIds?: Array<string>, marketTypeId?: number, includeConsumed?: boolean, options?: RawAxiosRequestConfig) {
|
||||||
return AcquisitionApiFp(this.configuration).findAllAcquisitions(ledgerId, marketTypeId, includeConsumed, options).then((request) => request(this.axios, this.basePath));
|
return AcquisitionApiFp(this.configuration).findAllAcquisitions(ledgerId, ledgerIds, marketTypeId, includeConsumed, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1835,7 +1864,7 @@ export const CorporationApiAxiosParamCreator = function (configuration?: Configu
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
* @summary Resolve public information for several corporation ids at once
|
||||||
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -1894,7 +1923,7 @@ export const CorporationApiFp = function(configuration?: Configuration) {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
* @summary Resolve public information for several corporation ids at once
|
||||||
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -1926,7 +1955,7 @@ export const CorporationApiFactory = function (configuration?: Configuration, ba
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
* @summary Resolve public information for several corporation ids at once
|
||||||
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -1954,7 +1983,7 @@ export class CorporationApi extends BaseAPI {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Resolve public information for several corporation ids at once, silently omitting ids ESI cannot resolve
|
* @summary Resolve public information for several corporation ids at once
|
||||||
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
* @param {Array<number>} ids Corporation ids to resolve, e.g. ids=98000001,98000002
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -2041,6 +2070,40 @@ export const LedgerApiAxiosParamCreator = function (configuration?: Configuratio
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily mark-to-market valuation series of a ledger\'s held balance (items and ISK)
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
dailyValuationForLedger: async (ledgerId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'ledgerId' is not null or undefined
|
||||||
|
assertParamExists('dailyValuationForLedger', 'ledgerId', ledgerId)
|
||||||
|
const localVarPath = `/ledgers/{ledgerId}/balance/daily-valuation`
|
||||||
|
.replace('{ledgerId}', encodeURIComponent(String(ledgerId)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
|
||||||
|
localVarHeaderParameter['Accept'] = '*/*';
|
||||||
|
|
||||||
|
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: toPathString(localVarUrlObj),
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find all ledgers owned by the authenticated user
|
* @summary Find all ledgers owned by the authenticated user
|
||||||
@@ -2252,6 +2315,19 @@ export const LedgerApiFp = function(configuration?: Configuration) {
|
|||||||
const localVarOperationServerBasePath = operationServerMap['LedgerApi.createMainLedger']?.[localVarOperationServerIndex]?.url;
|
const localVarOperationServerBasePath = operationServerMap['LedgerApi.createMainLedger']?.[localVarOperationServerIndex]?.url;
|
||||||
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily mark-to-market valuation series of a ledger\'s held balance (items and ISK)
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async dailyValuationForLedger(ledgerId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<DailyBalanceResponse>>> {
|
||||||
|
const localVarAxiosArgs = await localVarAxiosParamCreator.dailyValuationForLedger(ledgerId, options);
|
||||||
|
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
|
||||||
|
const localVarOperationServerBasePath = operationServerMap['LedgerApi.dailyValuationForLedger']?.[localVarOperationServerIndex]?.url;
|
||||||
|
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find all ledgers owned by the authenticated user
|
* @summary Find all ledgers owned by the authenticated user
|
||||||
@@ -2347,6 +2423,16 @@ export const LedgerApiFactory = function (configuration?: Configuration, basePat
|
|||||||
createMainLedger(createMainLedgerRequest: CreateMainLedgerRequest, options?: RawAxiosRequestConfig): AxiosPromise<MainLedgerResponse> {
|
createMainLedger(createMainLedgerRequest: CreateMainLedgerRequest, options?: RawAxiosRequestConfig): AxiosPromise<MainLedgerResponse> {
|
||||||
return localVarFp.createMainLedger(createMainLedgerRequest, options).then((request) => request(axios, basePath));
|
return localVarFp.createMainLedger(createMainLedgerRequest, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily mark-to-market valuation series of a ledger\'s held balance (items and ISK)
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
dailyValuationForLedger(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<Array<DailyBalanceResponse>> {
|
||||||
|
return localVarFp.dailyValuationForLedger(ledgerId, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find all ledgers owned by the authenticated user
|
* @summary Find all ledgers owned by the authenticated user
|
||||||
@@ -2427,6 +2513,17 @@ export class LedgerApi extends BaseAPI {
|
|||||||
return LedgerApiFp(this.configuration).createMainLedger(createMainLedgerRequest, options).then((request) => request(this.axios, this.basePath));
|
return LedgerApiFp(this.configuration).createMainLedger(createMainLedgerRequest, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary Get the daily mark-to-market valuation series of a ledger\'s held balance (items and ISK)
|
||||||
|
* @param {string} ledgerId Id of the ledger
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
public dailyValuationForLedger(ledgerId: string, options?: RawAxiosRequestConfig) {
|
||||||
|
return LedgerApiFp(this.configuration).dailyValuationForLedger(ledgerId, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Find all ledgers owned by the authenticated user
|
* @summary Find all ledgers owned by the authenticated user
|
||||||
@@ -3639,7 +3736,7 @@ export const ProfitApiAxiosParamCreator = function (configuration?: Configuratio
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily FIFO-realized margin series for a single ledger
|
* @summary Get the daily FIFO-realized margin series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3673,7 +3770,7 @@ export const ProfitApiAxiosParamCreator = function (configuration?: Configuratio
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily profit series for a single ledger
|
* @summary Get the daily profit series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3716,7 +3813,7 @@ export const ProfitApiFp = function(configuration?: Configuration) {
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily FIFO-realized margin series for a single ledger
|
* @summary Get the daily FIFO-realized margin series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3729,7 +3826,7 @@ export const ProfitApiFp = function(configuration?: Configuration) {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily profit series for a single ledger
|
* @summary Get the daily profit series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3751,7 +3848,7 @@ export const ProfitApiFactory = function (configuration?: Configuration, basePat
|
|||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily FIFO-realized margin series for a single ledger
|
* @summary Get the daily FIFO-realized margin series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3761,7 +3858,7 @@ export const ProfitApiFactory = function (configuration?: Configuration, basePat
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily profit series for a single ledger
|
* @summary Get the daily profit series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3778,7 +3875,7 @@ export const ProfitApiFactory = function (configuration?: Configuration, basePat
|
|||||||
export class ProfitApi extends BaseAPI {
|
export class ProfitApi extends BaseAPI {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily FIFO-realized margin series for a single ledger
|
* @summary Get the daily FIFO-realized margin series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
@@ -3789,7 +3886,7 @@ export class ProfitApi extends BaseAPI {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary Get the daily profit series for a single ledger
|
* @summary Get the daily profit series for a single or combined ledger
|
||||||
* @param {string} ledgerId Id of the ledger
|
* @param {string} ledgerId Id of the ledger
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export * from './ledger';
|
export * from './ledger';
|
||||||
export * from './balanceAppraisal';
|
export * from './balanceAppraisal';
|
||||||
|
export * from './statistics';
|
||||||
|
|
||||||
export {default as LedgerLabel} from './LedgerLabel.vue';
|
export {default as LedgerLabel} from './LedgerLabel.vue';
|
||||||
export {default as LedgerSelect} from './LedgerSelect.vue';
|
export {default as LedgerSelect} from './LedgerSelect.vue';
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import {describe, expect, test} from 'vitest';
|
||||||
|
import {latestDailyBalanceValue} from './statistics';
|
||||||
|
import type {DailyBalanceResponse} from '@/generated/mammon';
|
||||||
|
|
||||||
|
const balance = (date: string, averageValue: number): DailyBalanceResponse => ({
|
||||||
|
date, averageValue, highestValue: averageValue, lowestValue: averageValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('latestDailyBalanceValue', () => {
|
||||||
|
test('returns the average value of the most recent day in range', () => {
|
||||||
|
const result = latestDailyBalanceValue([balance('2026-08-01', 100), balance('2026-08-02', 150)]);
|
||||||
|
|
||||||
|
expect(result).toBe(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns zero for an empty range', () => {
|
||||||
|
expect(latestDailyBalanceValue([])).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type {DailyBalanceResponse} from "@/generated/mammon";
|
||||||
|
|
||||||
|
export const StatisticsModes = {
|
||||||
|
CashFlow: 'CASH_FLOW',
|
||||||
|
Margin: 'MARGIN',
|
||||||
|
DailyBalance: 'DAILY_BALANCE',
|
||||||
|
} as const;
|
||||||
|
export type StatisticsMode = typeof StatisticsModes[keyof typeof StatisticsModes];
|
||||||
|
|
||||||
|
export const latestDailyBalanceValue = (range: DailyBalanceResponse[]): number =>
|
||||||
|
range.at(-1)?.averageValue ?? 0;
|
||||||
@@ -55,7 +55,7 @@ const submit = async () => {
|
|||||||
|
|
||||||
select(v);
|
select(v);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
} else if (modelValue.value === undefined && suggestions.value.length > 0) {
|
} else if (suggestions.value.length > 0) {
|
||||||
select(suggestions.value[0]);
|
select(suggestions.value[0]);
|
||||||
await nextTick();
|
await nextTick();
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ watchEffect(async () => {
|
|||||||
<img v-if="modelValue?.id" :src="`https://images.evetech.net/types/${modelValue.id}/icon?size=32`" alt="" />
|
<img v-if="modelValue?.id" :src="`https://images.evetech.net/types/${modelValue.id}/icon?size=32`" alt="" />
|
||||||
<input type="text" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
|
<input type="text" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="suggestions.length > 1" class="z-20 absolute w-96">
|
<div v-if="suggestions.length > 0" class="z-20 absolute w-96">
|
||||||
<div v-bind="containerProps" class="rounded-b" style="height: 300px">
|
<div v-bind="containerProps" class="rounded-b" style="height: 300px">
|
||||||
<div v-bind="wrapperProps">
|
<div v-bind="wrapperProps">
|
||||||
<div v-for="s in list" :key="s.index" class="hover:bg-slate-700" :class="{'bg-slate-500': s.index !== currentIndex, 'bg-emerald-500': s.index === currentIndex}" @click="select(s.data)">
|
<div v-for="s in list" :key="s.index" class="hover:bg-slate-700" :class="{'bg-slate-500': s.index !== currentIndex, 'bg-emerald-500': s.index === currentIndex}" @click="select(s.data)">
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
import {
|
||||||
|
CategoryScale,
|
||||||
|
Chart as ChartJS,
|
||||||
|
type ChartData,
|
||||||
|
type ChartDataset,
|
||||||
|
type ChartOptions,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
LinearScale,
|
||||||
|
LineController,
|
||||||
|
LineElement,
|
||||||
|
PointElement,
|
||||||
|
Tooltip,
|
||||||
|
} from "chart.js";
|
||||||
|
import {Chart} from "vue-chartjs";
|
||||||
|
import {latestDailyBalanceValue} from "@/ledger";
|
||||||
|
import {ledgerApi} from "@/mammon";
|
||||||
|
import {useProcessedResource} from "@/activity";
|
||||||
|
import {DailyBalanceResponse} from "@/generated/mammon";
|
||||||
|
import {IskLabel} from "@/market";
|
||||||
|
import {formatIsk} from "@/formaters";
|
||||||
|
import {DualRangeSlider} from "@/components";
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
CategoryScale, LinearScale,
|
||||||
|
LineController, LineElement, PointElement,
|
||||||
|
Tooltip, Legend, Filler,
|
||||||
|
);
|
||||||
|
|
||||||
|
const props = defineProps<{ ledgerId: string }>();
|
||||||
|
|
||||||
|
const dailyBalances = useProcessedResource<DailyBalanceResponse[]>(async () => {
|
||||||
|
if (!props.ledgerId) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data} = await ledgerApi.dailyValuationForLedger(props.ledgerId);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const dates = computed(() => dailyBalances.value.map(b => b.date));
|
||||||
|
|
||||||
|
const from = ref(0);
|
||||||
|
const to = ref(0);
|
||||||
|
|
||||||
|
watch(dates, d => {
|
||||||
|
from.value = 0;
|
||||||
|
to.value = Math.max(d.length - 1, 0);
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
const maxIndex = computed(() => Math.max(dates.value.length - 1, 0));
|
||||||
|
|
||||||
|
const dailyBalanceRange = computed(() => dailyBalances.value.slice(from.value, to.value + 1));
|
||||||
|
|
||||||
|
const hasData = computed(() => dailyBalances.value.length > 0);
|
||||||
|
|
||||||
|
const baseline = computed(() => dailyBalanceRange.value[0]?.averageValue ?? 0);
|
||||||
|
|
||||||
|
const total = computed(() => latestDailyBalanceValue(dailyBalanceRange.value) - baseline.value);
|
||||||
|
|
||||||
|
const chartData = computed<ChartData<'line'>>(() => {
|
||||||
|
const highest: ChartDataset<'line'> = {
|
||||||
|
label: 'Highest',
|
||||||
|
data: dailyBalanceRange.value.map(b => b.highestValue - baseline.value),
|
||||||
|
borderColor: 'transparent',
|
||||||
|
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
||||||
|
pointRadius: 0,
|
||||||
|
tension: 0.2,
|
||||||
|
fill: '+1',
|
||||||
|
order: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const lowest: ChartDataset<'line'> = {
|
||||||
|
label: 'Lowest',
|
||||||
|
data: dailyBalanceRange.value.map(b => b.lowestValue - baseline.value),
|
||||||
|
borderColor: 'transparent',
|
||||||
|
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
||||||
|
pointRadius: 0,
|
||||||
|
tension: 0.2,
|
||||||
|
fill: false,
|
||||||
|
order: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const average: ChartDataset<'line'> = {
|
||||||
|
type: 'line',
|
||||||
|
label: 'Average',
|
||||||
|
data: dailyBalanceRange.value.map(b => b.averageValue - baseline.value),
|
||||||
|
borderColor: '#38bdf8',
|
||||||
|
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
||||||
|
pointBackgroundColor: ctx => (Number(ctx.dataset.data[ctx.dataIndex]) < 0 ? '#f87171' : '#34d399'),
|
||||||
|
pointBorderColor: ctx => (Number(ctx.dataset.data[ctx.dataIndex]) < 0 ? '#f87171' : '#34d399'),
|
||||||
|
segment: {
|
||||||
|
borderColor: ctx => ((ctx.p0.parsed.y ?? 0) < 0 || (ctx.p1.parsed.y ?? 0) < 0 ? '#f87171' : '#34d399'),
|
||||||
|
},
|
||||||
|
fill: false,
|
||||||
|
tension: 0.2,
|
||||||
|
order: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels: dailyBalanceRange.value.map(b => b.date),
|
||||||
|
datasets: [highest, lowest, average],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartOptions = computed<ChartOptions<'line'>>(() => ({
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
interaction: {mode: 'index', intersect: false},
|
||||||
|
plugins: {
|
||||||
|
legend: {display: true},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: ctx => `${ctx.dataset.label}: ${formatIsk(ctx.parsed.y ?? 0)}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {stacked: false},
|
||||||
|
y: {
|
||||||
|
position: 'left',
|
||||||
|
stacked: false,
|
||||||
|
ticks: {
|
||||||
|
callback: value => formatIsk(Number(value)),
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
lineWidth: ctx => (ctx.tick.value === 0 ? 2 : 1),
|
||||||
|
color: ctx => (ctx.tick.value === 0 ? 'rgba(226, 232, 240, 0.6)' : 'rgba(148, 163, 184, 0.2)'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-end mb-4">
|
||||||
|
<span class="mr-2">Change:</span>
|
||||||
|
<IskLabel :amount="total" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="!hasData" class="text-center text-gray-400 mt-8">No daily balance recorded for this ledger</p>
|
||||||
|
<template v-else>
|
||||||
|
<div class="h-96">
|
||||||
|
<Chart type="line" :data="chartData" :options="chartOptions" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3 mt-4">
|
||||||
|
<span class="text-sm w-24 text-gray-400">{{ dates[from] }}</span>
|
||||||
|
<DualRangeSlider class="grow" :min="0" :max="maxIndex" v-model:from="from" v-model:to="to" />
|
||||||
|
<span class="text-sm w-24 text-right text-gray-400">{{ dates[to] }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, ref, watch} from "vue";
|
||||||
|
import {
|
||||||
|
BarController,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
Chart as ChartJS,
|
||||||
|
type ChartData,
|
||||||
|
type ChartDataset,
|
||||||
|
type ChartOptions,
|
||||||
|
Filler,
|
||||||
|
Legend,
|
||||||
|
LinearScale,
|
||||||
|
LineController,
|
||||||
|
LineElement,
|
||||||
|
PointElement,
|
||||||
|
Tooltip,
|
||||||
|
} from "chart.js";
|
||||||
|
import {Chart} from "vue-chartjs";
|
||||||
|
import {StatisticsModes, type StatisticsMode} from "@/ledger";
|
||||||
|
import {profitApi} from "@/mammon";
|
||||||
|
import {useProcessedResource} from "@/activity";
|
||||||
|
import {DailyProfitResponse} from "@/generated/mammon";
|
||||||
|
import {IskLabel} from "@/market";
|
||||||
|
import {formatIsk} from "@/formaters";
|
||||||
|
import {DualRangeSlider} from "@/components";
|
||||||
|
|
||||||
|
ChartJS.register(
|
||||||
|
CategoryScale, LinearScale,
|
||||||
|
BarController, BarElement,
|
||||||
|
LineController, LineElement, PointElement,
|
||||||
|
Tooltip, Legend, Filler,
|
||||||
|
);
|
||||||
|
|
||||||
|
const props = defineProps<{ ledgerId: string; mode: StatisticsMode }>();
|
||||||
|
|
||||||
|
const profits = useProcessedResource<DailyProfitResponse[]>(async () => {
|
||||||
|
if (!props.ledgerId) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const {data} = props.mode === StatisticsModes.Margin
|
||||||
|
? await profitApi.marginPerDayInLedger(props.ledgerId)
|
||||||
|
: await profitApi.profitPerDayInLedger(props.ledgerId);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const dates = computed(() => profits.value.map(p => p.date));
|
||||||
|
|
||||||
|
const from = ref(0);
|
||||||
|
const to = ref(0);
|
||||||
|
|
||||||
|
watch(dates, d => {
|
||||||
|
from.value = 0;
|
||||||
|
to.value = Math.max(d.length - 1, 0);
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
const maxIndex = computed(() => Math.max(dates.value.length - 1, 0));
|
||||||
|
|
||||||
|
const profitRange = computed(() => profits.value.slice(from.value, to.value + 1));
|
||||||
|
|
||||||
|
const total = computed(() => profitRange.value.reduce((sum, p) => sum + p.profit, 0));
|
||||||
|
|
||||||
|
const hasData = computed(() => profits.value.length > 0);
|
||||||
|
|
||||||
|
const cumulativeProfit = computed(() => {
|
||||||
|
let running = 0;
|
||||||
|
|
||||||
|
return profitRange.value.map(p => (running += p.profit));
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartData = computed<ChartData<'bar' | 'line'>>(() => {
|
||||||
|
const cumulative: ChartDataset<'line'> = {
|
||||||
|
type: 'line',
|
||||||
|
label: 'Cumulative profit',
|
||||||
|
data: cumulativeProfit.value,
|
||||||
|
borderColor: '#38bdf8',
|
||||||
|
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
||||||
|
pointBackgroundColor: '#38bdf8',
|
||||||
|
fill: true,
|
||||||
|
tension: 0.2,
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const iskIn: ChartDataset<'bar'> = {
|
||||||
|
type: 'bar',
|
||||||
|
label: 'ISK in',
|
||||||
|
data: profitRange.value.map(p => p.iskIn),
|
||||||
|
backgroundColor: 'rgba(16, 185, 129, 0.7)',
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const iskOut: ChartDataset<'bar'> = {
|
||||||
|
type: 'bar',
|
||||||
|
label: 'ISK out',
|
||||||
|
data: profitRange.value.map(p => -p.iskOut),
|
||||||
|
backgroundColor: 'rgba(180, 83, 9, 0.7)',
|
||||||
|
yAxisID: 'y',
|
||||||
|
order: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels: profitRange.value.map(p => p.date),
|
||||||
|
datasets: [cumulative, iskIn, iskOut],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartOptions = computed<ChartOptions<'bar' | 'line'>>(() => ({
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
interaction: {mode: 'index', intersect: false},
|
||||||
|
plugins: {
|
||||||
|
legend: {display: true},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: ctx => `${ctx.dataset.label}: ${formatIsk(ctx.parsed.y ?? 0)}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {stacked: true},
|
||||||
|
y: {
|
||||||
|
position: 'left',
|
||||||
|
stacked: true,
|
||||||
|
ticks: {
|
||||||
|
callback: value => formatIsk(Number(value)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex justify-end mb-4">
|
||||||
|
<span class="mr-2">Total profit:</span>
|
||||||
|
<IskLabel :amount="total" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="!hasData" class="text-center text-gray-400 mt-8">No trade profit recorded for this ledger</p>
|
||||||
|
<template v-else>
|
||||||
|
<div class="h-96">
|
||||||
|
<Chart type="bar" :data="chartData" :options="chartOptions" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-3 mt-4">
|
||||||
|
<span class="text-sm w-24 text-gray-400">{{ dates[from] }}</span>
|
||||||
|
<DualRangeSlider class="grow" :min="0" :max="maxIndex" v-model:from="from" v-model:to="to" />
|
||||||
|
<span class="text-sm w-24 text-right text-gray-400">{{ dates[to] }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {RouterLink, RouterView} from 'vue-router';
|
import {RouterLink, RouterView} from 'vue-router';
|
||||||
import {appraiseItemBalances, getLedgerBalance, isMain, LedgerLabel, useLedgerParam} from "@/ledger";
|
import {appraiseItemBalances, getLedgerBalance, LedgerLabel, useLedgerParam} from "@/ledger";
|
||||||
import {routeNames} from "@/routes.ts";
|
import {routeNames} from "@/routes.ts";
|
||||||
import {getMarketTypes, getPrices, IskLabel} from "@/market";
|
import {getMarketTypes, getPrices, IskLabel} from "@/market";
|
||||||
import {useMarketLocationStore} from '@/market/location';
|
import {useMarketLocationStore} from '@/market/location';
|
||||||
@@ -53,7 +53,7 @@ const itemAppraisal = computedAsync(async () => {
|
|||||||
<RouterLink :to="{name: routeNames.listLedgerAcquisitions}" class="tab">
|
<RouterLink :to="{name: routeNames.listLedgerAcquisitions}" class="tab">
|
||||||
<span>Acquisitions</span>
|
<span>Acquisitions</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<RouterLink v-if="isMain(ledger)" :to="{name: routeNames.viewLedgerStatistics}" class="tab">
|
<RouterLink :to="{name: routeNames.viewLedgerStatistics}" class="tab">
|
||||||
<span>Statistics</span>
|
<span>Statistics</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,174 +1,33 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, ref, watch} from "vue";
|
import {ref} from "vue";
|
||||||
import {
|
import {StatisticsModes, type StatisticsMode, useLedgerParam} from "@/ledger";
|
||||||
BarController,
|
import DailyBalanceChart from "./DailyBalanceChart.vue";
|
||||||
BarElement,
|
import ProfitChart from "./ProfitChart.vue";
|
||||||
CategoryScale,
|
|
||||||
Chart as ChartJS,
|
|
||||||
type ChartData,
|
|
||||||
type ChartDataset,
|
|
||||||
type ChartOptions,
|
|
||||||
Filler,
|
|
||||||
Legend,
|
|
||||||
LinearScale,
|
|
||||||
LineController,
|
|
||||||
LineElement,
|
|
||||||
PointElement,
|
|
||||||
Tooltip,
|
|
||||||
} from "chart.js";
|
|
||||||
import {Chart} from "vue-chartjs";
|
|
||||||
import {useLedgerParam} from "@/ledger";
|
|
||||||
import {profitApi} from "@/mammon";
|
|
||||||
import {useProcessedResource} from "@/activity";
|
|
||||||
import {DailyProfitResponse} from "@/generated/mammon";
|
|
||||||
import {IskLabel} from "@/market";
|
|
||||||
import {formatIsk} from "@/formaters";
|
|
||||||
import {DualRangeSlider} from "@/components";
|
|
||||||
|
|
||||||
ChartJS.register(
|
const {ledgerId, ledger} = useLedgerParam();
|
||||||
CategoryScale, LinearScale,
|
|
||||||
BarController, BarElement,
|
|
||||||
LineController, LineElement, PointElement,
|
|
||||||
Tooltip, Legend, Filler,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {ledgerId} = useLedgerParam();
|
const mode = ref<StatisticsMode>(StatisticsModes.DailyBalance);
|
||||||
|
|
||||||
const ProfitModes = {
|
const isDailyBalance = (mode: StatisticsMode): mode is typeof StatisticsModes.DailyBalance =>
|
||||||
CashFlow: 'CASH_FLOW',
|
mode === StatisticsModes.DailyBalance;
|
||||||
Margin: 'MARGIN',
|
|
||||||
} as const;
|
|
||||||
type ProfitMode = typeof ProfitModes[keyof typeof ProfitModes];
|
|
||||||
|
|
||||||
const mode = ref<ProfitMode>(ProfitModes.CashFlow);
|
|
||||||
|
|
||||||
const profits = useProcessedResource<DailyProfitResponse[]>(async () => {
|
|
||||||
if (!ledgerId.value) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const {data} = mode.value === ProfitModes.Margin
|
|
||||||
? await profitApi.marginPerDayInLedger(ledgerId.value)
|
|
||||||
: await profitApi.profitPerDayInLedger(ledgerId.value);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const from = ref(0);
|
|
||||||
const to = ref(0);
|
|
||||||
|
|
||||||
watch(() => profits.value.length, length => {
|
|
||||||
from.value = 0;
|
|
||||||
to.value = Math.max(length - 1, 0);
|
|
||||||
}, {immediate: true});
|
|
||||||
|
|
||||||
const maxIndex = computed(() => Math.max(profits.value.length - 1, 0));
|
|
||||||
|
|
||||||
const range = computed(() => profits.value.slice(from.value, to.value + 1));
|
|
||||||
|
|
||||||
const total = computed(() => range.value.reduce((sum, p) => sum + p.profit, 0));
|
|
||||||
|
|
||||||
const cumulativeProfit = computed(() => {
|
|
||||||
let running = 0;
|
|
||||||
|
|
||||||
return range.value.map(p => (running += p.profit));
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartData = computed<ChartData<'bar' | 'line'>>(() => {
|
|
||||||
const cumulative: ChartDataset<'line'> = {
|
|
||||||
type: 'line',
|
|
||||||
label: 'Cumulative profit',
|
|
||||||
data: cumulativeProfit.value,
|
|
||||||
borderColor: '#38bdf8',
|
|
||||||
backgroundColor: 'rgba(56, 189, 248, 0.15)',
|
|
||||||
pointBackgroundColor: '#38bdf8',
|
|
||||||
fill: true,
|
|
||||||
tension: 0.2,
|
|
||||||
yAxisID: 'y',
|
|
||||||
order: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const iskIn: ChartDataset<'bar'> = {
|
|
||||||
type: 'bar',
|
|
||||||
label: 'ISK in',
|
|
||||||
data: range.value.map(p => p.iskIn),
|
|
||||||
backgroundColor: 'rgba(16, 185, 129, 0.7)',
|
|
||||||
yAxisID: 'y',
|
|
||||||
order: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const iskOut: ChartDataset<'bar'> = {
|
|
||||||
type: 'bar',
|
|
||||||
label: 'ISK out',
|
|
||||||
data: range.value.map(p => -p.iskOut),
|
|
||||||
backgroundColor: 'rgba(180, 83, 9, 0.7)',
|
|
||||||
yAxisID: 'y',
|
|
||||||
order: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
labels: range.value.map(p => p.date),
|
|
||||||
datasets: [cumulative, iskIn, iskOut],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartOptions = computed<ChartOptions<'bar' | 'line'>>(() => ({
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
interaction: {mode: 'index', intersect: false},
|
|
||||||
plugins: {
|
|
||||||
legend: {display: true},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
label: ctx => `${ctx.dataset.label}: ${formatIsk(Math.abs(ctx.parsed.y ?? 0))}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
stacked: true,
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
position: 'left',
|
|
||||||
stacked: true,
|
|
||||||
ticks: {
|
|
||||||
callback: value => formatIsk(Math.abs(Number(value))),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mt-4">
|
<div v-if="ledger" class="mt-4">
|
||||||
<div class="flex justify-center mb-4">
|
<div class="flex justify-center mb-4">
|
||||||
<div class="flex bg-slate-600 rounded-s-md p-1">
|
<div class="flex bg-slate-600 rounded-s-md p-1">
|
||||||
<button class="switch" :class="{active: mode === ProfitModes.CashFlow}" @click="mode = ProfitModes.CashFlow">Cash Flow</button>
|
<button class="switch" :class="{active: mode === StatisticsModes.DailyBalance}" @click="mode = StatisticsModes.DailyBalance">Daily Balance</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="switch flex bg-slate-600 rounded-e-md p-1">
|
<div class="flex bg-slate-600 p-1">
|
||||||
<button class="switch" :class="{active: mode === ProfitModes.Margin}" @click="mode = ProfitModes.Margin">Margin</button>
|
<button class="switch" :class="{active: mode === StatisticsModes.Margin}" @click="mode = StatisticsModes.Margin">Margin</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex bg-slate-600 rounded-e-md p-1">
|
||||||
|
<button class="switch" :class="{active: mode === StatisticsModes.CashFlow}" @click="mode = StatisticsModes.CashFlow">Cash Flow</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end mb-4">
|
<DailyBalanceChart v-if="isDailyBalance(mode)" :ledger-id="ledgerId" />
|
||||||
<span class="mr-2">Total profit:</span>
|
<ProfitChart v-else :ledger-id="ledgerId" :mode="mode" />
|
||||||
<IskLabel :amount="total" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p v-if="profits.length === 0" class="text-center text-gray-400 mt-8">
|
|
||||||
No trade profit recorded for this ledger
|
|
||||||
</p>
|
|
||||||
<template v-else>
|
|
||||||
<div class="h-96">
|
|
||||||
<Chart type="bar" :data="chartData" :options="chartOptions" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3 mt-4">
|
|
||||||
<span class="text-sm w-24 text-gray-400">{{ profits[from]?.date }}</span>
|
|
||||||
<DualRangeSlider class="grow" :min="0" :max="maxIndex" v-model:from="from" v-model:to="to" />
|
|
||||||
<span class="text-sm w-24 text-right text-gray-400">{{ profits[to]?.date }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -182,4 +41,3 @@ button.switch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
Reference in new issue
Block a user