Thomas Kaul
4 months ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with
58 additions and
57 deletions
-
CHANGELOG.md
-
README.md
-
apps/api/src/app/export/export.service.ts
-
apps/api/src/app/import/import.service.ts
-
apps/api/src/app/order/create-order.dto.ts
-
apps/api/src/app/order/order.controller.ts
-
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts
-
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts
-
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
-
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
-
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
-
apps/client/src/app/services/import-activities.service.ts
-
libs/common/src/lib/interfaces/export.interface.ts
-
test/import/ok/500-activities.json
-
test/import/ok/btceur.json
-
test/import/ok/btcusd.json
-
test/import/ok/derived-currency.json
-
test/import/ok/sample.json
-
test/import/ok/vti-buy-long-history.json
|
|
|
@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 |
|
|
|
|
|
|
|
## Unreleased |
|
|
|
|
|
|
|
### Added |
|
|
|
|
|
|
|
- Extended the activities import documentation by the tags |
|
|
|
|
|
|
|
### Changed |
|
|
|
|
|
|
|
- Changed `tags` to `tagIds` in the activities import and export |
|
|
|
- Refactored the _ZEN_ page to standalone |
|
|
|
|
|
|
|
## 2.194.0 - 2025-08-27 |
|
|
|
|
|
|
|
@ -222,7 +222,7 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/<INSERT_SECURITY_TO |
|
|
|
``` |
|
|
|
|
|
|
|
| Field | Type | Description | |
|
|
|
| ------------ | ------------------- | ------------------------------------------------------------------- | |
|
|
|
| ------------ | --------------------- | ------------------------------------------------------------------- | |
|
|
|
| `accountId` | `string` (optional) | Id of the account | |
|
|
|
| `comment` | `string` (optional) | Comment of the activity | |
|
|
|
| `currency` | `string` | `CHF` \| `EUR` \| `USD` etc. | |
|
|
|
@ -231,6 +231,7 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/<INSERT_SECURITY_TO |
|
|
|
| `fee` | `number` | Fee of the activity | |
|
|
|
| `quantity` | `number` | Quantity of the activity | |
|
|
|
| `symbol` | `string` | Symbol of the activity (suitable for `dataSource`) | |
|
|
|
| `tagIds` | `string[]` (optional) | Ids of the tags | |
|
|
|
| `type` | `string` | `BUY` \| `DIVIDEND` \| `FEE` \| `INTEREST` \| `LIABILITY` \| `SELL` | |
|
|
|
| `unitPrice` | `number` | Price per unit of the activity | |
|
|
|
|
|
|
|
|
|
|
|
@ -237,7 +237,7 @@ export class ExportService { |
|
|
|
dataSource: SymbolProfile.dataSource, |
|
|
|
date: date.toISOString(), |
|
|
|
symbol: SymbolProfile.symbol, |
|
|
|
tags: currentTags.map(({ id: tagId }) => { |
|
|
|
tagId: currentTags.map(({ id: tagId }) => { |
|
|
|
return tagId; |
|
|
|
}) |
|
|
|
}; |
|
|
|
|
|
|
|
@ -365,7 +365,7 @@ export class ImportService { |
|
|
|
} |
|
|
|
|
|
|
|
// If a new tag is created, then update the tag ID in all activities
|
|
|
|
activity.tags = (activity.tags ?? []).map((tagId) => { |
|
|
|
activity.tagIds = (activity.tagIds ?? []).map((tagId) => { |
|
|
|
return tagIdMapping[tagId] ?? tagId; |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -630,7 +630,7 @@ export class ImportService { |
|
|
|
fee, |
|
|
|
quantity, |
|
|
|
symbol, |
|
|
|
tags, |
|
|
|
tagIds, |
|
|
|
type, |
|
|
|
unitPrice |
|
|
|
}) => { |
|
|
|
@ -663,6 +663,7 @@ export class ImportService { |
|
|
|
error, |
|
|
|
fee, |
|
|
|
quantity, |
|
|
|
tagIds, |
|
|
|
type, |
|
|
|
unitPrice, |
|
|
|
SymbolProfile: { |
|
|
|
@ -679,8 +680,7 @@ export class ImportService { |
|
|
|
isActive: true, |
|
|
|
sectors: undefined, |
|
|
|
updatedAt: undefined |
|
|
|
}, |
|
|
|
tagIds: tags |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
); |
|
|
|
@ -745,7 +745,8 @@ export class ImportService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { |
|
|
|
if (assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { |
|
|
|
} else { |
|
|
|
const assetProfile = { |
|
|
|
currency, |
|
|
|
...( |
|
|
|
|
|
|
|
@ -64,7 +64,7 @@ export class CreateOrderDto { |
|
|
|
|
|
|
|
@IsArray() |
|
|
|
@IsOptional() |
|
|
|
tags?: string[]; |
|
|
|
tagIds?: string[]; |
|
|
|
|
|
|
|
@IsEnum(Type, { each: true }) |
|
|
|
type: Type; |
|
|
|
|
|
|
|
@ -217,7 +217,7 @@ export class OrderController { |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
tags: data.tags?.map((id) => { |
|
|
|
tags: data.tagIds?.map((id) => { |
|
|
|
return { id }; |
|
|
|
}), |
|
|
|
user: { connect: { id: this.request.user.id } }, |
|
|
|
|
|
|
|
@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po |
|
|
|
import { parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
|
|
|
|
|
import { Tag } from '@prisma/client'; |
|
|
|
import { Big } from 'big.js'; |
|
|
|
import { join } from 'path'; |
|
|
|
|
|
|
|
@ -109,9 +108,6 @@ describe('PortfolioCalculator', () => { |
|
|
|
name: 'Bitcoin', |
|
|
|
symbol: activity.symbol |
|
|
|
}, |
|
|
|
tags: activity.tags?.map((id) => { |
|
|
|
return { id } as Tag; |
|
|
|
}), |
|
|
|
unitPriceInAssetProfileCurrency: 44558.42 |
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po |
|
|
|
import { parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
|
|
|
|
|
import { Tag } from '@prisma/client'; |
|
|
|
import { Big } from 'big.js'; |
|
|
|
import { join } from 'path'; |
|
|
|
|
|
|
|
@ -109,9 +108,6 @@ describe('PortfolioCalculator', () => { |
|
|
|
name: 'Bitcoin', |
|
|
|
symbol: activity.symbol |
|
|
|
}, |
|
|
|
tags: activity.tags?.map((id) => { |
|
|
|
return { id } as Tag; |
|
|
|
}), |
|
|
|
unitPriceInAssetProfileCurrency: 44558.42 |
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po |
|
|
|
import { parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
|
|
|
|
|
import { Tag } from '@prisma/client'; |
|
|
|
import { Big } from 'big.js'; |
|
|
|
import { join } from 'path'; |
|
|
|
|
|
|
|
@ -112,9 +111,6 @@ describe('PortfolioCalculator', () => { |
|
|
|
name: 'Novartis AG', |
|
|
|
symbol: activity.symbol |
|
|
|
}, |
|
|
|
tags: activity.tags?.map((id) => { |
|
|
|
return { id } as Tag; |
|
|
|
}), |
|
|
|
unitPriceInAssetProfileCurrency: activity.unitPrice |
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
@ -18,7 +18,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po |
|
|
|
import { parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
|
|
|
|
|
import { Tag } from '@prisma/client'; |
|
|
|
import { Big } from 'big.js'; |
|
|
|
import { join } from 'path'; |
|
|
|
|
|
|
|
@ -112,9 +111,6 @@ describe('PortfolioCalculator', () => { |
|
|
|
name: 'Novartis AG', |
|
|
|
symbol: activity.symbol |
|
|
|
}, |
|
|
|
tags: activity.tags?.map((id) => { |
|
|
|
return { id } as Tag; |
|
|
|
}), |
|
|
|
unitPriceInAssetProfileCurrency: activity.unitPrice |
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
@ -523,7 +523,7 @@ export class GfCreateOrUpdateActivityDialog implements OnDestroy { |
|
|
|
? undefined |
|
|
|
: this.activityForm.get('searchSymbol')?.value?.symbol) ?? |
|
|
|
this.activityForm.get('name')?.value, |
|
|
|
tags: this.activityForm.get('tags').value?.map(({ id }) => { |
|
|
|
tagIds: this.activityForm.get('tags').value?.map(({ id }) => { |
|
|
|
return id; |
|
|
|
}), |
|
|
|
type: this.activityForm.get('type').value, |
|
|
|
|
|
|
|
@ -146,7 +146,7 @@ export class ImportActivitiesService { |
|
|
|
fee, |
|
|
|
quantity, |
|
|
|
SymbolProfile, |
|
|
|
tags, |
|
|
|
tagIds, |
|
|
|
type, |
|
|
|
unitPrice, |
|
|
|
updateAccountBalance |
|
|
|
@ -156,16 +156,14 @@ export class ImportActivitiesService { |
|
|
|
comment, |
|
|
|
fee, |
|
|
|
quantity, |
|
|
|
tagIds, |
|
|
|
type, |
|
|
|
unitPrice, |
|
|
|
updateAccountBalance, |
|
|
|
currency: currency ?? SymbolProfile.currency, |
|
|
|
dataSource: SymbolProfile.dataSource, |
|
|
|
date: date.toString(), |
|
|
|
symbol: SymbolProfile.symbol, |
|
|
|
tags: tags?.map(({ id }) => { |
|
|
|
return id; |
|
|
|
}) |
|
|
|
symbol: SymbolProfile.symbol |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1,7 +1,8 @@ |
|
|
|
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; |
|
|
|
|
|
|
|
import { |
|
|
|
Account, |
|
|
|
DataSource, |
|
|
|
Order, |
|
|
|
Platform, |
|
|
|
SymbolProfile, |
|
|
|
Tag |
|
|
|
@ -15,14 +16,20 @@ export interface Export { |
|
|
|
balances: AccountBalance[]; |
|
|
|
})[]; |
|
|
|
activities: (Omit< |
|
|
|
Order, |
|
|
|
Activity, |
|
|
|
| 'accountUserId' |
|
|
|
| 'createdAt' |
|
|
|
| 'date' |
|
|
|
| 'feeInAssetProfileCurrency' |
|
|
|
| 'feeInBaseCurrency' |
|
|
|
| 'isDraft' |
|
|
|
| 'symbolProfileId' |
|
|
|
| 'tags' |
|
|
|
| 'unitPriceInAssetProfileCurrency' |
|
|
|
| 'updatedAt' |
|
|
|
| 'userId' |
|
|
|
| 'value' |
|
|
|
| 'valueInBaseCurrency' |
|
|
|
> & { dataSource: DataSource; date: string; symbol: string })[]; |
|
|
|
assetProfiles: (Omit< |
|
|
|
SymbolProfile, |
|
|
|
|
|
|
|
@ -14,7 +14,7 @@ |
|
|
|
} |
|
|
|
], |
|
|
|
"platforms": [], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
|
|
|
|
@ -5,7 +5,7 @@ |
|
|
|
}, |
|
|
|
"accounts": [], |
|
|
|
"platforms": [], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"accountId": null, |
|
|
|
@ -18,7 +18,7 @@ |
|
|
|
"dataSource": "YAHOO", |
|
|
|
"date": "2021-12-12T00:00:00.000Z", |
|
|
|
"symbol": "BTCUSD", |
|
|
|
"tags": [] |
|
|
|
"tagIds": [] |
|
|
|
} |
|
|
|
], |
|
|
|
"user": { |
|
|
|
|
|
|
|
@ -5,7 +5,7 @@ |
|
|
|
}, |
|
|
|
"accounts": [], |
|
|
|
"platforms": [], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"accountId": null, |
|
|
|
@ -18,7 +18,7 @@ |
|
|
|
"dataSource": "YAHOO", |
|
|
|
"date": "2021-12-12T00:00:00.000Z", |
|
|
|
"symbol": "BTCUSD", |
|
|
|
"tags": [] |
|
|
|
"tagIds": [] |
|
|
|
} |
|
|
|
], |
|
|
|
"user": { |
|
|
|
|
|
|
|
@ -14,7 +14,7 @@ |
|
|
|
} |
|
|
|
], |
|
|
|
"platforms": [], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
|
|
|
|
@ -77,7 +77,12 @@ |
|
|
|
"url": "https://interactivebrokers.com" |
|
|
|
} |
|
|
|
], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [ |
|
|
|
{ |
|
|
|
"id": "7314654b-46a7-48a4-b6b9-4895b45ea107", |
|
|
|
"name": "CORE" |
|
|
|
} |
|
|
|
], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
@ -90,7 +95,7 @@ |
|
|
|
"dataSource": "MANUAL", |
|
|
|
"date": "2021-09-01T00:00:00.000Z", |
|
|
|
"symbol": "14a69cb9-1e31-43fa-b320-83703d8ed74b", |
|
|
|
"tags": [] |
|
|
|
"tagIds": [] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
@ -103,7 +108,7 @@ |
|
|
|
"dataSource": "YAHOO", |
|
|
|
"date": "2021-09-16T00:00:00.000Z", |
|
|
|
"symbol": "MSFT", |
|
|
|
"tags": [] |
|
|
|
"tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
@ -116,7 +121,7 @@ |
|
|
|
"dataSource": "YAHOO", |
|
|
|
"date": "2021-11-17T00:00:00.000Z", |
|
|
|
"symbol": "MSFT", |
|
|
|
"tags": [] |
|
|
|
"tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"accountId": null, |
|
|
|
@ -129,7 +134,7 @@ |
|
|
|
"dataSource": "MANUAL", |
|
|
|
"date": "2022-01-01T00:00:00.000Z", |
|
|
|
"symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", |
|
|
|
"tags": [] |
|
|
|
"tagIds": [] |
|
|
|
}, |
|
|
|
{ |
|
|
|
"accountId": "b2d3fe1d-d6a8-41a3-be39-07ef5e9480f0", |
|
|
|
@ -142,7 +147,7 @@ |
|
|
|
"dataSource": "YAHOO", |
|
|
|
"date": "2050-06-06T00:00:00.000Z", |
|
|
|
"symbol": "MSFT", |
|
|
|
"tags": [] |
|
|
|
"tagIds": ["7314654b-46a7-48a4-b6b9-4895b45ea107"] |
|
|
|
} |
|
|
|
], |
|
|
|
"user": { |
|
|
|
|
|
|
|
@ -5,7 +5,7 @@ |
|
|
|
}, |
|
|
|
"accounts": [], |
|
|
|
"platforms": [], |
|
|
|
"tags": [], |
|
|
|
"tagIds": [], |
|
|
|
"activities": [ |
|
|
|
{ |
|
|
|
"fee": 0, |
|
|
|
|