diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b4cbf4495..ad28005494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Simplified the portfolio summary by hiding the currency on mobile +- Improved the language localization for Catalan (`ca`) + +### Fixed + +- Fixed the wrapping of the name column in the accounts table component on mobile +- Fixed the sorting of the watchlist for asset profiles without a name + +## 3.73.0 - 2026-09-26 + +### Changed + +- Improved the server of the Model Context Protocol (MCP) to list only the tools covered by the scopes of the access (experimental) +- Refreshed the cryptocurrencies list +- Improved the language localization for Catalan (`ca`) +- Upgraded `@rekog/mcp-nest` from version `2.0.2` to `2.0.7` - Upgraded `bull-board` from version `9.9.0` to `9.10.1` - Upgraded `zod` from version `4.5.4` to `4.6.5` ### Fixed -- Fixed the sorting of the watchlist for asset profiles without a name +- Fixed the value of the holdings excluded from analysis in the portfolio summary ## 3.72.0 - 2026-09-20 diff --git a/README.md b/README.md index c98c163c40..b9352e3bd3 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ docker compose -f docker/docker-compose.build.yml up -d ### Home Server Systems (Community) -Ghostfolio is available for various home server systems, including [CasaOS](https://github.com/bigbeartechworld/big-bear-casaos), [Home Assistant](https://github.com/lildude/ha-addon-ghostfolio), [Runtipi](https://www.runtipi.io/docs/apps-available), [TrueCharts](https://truecharts.org/charts/stable/ghostfolio), [Umbrel](https://apps.umbrel.com/app/ghostfolio), and [Unraid](https://unraid.net/community/apps?q=ghostfolio). +Ghostfolio is available for various home server systems, including [CasaOS](https://github.com/bigbeartechworld/big-bear-casaos), [Easypanel](https://easypanel.io/templates/ghostfolio), [Home Assistant](https://github.com/lildude/ha-addon-ghostfolio), [Runtipi](https://www.runtipi.io/docs/apps-available), [TrueCharts](https://truecharts.org/charts/stable/ghostfolio), [Umbrel](https://apps.umbrel.com/app/ghostfolio), and [Unraid](https://unraid.net/community/apps?q=ghostfolio). ## Development diff --git a/apps/api/src/app/auth-device/auth-device.controller.ts b/apps/api/src/app/auth-device/auth-device.controller.ts index 45f7925ad6..509746ca97 100644 --- a/apps/api/src/app/auth-device/auth-device.controller.ts +++ b/apps/api/src/app/auth-device/auth-device.controller.ts @@ -3,7 +3,7 @@ import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-durin import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { permissions } from '@ghostfolio/common/permissions'; -import { RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Controller, diff --git a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts index 1db09f95e0..58f19800e8 100644 --- a/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts +++ b/apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts @@ -17,7 +17,7 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions'; -import { RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts index cd330f6911..b1b7f24e79 100644 --- a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts @@ -12,7 +12,7 @@ import { QuotesResponse } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import { RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Controller, diff --git a/apps/api/src/app/endpoints/market-data/market-data.controller.ts b/apps/api/src/app/endpoints/market-data/market-data.controller.ts index 6f7583acf3..73c8ad4451 100644 --- a/apps/api/src/app/endpoints/market-data/market-data.controller.ts +++ b/apps/api/src/app/endpoints/market-data/market-data.controller.ts @@ -8,7 +8,7 @@ import { UpdateBulkMarketDataDto } from '@ghostfolio/common/dtos'; import { getCurrencyFromSymbol, isCurrency } from '@ghostfolio/common/helper'; import { MarketDataOfMarketsResponse } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, diff --git a/apps/api/src/app/endpoints/mcp/mcp.controller.spec.ts b/apps/api/src/app/endpoints/mcp/mcp.controller.spec.ts index f6e1d04383..4fcb92a9be 100644 --- a/apps/api/src/app/endpoints/mcp/mcp.controller.spec.ts +++ b/apps/api/src/app/endpoints/mcp/mcp.controller.spec.ts @@ -1,13 +1,26 @@ import { REQUIRES_SCOPE_KEY } from '@ghostfolio/api/decorators/requires-scope.decorator'; import { McpToolExceptionFilter } from '@ghostfolio/api/filters/mcp-tool-exception.filter'; import { AccessGuard } from '@ghostfolio/api/guards/access.guard'; -import { Scope, scopes } from '@ghostfolio/common/scopes'; +import { getMcpUserOfBearerToken } from '@ghostfolio/api/helper/bearer-token.helper'; +import { + getScopesOfAccess, + getScopesOfAccessLevel, + Scope, + scopes +} from '@ghostfolio/common/scopes'; import { EXCEPTION_FILTERS_METADATA, GUARDS_METADATA } from '@nestjs/common/constants'; -import { MCP_TOOL_METADATA_KEY, ToolMetadata } from '@rekog/mcp-nest'; +import { + AccessMatchMode, + MCP_SCOPES_MATCH_METADATA_KEY, + MCP_SCOPES_METADATA_KEY, + MCP_TOOL_METADATA_KEY, + ToolAuthorizationService, + ToolMetadata +} from '@rekog/mcp-nest'; import { GhostfolioMcpController } from './mcp.controller'; @@ -35,6 +48,41 @@ function getToolMethodNames() { ); } +/** + * Gives the names of the tools which the transport lists for the request. The + * metadata of each tool is read as the transport reads it. + */ +function getNamesOfListedTools(request: unknown) { + const toolAuthorizationService = new ToolAuthorizationService(); + const user = getMcpUserOfBearerToken(request); + + return getToolMethodNames() + .map((methodName) => { + return { + metadata: { + ...getMetadataOfMethod( + MCP_TOOL_METADATA_KEY, + methodName + ), + requiredScopes: getMetadataOfMethod( + MCP_SCOPES_METADATA_KEY, + methodName + ), + requiredScopesMatch: getMetadataOfMethod( + MCP_SCOPES_MATCH_METADATA_KEY, + methodName + ) + } + }; + }) + .filter((tool) => { + return toolAuthorizationService.canAccessTool(user, tool); + }) + .map(({ metadata: { name } }) => { + return name; + }); +} + describe('GhostfolioMcpController', () => { // A tool without the decorator of the scope would be open to every access, // hence a new tool has to declare its scope @@ -71,6 +119,59 @@ describe('GhostfolioMcpController', () => { expect(toolMethodNamesWithoutGuardOfAccess).toEqual([]); }); + it('Lists only the tools to read for an access with the permission "Restricted view"', () => { + expect( + getNamesOfListedTools({ + impersonationOfBearerToken: { + isActive: true, + scopes: getScopesOfAccess({ + scopes: getScopesOfAccessLevel('READ_RESTRICTED'), + type: 'MCP' + }) + } + }) + ).toEqual([ + 'get-accounts', + 'get-activities', + 'get-portfolio', + 'get-watchlist' + ]); + }); + + it('Lists every tool for an access with the permission "Restricted view and manage"', () => { + expect( + getNamesOfListedTools({ + impersonationOfBearerToken: { + isActive: true, + scopes: getScopesOfAccess({ + scopes: getScopesOfAccessLevel( + 'CREATE_READ_RESTRICTED_UPDATE_DELETE' + ), + type: 'MCP' + }) + } + }) + ).toEqual([ + 'get-accounts', + 'get-activities', + 'get-portfolio', + 'get-watchlist', + 'import-activities', + 'search-asset-profiles' + ]); + }); + + it('Lists no tool for an inactive access', () => { + expect( + getNamesOfListedTools({ + impersonationOfBearerToken: { + isActive: false, + scopes: getScopesOfAccessLevel('CREATE_READ_RESTRICTED_UPDATE_DELETE') + } + }) + ).toEqual([]); + }); + it('Requires the scope to create an activity for the tool to import activities', () => { expect( getMetadataOfMethod(REQUIRES_SCOPE_KEY, 'importActivities') diff --git a/apps/api/src/app/endpoints/mcp/mcp.controller.ts b/apps/api/src/app/endpoints/mcp/mcp.controller.ts index dee145015f..802567ad35 100644 --- a/apps/api/src/app/endpoints/mcp/mcp.controller.ts +++ b/apps/api/src/app/endpoints/mcp/mcp.controller.ts @@ -101,12 +101,6 @@ export class GhostfolioMcpController { return this.mcpService.getWatchlist({ userId }); } - /** - * The transport gives the tool to every client, because it filters the list - * of the tools by the scopes of request.user, which a request of an access - * never has. The guard refuses the call itself, hence the description names - * the permission which the access needs. - */ @RequiresScopeOfAccess(scopes.activityCreate) @Tool({ annotations: { @@ -115,7 +109,7 @@ export class GhostfolioMcpController { readOnlyHint: false, title: 'Import activities' }, - description: `Imports activities into the portfolio and gives the number of the imported activities and the number of the skipped activities. Use search-asset-profiles first unless the exact symbol and data source are already known. An activity is skipped if an equal activity is in the portfolio already, hence send each activity one time only: two equal activities of the same call are both imported. The access needs the permission "Restricted view and manage". At most ${MCP_MAX_ACTIVITIES} activities are imported per call, while the instance can have a lower limit, which an error names. An error does not remove the activities of the same call which are imported already, hence get the activities after an error before you import them again.`, + description: `Imports activities into the portfolio and gives the number of the imported activities and the number of the skipped activities. Use search-asset-profiles first unless the exact symbol and data source are already known. An activity is skipped if an equal activity is in the portfolio already, hence send each activity one time only: two equal activities of the same call are both imported. At most ${MCP_MAX_ACTIVITIES} activities are imported per call, while the instance can have a lower limit, which an error names. An error does not remove the activities of the same call which are imported already, hence get the activities after an error before you import them again.`, name: 'import-activities', parameters: IMPORT_ACTIVITIES_PARAMETERS }) diff --git a/apps/api/src/app/endpoints/mcp/mcp.module.ts b/apps/api/src/app/endpoints/mcp/mcp.module.ts index be81137f54..1da7a06823 100644 --- a/apps/api/src/app/endpoints/mcp/mcp.module.ts +++ b/apps/api/src/app/endpoints/mcp/mcp.module.ts @@ -2,6 +2,7 @@ import { ImportModule } from '@ghostfolio/api/app/import/import.module'; import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { environment } from '@ghostfolio/api/environments/environment'; +import { getMcpUserOfBearerToken } from '@ghostfolio/api/helper/bearer-token.helper'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; @@ -38,8 +39,9 @@ import { McpService } from './mcp.service'; return new McpStrategy({ instructions: - 'Ghostfolio is a wealth management application. The tools read the portfolio and the watchlist of the user who granted the access and import activities into the portfolio. They give no quantity and no monetary value (except the unit price of an activity).', + 'Ghostfolio is a wealth management application. The tools read the portfolio and the watchlist of the user who granted the access and import activities into the portfolio. They give no quantity and no monetary value (except the unit price of an activity). Only the tools which the permission of the access covers are listed. To import activities, the access needs the permission "Restricted view and manage".', name: 'ghostfolio', + resolveUser: getMcpUserOfBearerToken, title: 'Ghostfolio', transports: [ new StreamableHttpTransport({ diff --git a/apps/api/src/app/endpoints/tags/tags.controller.ts b/apps/api/src/app/endpoints/tags/tags.controller.ts index a61e1188c8..d464b7bb65 100644 --- a/apps/api/src/app/endpoints/tags/tags.controller.ts +++ b/apps/api/src/app/endpoints/tags/tags.controller.ts @@ -5,7 +5,7 @@ import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; import { isSystemTag } from '@ghostfolio/common/helper'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { RequestWithUser } from '@ghostfolio/common/types'; +import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, diff --git a/apps/api/src/app/endpoints/watchlist/watchlist.controller.ts b/apps/api/src/app/endpoints/watchlist/watchlist.controller.ts index b9250833ec..790f0b550e 100644 --- a/apps/api/src/app/endpoints/watchlist/watchlist.controller.ts +++ b/apps/api/src/app/endpoints/watchlist/watchlist.controller.ts @@ -7,7 +7,7 @@ import { CreateWatchlistItemDto } from '@ghostfolio/common/dtos'; import { WatchlistResponse } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; import { scopes } from '@ghostfolio/common/scopes'; -import { ImpersonationContext } from '@ghostfolio/common/types'; +import type { ImpersonationContext } from '@ghostfolio/common/types'; import { Body, diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index 59addfb44e..223a8964c1 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -773,6 +773,27 @@ describe('PortfolioService', () => { ).getSummary(args); }; + function createExcludedActivity({ + currency = 'CHF', + quantity, + symbol, + type, + unitPrice + }: Pick & { + currency?: string; + symbol: string; + }) { + return { + currency, + quantity, + type, + unitPrice, + account: { tags: [{ id: TAG_ID_EXCLUDE_FROM_ANALYSIS }] }, + assetProfile: { currency, symbol, dataSource: DataSource.YAHOO }, + tags: [] + } as unknown as Activity; + } + function createPortfolioCalculator() { return { getDividendInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), @@ -791,9 +812,13 @@ describe('PortfolioService', () => { beforeEach(() => { jest - .spyOn(activitiesService, 'getActivities') + .spyOn(activitiesService, 'getActivitiesForPortfolioCalculator') .mockResolvedValue({ activities: [], count: 0 }); + jest + .spyOn(exchangeRateDataService, 'toCurrency') + .mockImplementation((aValue) => aValue); + jest.spyOn(portfolioService, 'getPerformance').mockResolvedValue({ performance: { currentValueInBaseCurrency: 3000, @@ -837,6 +862,177 @@ describe('PortfolioService', () => { expect(summary.totalAssetsInBaseCurrency).toBe(3000); expect(summary.totalValueInBaseCurrency).toBe(3000); }); + + it('should value the open holdings of excluded accounts at the current market price', async () => { + jest.spyOn(accountService, 'getCashDetails').mockResolvedValue({ + accounts: [], + balanceInBaseCurrency: 1500 + }); + + jest + .spyOn(activitiesService, 'getActivitiesForPortfolioCalculator') + .mockResolvedValue({ + activities: [ + createExcludedActivity({ + quantity: 10, + symbol: 'AAPL', + type: 'BUY', + unitPrice: 100 + }), + createExcludedActivity({ + quantity: 4, + symbol: 'AAPL', + type: 'SELL', + unitPrice: 150 + }), + createExcludedActivity({ + quantity: 5, + symbol: 'MSFT', + type: 'BUY', + unitPrice: 100 + }), + createExcludedActivity({ + quantity: 5, + symbol: 'MSFT', + type: 'SELL', + unitPrice: 120 + }) + ], + count: 4 + }); + + const getQuotes = jest + .spyOn(dataProviderService, 'getQuotes') + .mockResolvedValue({ + 'YAHOO-AAPL': { + currency: 'CHF', + dataSource: DataSource.YAHOO, + marketPrice: 200, + marketState: 'open' + } + }); + + const summary = await getSummary({ + balanceInBaseCurrency: 1000, + emergencyFundHoldingsValueInBaseCurrency: 0, + filteredValueInBaseCurrency: new Big(3000), + portfolioCalculator: createPortfolioCalculator(), + userCurrency: 'CHF', + userId: userDummyData.id + }); + + // The closed holding (MSFT) does not need a quote + expect(getQuotes).toHaveBeenCalledWith( + expect.objectContaining({ + items: [{ dataSource: DataSource.YAHOO, symbol: 'AAPL' }] + }) + ); + + // 500 (balance of excluded accounts) + 6 * 200 (AAPL) + 0 (MSFT) + expect(summary.excludedAccountsAndActivities).toBe(1700); + expect(summary.totalValueInBaseCurrency).toBe(4700); + }); + + it('should convert the market value of an excluded holding from the currency of the asset profile to the user currency', async () => { + jest.spyOn(accountService, 'getCashDetails').mockResolvedValue({ + accounts: [], + balanceInBaseCurrency: 1000 + }); + + jest + .spyOn(activitiesService, 'getActivitiesForPortfolioCalculator') + .mockResolvedValue({ + activities: [ + createExcludedActivity({ + currency: 'USD', + quantity: 10, + symbol: 'AAPL', + type: 'BUY', + unitPrice: 100 + }), + createExcludedActivity({ + currency: 'USD', + quantity: 4, + symbol: 'AAPL', + type: 'SELL', + unitPrice: 150 + }) + ], + count: 2 + }); + + jest.spyOn(dataProviderService, 'getQuotes').mockResolvedValue({ + 'YAHOO-AAPL': { + currency: 'USD', + dataSource: DataSource.YAHOO, + marketPrice: 200, + marketState: 'open' + } + }); + + jest + .spyOn(exchangeRateDataService, 'toCurrency') + .mockImplementation((aValue, aFromCurrency, aToCurrency) => { + return aFromCurrency === 'USD' && aToCurrency === 'CHF' + ? aValue * 0.8 + : aValue; + }); + + const summary = await getSummary({ + balanceInBaseCurrency: 1000, + emergencyFundHoldingsValueInBaseCurrency: 0, + filteredValueInBaseCurrency: new Big(3000), + portfolioCalculator: createPortfolioCalculator(), + userCurrency: 'CHF', + userId: userDummyData.id + }); + + // 6 * 200 USD (AAPL) * 0.8 (USDCHF) + expect(summary.excludedAccountsAndActivities).toBe(960); + expect(summary.totalValueInBaseCurrency).toBe(3960); + }); + + it('should fall back to the unit price of the latest activity of an excluded holding without a market price', async () => { + jest.spyOn(accountService, 'getCashDetails').mockResolvedValue({ + accounts: [], + balanceInBaseCurrency: 1000 + }); + + jest + .spyOn(activitiesService, 'getActivitiesForPortfolioCalculator') + .mockResolvedValue({ + activities: [ + createExcludedActivity({ + quantity: 10, + symbol: 'AAPL', + type: 'BUY', + unitPrice: 100 + }), + createExcludedActivity({ + quantity: 4, + symbol: 'AAPL', + type: 'SELL', + unitPrice: 150 + }) + ], + count: 2 + }); + + jest.spyOn(dataProviderService, 'getQuotes').mockResolvedValue({}); + + const summary = await getSummary({ + balanceInBaseCurrency: 1000, + emergencyFundHoldingsValueInBaseCurrency: 0, + filteredValueInBaseCurrency: new Big(3000), + portfolioCalculator: createPortfolioCalculator(), + userCurrency: 'CHF', + userId: userDummyData.id + }); + + // 6 * 150 (unit price of the latest activity) + expect(summary.excludedAccountsAndActivities).toBe(900); + expect(summary.totalValueInBaseCurrency).toBe(3900); + }); }); describe('getValueOfAccountsAndPlatforms', () => { diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 1476db4ae0..90de5ddc38 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -39,6 +39,7 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS, UNKNOWN_KEY } from '@ghostfolio/common/config'; +import { SubscriptionType } from '@ghostfolio/common/enums'; import { DATE_FORMAT, getAssetProfileIdentifier, @@ -2093,11 +2094,12 @@ export class PortfolioService { }): Promise { const user = await this.userService.user({ id: userId }); - const { activities } = await this.activitiesService.getActivities({ - userCurrency, - userId, - withExcludedAccountsAndActivities: true - }); + const { activities } = + await this.activitiesService.getActivitiesForPortfolioCalculator({ + userCurrency, + userId, + withExcludedAccountsAndActivities: true + }); const excludedActivities: Activity[] = []; const nonExcludedActivities: Activity[] = []; @@ -2164,31 +2166,28 @@ export class PortfolioService { .plus(emergencyFundHoldingsValueInBaseCurrency) .toNumber(); - const totalOfExcludedActivities = this.getSumOfActivityType({ - userCurrency, - activities: excludedActivities, - activityType: 'BUY' - }).minus( - this.getSumOfActivityType({ - userCurrency, - activities: excludedActivities, - activityType: 'SELL' - }) - ); - - const cashDetailsWithExcludedAccounts = - await this.accountService.getCashDetails({ + const [ + cashDetailsWithExcludedAccounts, + valueOfExcludedActivitiesInBaseCurrency + ] = await Promise.all([ + this.accountService.getCashDetails({ userId, currency: userCurrency, withExcludedAccounts: true - }); + }), + this.getValueOfExcludedActivitiesInBaseCurrency({ + userCurrency, + activities: excludedActivities, + subscriptionType: user.subscription?.type + }) + ]); const excludedBalanceInBaseCurrency = new Big( cashDetailsWithExcludedAccounts.balanceInBaseCurrency ).minus(balanceInBaseCurrency); const excludedAccountsAndActivities = excludedBalanceInBaseCurrency - .plus(totalOfExcludedActivities) + .plus(valueOfExcludedActivitiesInBaseCurrency) .toNumber(); // Exclude emergency fund from the financial independence calculation @@ -2491,6 +2490,92 @@ export class PortfolioService { return { accounts, platforms }; } + private async getValueOfExcludedActivitiesInBaseCurrency({ + activities, + subscriptionType, + userCurrency + }: { + activities: Activity[]; + subscriptionType?: SubscriptionType; + userCurrency: string; + }) { + const holdings: { + [assetProfileIdentifier: string]: { + latestActivity: Activity; + quantity: Big; + }; + } = {}; + + // The activities are sorted by date in ascending order + for (const activity of activities) { + const factor = getFactor(activity.type); + + if (factor === 0 || isDraftActivity(activity)) { + continue; + } + + const assetProfileIdentifier = getAssetProfileIdentifier( + activity.assetProfile + ); + + const quantity = holdings[assetProfileIdentifier]?.quantity ?? new Big(0); + + holdings[assetProfileIdentifier] = { + latestActivity: activity, + quantity: quantity.plus(new Big(activity.quantity).mul(factor)) + }; + } + + const openHoldings = Object.values(holdings).filter(({ quantity }) => { + return !quantity.eq(0); + }); + + const quotes = + openHoldings.length > 0 + ? await this.dataProviderService.getQuotes({ + subscriptionType, + items: openHoldings.map( + ({ + latestActivity: { + assetProfile: { dataSource, symbol } + } + }) => { + return { dataSource, symbol }; + } + ) + }) + : {}; + + return getSum( + openHoldings.map(({ latestActivity, quantity }) => { + const { assetProfile, currency, unitPrice } = latestActivity; + + const marketPrice = + quotes[getAssetProfileIdentifier(assetProfile)]?.marketPrice; + + if (!marketPrice) { + // Fall back to the unit price of the latest activity without a + // market price + return new Big( + this.exchangeRateDataService.toCurrency( + quantity.mul(unitPrice).toNumber(), + currency ?? assetProfile.currency, + userCurrency + ) + ); + } + + return new Big( + this.exchangeRateDataService.toCurrency( + quantity.mul(marketPrice).toNumber(), + assetProfile.currency, + userCurrency + ) + ); + }) + ); + } + private isExcludedFromAnalysis(activity: Activity) { return ( isAccountExcluded(activity.account) || diff --git a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json index 69d4552648..7e9558bbbd 100644 --- a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json +++ b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json @@ -459,7 +459,7 @@ "AHARWBTC": "Aave Harmony WBTC", "AHOO": "Ahoolee", "AHT": "AhaToken", - "AI": "Flourishing AI", + "AI": "Gensyn", "AI16Z": "ai16z", "AI21X": "ai21x", "AI23T": "23 Turtles", @@ -467,7 +467,7 @@ "AI3": "Autonomys Network", "AI4": "AI⁴", "AI69SAKURA": "Sakura", - "AIA": "AIA Chain", + "AIA": "DeAgentAI", "AIACHAIN": "AIA Chain", "AIAF": "AI Agent Factory", "AIAGENT": "AI Agents", @@ -1338,7 +1338,6 @@ "AUX": "Auxilium", "AV": "AvatarCoin", "AVA": "AVA", - "AVA34326": "AVA Chiang Mai Night Safari", "AVAAI": "Ava AI", "AVACN": "AVACOIN", "AVAI": "Orca AVAI", @@ -2066,7 +2065,7 @@ "BHIGH": "Backed HIGH € High Yield Corp Bond", "BHIRE": "BitHIRE", "BHIVE": "Hive", - "BHO": "Bholdus", + "BHO": "Bholdus Token", "BHP": "Blockchain of Hash Power", "BHPC": "BHPCash", "BIAFRA": "Biafra Coin", @@ -3064,6 +3063,7 @@ "BTU": "BTU Protocol", "BTV": "Bitvote", "BTW": "BitWhite", + "BTW39158": "Bitway", "BTX": "BitCore", "BTXC": "Bettex coin", "BTXEX": "BTXEX", @@ -4055,7 +4055,6 @@ "COMAI": "Commune AI", "COMB": "Combine.finance", "COMBO": "COMBO", - "COMBO8259": "Furucombo", "COMBOX": "ComBox", "COMC": "ComCrica Token", "COME": "Community of Meme", @@ -4096,7 +4095,7 @@ "COOHA": "CoolHash", "COOK": "Cook Finance", "COOK33720": "mETH Protocol", - "COOKIE": "CookieSale", + "COOKIE": "Cookie DAO", "COOKTOKEN": "Cook", "COOL": "CoolCoin", "COOP": "Coop Network", @@ -8898,6 +8897,7 @@ "IMS": "Independent Money System", "IMST": "Imsmart", "IMT": "Moneytoken", + "IMU": "Immunefi", "IMUSIFY": "imusify", "IMVR": "ImmVRse", "IMX": "Immutable", @@ -9654,6 +9654,7 @@ "KINECOSYSTEM": "Kin", "KINET": "KinetixFi", "KING": "King Swap", + "KING33695": "King Protocol", "KING93": "King93", "KINGB": "King Bean", "KINGBONK": "King Bonk", @@ -9981,7 +9982,6 @@ "LAELAPS": "Laelaps", "LAFFIN": "Laffin Kamala", "LAI": "LayerAI", - "LAI23846": "LayerAI", "LAIKA": "LAIKA", "LAIKAPROTOCOL": "Laika Protocol", "LAINESOL": "Laine Staked SOL", @@ -11576,7 +11576,8 @@ "MOMO": "Momo", "MOMO2": "MOMO 2.0", "MOMO2025": "momo", - "MON": "PocMon", + "MON": "Monad", + "MON22337": "PocMon", "MON30495": "Monad", "MON30950": "MON", "MONA": "MonaCoin", @@ -11645,7 +11646,6 @@ "MOOMEME": "MOO MOO", "MOOMOO": "MOOMOO THE BULL", "MOON": "MoonSwap", - "MOON7396": "r/CryptoCurrency Moons", "MOONARCH": "Moonarch.app", "MOONB": "Moon Base", "MOONBEANS": "Moonbeans", @@ -13604,7 +13604,8 @@ "PHV": "PATHHIVE", "PHX": "Phoenix Global [old]", "PHY": "DePHY", - "PI": "Plian", + "PI": "Pi Network", + "PI2620": "Plian", "PI35697": "Pi", "PIA": "Olympia AI", "PIAI": "Pi Network AI", @@ -13830,7 +13831,7 @@ "PNDC": "Pond Coin", "PNDN": "Pandana", "PNDO": "Pondo", - "PNDR": "Pandora Protocol", + "PNDR": "Pandora Finance", "PNFT": "Pawn My NFT", "PNG": "Pangolin", "PNGDA": "Pengda Yellow Panda", @@ -14001,7 +14002,7 @@ "POWERMARKET": "POWER MARKET", "POWR": "Powerledger", "POWSCHE": "Powsche", - "POX": "Pollux Coin", + "POX": "Monkey Pox", "POZO": "Pozo Coin", "PP": "Phoenix Protocol Dao", "PPAD": "PlayPad", @@ -14508,6 +14509,7 @@ "RAIL": "Railgun", "RAILS": "Rails Token", "RAIN": "Rainmaker Games", + "RAIN38341": "Rain", "RAINBOW": "Rainbow Token", "RAINBOWTOKEN": "Rainbow Token", "RAINC": "RainCheck", @@ -15930,7 +15932,8 @@ "SKULL": "Skull Order", "SKUY": "SEKUYA", "SKX": "SKPANAX", - "SKY": "Skycoin", + "SKY": "Sky", + "SKY1619": "Skycoin", "SKY33038": "Sky", "SKYA": "Sekuya Multiverse", "SKYAI": "SKYAI", @@ -18274,7 +18277,8 @@ "USDQ": "Quantoz USDQ", "USDQSTABLE": "USDQ", "USDR": "Wrapped USDR", - "USDS": "Stably Classic", + "USDS": "USDS", + "USDS20039": "USDS", "USDS33039": "USDS", "USDSB": "USDSB", "USDSTABLY": "StableUSD", @@ -18698,7 +18702,7 @@ "VPAY": "VPay by Virtuals", "VPK": "Vulture Peak", "VPND": "VaporNodes", - "VPP": "Virtue Poker", + "VPP": "Virtue Poker Points", "VPR": "VaporWallet", "VPRC": "VapersCoin", "VPS": "VPS AI", @@ -18948,7 +18952,7 @@ "WDOT": "WDOT", "WDR": "Wider Coin", "WDX": "WeiDex", - "WE": "Wanda Exchange", + "WE": "WeBuy", "WEALTH": "WealthCoin", "WEAPON": "MEGAWEAPON", "WEAR": "MetaWear", @@ -19116,7 +19120,6 @@ "WINB": "WINBIT CASINO", "WINE": "Wine Shares", "WING": "Wing Finance", - "WING7048": "Wing Finance", "WINGS": "Wings", "WINK": "Wink", "WINN": "Winnerz", @@ -19687,7 +19690,6 @@ "XPLA": "XPLA", "XPLL": "ParallelChain", "XPM": "Primecoin", - "XPM20261": "XPMarket", "XPN": "PANTHEON X", "XPND": "Time Raiders", "XPNET": "XP NETWORK", diff --git a/apps/api/src/decorators/requires-scope-of-access.decorator.ts b/apps/api/src/decorators/requires-scope-of-access.decorator.ts index b76f1441c1..f0d35effcb 100644 --- a/apps/api/src/decorators/requires-scope-of-access.decorator.ts +++ b/apps/api/src/decorators/requires-scope-of-access.decorator.ts @@ -4,15 +4,24 @@ import { ScopeGuard } from '@ghostfolio/api/guards/scope.guard'; import { Scope } from '@ghostfolio/common/scopes'; import { applyDecorators, SetMetadata, UseGuards } from '@nestjs/common'; +import { ToolScopes } from '@rekog/mcp-nest'; /** * Marks a handler which requires the given scopes of an access, but no * authenticated user. The access itself is the credential, hence a client of * the model context protocol can use it. + * + * The same scopes are declared to the transport of the model context + * protocol, which lists a tool only for an access whose scopes cover it. The + * transport refuses the call of a tool which it does not list with a protocol + * error before the guards and the filter of the exceptions run. */ -export function RequiresScopeOfAccess(...requiredScopes: Scope[]) { +export function RequiresScopeOfAccess(scope: Scope, ...otherScopes: Scope[]) { + const requiredScopes = [scope, ...otherScopes]; + return applyDecorators( SetMetadata(REQUIRES_SCOPE_KEY, requiredScopes), + ToolScopes(requiredScopes), UseGuards(AccessGuard, ScopeGuard) ); } diff --git a/apps/api/src/guards/access.guard.ts b/apps/api/src/guards/access.guard.ts index 87a1f24692..f57c5a5b85 100644 --- a/apps/api/src/guards/access.guard.ts +++ b/apps/api/src/guards/access.guard.ts @@ -1,3 +1,4 @@ +import { getActiveImpersonationOfBearerToken } from '@ghostfolio/api/helper/bearer-token.helper'; import { getRequest } from '@ghostfolio/api/helper/execution-context.helper'; import type { RequestWithUser } from '@ghostfolio/common/types'; @@ -28,14 +29,17 @@ export class AccessGuard implements CanActivate { public canActivate(context: ExecutionContext) { const request = getRequest(context); - if (!request?.impersonationOfBearerToken?.isActive) { + const impersonationOfBearerToken = + getActiveImpersonationOfBearerToken(request); + + if (!impersonationOfBearerToken) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } - request.impersonation = request.impersonationOfBearerToken; + request.impersonation = impersonationOfBearerToken; return true; } diff --git a/apps/api/src/helper/bearer-token.helper.spec.ts b/apps/api/src/helper/bearer-token.helper.spec.ts new file mode 100644 index 0000000000..e2f48ff5bb --- /dev/null +++ b/apps/api/src/helper/bearer-token.helper.spec.ts @@ -0,0 +1,31 @@ +import { scopes } from '@ghostfolio/common/scopes'; + +import { getMcpUserOfBearerToken } from './bearer-token.helper'; + +describe('getMcpUserOfBearerToken', () => { + it('should give the scopes of an active access', () => { + expect( + getMcpUserOfBearerToken({ + impersonationOfBearerToken: { + isActive: true, + scopes: [scopes.portfolioRead] + } + }) + ).toEqual({ scopes: [scopes.portfolioRead] }); + }); + + it('should give no user for an inactive access', () => { + expect( + getMcpUserOfBearerToken({ + impersonationOfBearerToken: { + isActive: false, + scopes: [scopes.portfolioRead] + } + }) + ).toBeUndefined(); + }); + + it('should give no user without an access', () => { + expect(getMcpUserOfBearerToken({})).toBeUndefined(); + }); +}); diff --git a/apps/api/src/helper/bearer-token.helper.ts b/apps/api/src/helper/bearer-token.helper.ts index 5641016f5b..47be1e69b6 100644 --- a/apps/api/src/helper/bearer-token.helper.ts +++ b/apps/api/src/helper/bearer-token.helper.ts @@ -1,3 +1,5 @@ +import type { RequestWithUser } from '@ghostfolio/common/types'; + const PREFIX_OF_BEARER_TOKEN = 'bearer '; /** @@ -16,3 +18,30 @@ export function getAccessIdOfBearerToken(authorization?: string) { ? value.slice(PREFIX_OF_BEARER_TOKEN.length).trim() || undefined : undefined; } + +/** + * Gives the context of the access which the authorization middleware of the + * model context protocol resolved from the bearer token, but only while the + * access is active + */ +export function getActiveImpersonationOfBearerToken( + request?: Pick +) { + return request?.impersonationOfBearerToken?.isActive + ? request.impersonationOfBearerToken + : undefined; +} + +/** + * Gives the user which the transport of the model context protocol evaluates + * to list and to call the tools. It carries the scopes of the active access, + * hence the transport lists only the tools which the access covers. + */ +export function getMcpUserOfBearerToken(request: unknown) { + const impersonationOfBearerToken = + getActiveImpersonationOfBearerToken(request); + + return impersonationOfBearerToken + ? { scopes: impersonationOfBearerToken.scopes } + : undefined; +} diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index ea408c17d8..8846c14a7c 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -48,7 +48,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalBuy" /> @@ -62,7 +62,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalSell" /> @@ -79,7 +79,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalInvestmentValueWithCurrencyEffect" /> @@ -93,7 +93,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.grossPerformanceWithCurrencyEffect" /> @@ -110,7 +110,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.fees" /> @@ -127,7 +127,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.netPerformanceWithCurrencyEffect" /> @@ -171,7 +171,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalAssetsInBaseCurrency" /> @@ -217,7 +217,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="holdingsInBaseCurrency" /> @@ -233,7 +233,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="investmentsInBaseCurrency" /> @@ -248,7 +248,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.emergencyFund?.assets" /> @@ -295,7 +295,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalCashInBaseCurrency" /> @@ -311,7 +311,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.cash" /> @@ -326,7 +326,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.emergencyFund?.cash" /> @@ -356,7 +356,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.excludedAccountsAndActivities" /> @@ -379,7 +379,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.liabilitiesInBaseCurrency" /> @@ -396,7 +396,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.totalValueInBaseCurrency" /> @@ -469,7 +469,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.emergencyFund?.total" /> @@ -483,7 +483,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.interestInBaseCurrency" /> @@ -497,7 +497,7 @@ [isLoading]="isLoading" [locale]="locale" [precision]="precision" - [unit]="baseCurrency" + [unit]="displayedCurrency" [value]="summary?.dividendInBaseCurrency" /> diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts index ea68713189..dec65ddad9 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts @@ -79,6 +79,10 @@ export class GfPortfolioSummaryComponent implements OnChanges { : 0; } + protected get displayedCurrency() { + return this.deviceType === 'mobile' ? undefined : this.baseCurrency; + } + protected get emergencyFundPercentage() { return this.summary?.totalValueInBaseCurrency ? (this.summary.emergencyFund?.total || 0) / diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html index 59478d3cfa..7d5776d0ca 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html @@ -30,7 +30,7 @@ systems, including CasaOS, + >, Easypanel, Home Assistant, Runtipi, diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 525d25fb23..1d502bb80b 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -3,7 +3,7 @@ Invalid API key - Invalid API key + Clau API no vàlida apps/client/src/app/components/admin-settings/admin-settings.component.html 115 @@ -324,7 +324,7 @@ Date must be in the future. - Date must be in the future. + La data ha de ser futura. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 70 @@ -332,7 +332,7 @@ Fetch market price - Fetch market price + Recupera el preu de mercat libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html 40 @@ -372,7 +372,7 @@ Any person who has the link can view the data. - Any person who has the link can view the data. + Qualsevol persona que tingui l’enllaç pot veure les dades. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 42 @@ -516,7 +516,7 @@ Copy - Copy + Copia libs/ui/src/lib/notifications/alert-dialog/alert-dialog.html 20 @@ -696,7 +696,7 @@ Paid - Paid + De pagament apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts 136 @@ -788,7 +788,7 @@ Unknown - Unknown + Desconegut libs/ui/src/lib/i18n.ts 89 @@ -804,7 +804,7 @@ View and manage - View and manage + Veure i gestionar libs/ui/src/lib/access-level-icon/access-level-icon.component.html 9 @@ -904,7 +904,7 @@ Find an account... - Find an account... + Cerca un compte... libs/ui/src/lib/assistant/assistant.component.ts 450 @@ -984,7 +984,7 @@ Category - Category + Categoria apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 76 @@ -1052,7 +1052,7 @@ Data Gathering Frequency - Data Gathering Frequency + Freqüència de recollida de dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 477 @@ -1088,7 +1088,7 @@ Apply current market price - Apply current market price + Aplica el preu de mercat actual apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 221 @@ -1096,7 +1096,7 @@ Subscription History - Subscription History + Historial de subscripcions apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html 156 @@ -1144,7 +1144,7 @@ Healthcare - Healthcare + Salut libs/ui/src/lib/i18n.ts 98 @@ -1276,7 +1276,7 @@ Technology - Technology + Tecnologia libs/ui/src/lib/i18n.ts 102 @@ -1344,7 +1344,7 @@ Asset profile has been saved - Asset profile has been saved + El perfil de l’actiu s’ha desat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 754 @@ -1512,7 +1512,7 @@ Update Account - Update Account + Actualitza el compte libs/common/src/lib/routes/routes.ts 120 @@ -1644,7 +1644,7 @@ Current year - Current year + Any actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 267 @@ -1660,7 +1660,7 @@ Cache has been flushed. - Cache has been flushed. + La memòria cau s’ha buidat. apps/client/src/app/components/admin-overview/admin-overview.component.ts 281 @@ -2080,7 +2080,7 @@ Last Used - Last Used + Últim ús apps/client/src/app/components/access-table/access-table.component.html 31 @@ -2184,7 +2184,7 @@ Current week - Current week + Setmana actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 259 @@ -2212,7 +2212,7 @@ Code - Code + Codi apps/client/src/app/components/admin-overview/admin-overview.html 165 @@ -2312,7 +2312,7 @@ Energy - Energy + Energia libs/ui/src/lib/i18n.ts 96 @@ -2676,7 +2676,7 @@ The value has been copied to the clipboard - The value has been copied to the clipboard + El valor s’ha copiat al porta-retalls libs/ui/src/lib/notifications/alert-dialog/alert-dialog.component.ts 46 @@ -2752,7 +2752,7 @@ Add Account - Add Account + Afegeix un compte libs/common/src/lib/routes/routes.ts 101 @@ -2848,7 +2848,7 @@ Clone Activity - Clone Activity + Clona l’activitat libs/common/src/lib/routes/routes.ts 190 @@ -2992,7 +2992,7 @@ Next - Next + Següent apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 406 @@ -3148,7 +3148,7 @@ Daily - Daily + Diàriament apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 247 @@ -3849,7 +3849,7 @@ Creation - Creation + Creació apps/client/src/app/components/admin-overview/admin-overview.html 191 @@ -6758,7 +6758,7 @@ View Details - View Details + Veure els detalls apps/client/src/app/components/admin-users/admin-users.html 220 diff --git a/libs/common/src/lib/interfaces/product.interface.ts b/libs/common/src/lib/interfaces/product.interface.ts index b11c7ecada..11d5e35b05 100644 --- a/libs/common/src/lib/interfaces/product.interface.ts +++ b/libs/common/src/lib/interfaces/product.interface.ts @@ -17,6 +17,7 @@ export interface Product { pricingPerYear?: string; regions?: string[]; slogan?: string; + updatedAt?: string; url?: string; useAnonymously?: boolean; } diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index e6c6ce5d34..f713871dc8 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -2,6 +2,25 @@ import { Product } from '@ghostfolio/common/interfaces'; export const personalFinanceTools: Product[] = ( [ + { + categories: [ + 'FAMILY_OFFICE', + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'NET_WORTH_TRACKING', + 'WEALTH_MANAGEMENT' + ], + hasSelfHostingAbility: false, + key: 'abbove', + languages: ['English', 'Français', 'Nederlands'], + name: 'Abbove', + note: 'Originally named as PaxFamilia', + origin: 'BE', + platforms: ['WEB'], + slogan: 'Where every wealth planning journey begins', + updatedAt: '2026-09-23', + url: 'https://www.abbove.com' + }, { categories: ['BUDGETING'], hasFreePlan: true, @@ -13,6 +32,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['MACOS', 'WINDOWS'], pricingPerYear: '$44.95', slogan: 'Lifetime Personal Finance Control, One Single Payment.', + updatedAt: '2026-07-05', url: 'https://www.mechcad.net' }, { @@ -20,13 +40,41 @@ export const personalFinanceTools: Product[] = ( key: 'addepar', name: 'Addepar', slogan: 'Transform your business with Addepar', + updatedAt: '2026-08-28', url: 'https://addepar.com' }, + { + alias: 'APX', + categories: ['FAMILY_OFFICE', 'FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + hasSelfHostingAbility: true, + key: 'advent-portfolio-exchange', + name: 'Advent Portfolio Exchange', + origin: 'US', + platforms: ['WEB'], + slogan: 'Simplify portfolio accounting and reporting', + updatedAt: '2026-09-23', + url: 'https://www.advent.com/solutions/advent-portfolio-exchange' + }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'NET_WORTH_TRACKING', + 'WEALTH_MANAGEMENT' + ], + key: 'advisorengine', + name: 'AdvisorEngine', + origin: 'US', + slogan: 'Your complete wealth management platform', + updatedAt: '2026-09-23', + url: 'https://www.advisorengine.com' + }, { categories: ['WEALTH_MANAGEMENT'], key: 'akkuro', name: 'Akkuro', slogan: 'Composable Banking', + updatedAt: '2026-07-09', url: 'https://akkuro.com' }, { @@ -38,6 +86,7 @@ export const personalFinanceTools: Product[] = ( name: 'AllInvestView', platforms: ['WEB'], slogan: 'All your Investments in One View', + updatedAt: '2026-07-05', url: 'https://www.allinvestview.com' }, { @@ -49,6 +98,7 @@ export const personalFinanceTools: Product[] = ( name: 'Allvue Systems', origin: 'US', slogan: 'Investment Software Suite', + updatedAt: '2026-07-05', url: 'https://www.allvuesystems.com' }, { @@ -70,8 +120,24 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: 'CHF 99', slogan: 'Manage your entire Swiss wealth in one place', + updatedAt: '2026-08-27', url: 'https://alpgain.ch' }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'alphaquark', + languages: ['English'], + name: 'AlphaQuark', + origin: 'IN', + platforms: ['WEB'], + regions: ['IN'], + slogan: + 'Best Wealth Management Platform in India for RAs, RIAs & Sub-Brokers', + updatedAt: '2026-09-23', + url: 'https://alphaquark.in' + }, { categories: ['STOCK_TRACKING'], founded: 2016, @@ -80,6 +146,7 @@ export const personalFinanceTools: Product[] = ( name: 'AlphaTrackr', platforms: ['WEB'], slogan: 'Investment Portfolio Tracking Tool', + updatedAt: '2026-07-05', url: 'https://www.alphatrackr.com' }, { @@ -91,10 +158,11 @@ export const personalFinanceTools: Product[] = ( origin: 'CH', platforms: ['WEB'], slogan: 'Simplicity for Complex Wealth', + updatedAt: '2026-07-05', url: 'https://altoo.io' }, { - categories: ['WEALTH_MANAGEMENT'], + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], founded: 2018, hasFreePlan: false, hasSelfHostingAbility: false, @@ -103,6 +171,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['WEB'], slogan: 'The wealth platform built for independent advisors', + updatedAt: '2026-07-05', url: 'https://altruist.com' }, { @@ -115,6 +184,7 @@ export const personalFinanceTools: Product[] = ( origin: 'SG', pricingPerYear: '$228', slogan: 'Portfolio Visualizer', + updatedAt: '2026-07-05', url: 'https://amsflow.com' }, { @@ -127,6 +197,7 @@ export const personalFinanceTools: Product[] = ( origin: 'FR', platforms: ['WEB'], slogan: 'The investment copilot with no conflict of interest', + updatedAt: '2026-08-16', url: 'https://anantys.com' }, { @@ -141,8 +212,34 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$120', slogan: 'Analyze and track your portfolio.', + updatedAt: '2026-07-05', url: 'https://anlage.app' }, + { + categories: ['FAMILY_OFFICE', 'WEALTH_MANAGEMENT'], + founded: 2002, + key: 'archway', + languages: ['English'], + name: 'Archway', + origin: 'US', + platforms: ['WEB'], + slogan: 'The foundation for every transaction', + updatedAt: '2026-09-23', + url: 'https://www.archwaygroup.com' + }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'asignal', + languages: ['English'], + name: 'ASignal', + platforms: ['WEB'], + pricingPerYear: '$180', + slogan: 'Every signal comes with the research attached.', + updatedAt: '2026-09-23', + url: 'https://asignal.io' + }, { categories: ['FAMILY_OFFICE'], founded: 2022, @@ -153,6 +250,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['WEB'], slogan: 'The Intelligent Family Office Suite', + updatedAt: '2026-07-05', url: 'https://www.asseta.ai' }, { @@ -162,6 +260,7 @@ export const personalFinanceTools: Product[] = ( name: 'Atominvest', origin: 'GB', slogan: 'Portfolio Management', + updatedAt: '2026-07-05', url: 'https://www.atominvest.co' }, { @@ -175,6 +274,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$47.99', slogan: 'The Smarter Way to Track Your Finances', + updatedAt: '2026-07-05', url: 'https://www.balancepro.app' }, { @@ -188,6 +288,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€39.99', slogan: 'L’app tout-en-1 pour mieux gérer son argent', + updatedAt: '2026-08-17', url: 'https://www.bankin.com' }, { @@ -200,6 +301,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS', 'MACOS'], pricingPerYear: '$59.99', slogan: 'Proactive money management app for macOS & iOS', + updatedAt: '2026-07-05', url: 'https://www.banktivity.com' }, { @@ -207,6 +309,7 @@ export const personalFinanceTools: Product[] = ( key: 'basil-wealth', name: 'Basil', platforms: ['WEB'], + updatedAt: '2026-07-05', url: 'https://basilwealth.com' }, { @@ -218,6 +321,7 @@ export const personalFinanceTools: Product[] = ( name: 'Basil Finance', slogan: 'The ultimate solution for tracking and managing your investments', + updatedAt: '2026-07-05', url: 'https://basil.fi' }, { @@ -231,6 +335,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '$49.99', slogan: 'Stop guessing your net worth', + updatedAt: '2026-08-27', url: 'https://www.get-beam.app' }, { @@ -244,8 +349,35 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$100', slogan: 'Stock Portfolio Tracker for Smart Investors', + updatedAt: '2026-07-05', url: 'https://beanvest.com' }, + { + categories: ['INVESTMENT_RESEARCH'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'benzinga-pro', + languages: ['English'], + name: 'Benzinga Pro', + origin: 'US', + platforms: ['WEB'], + slogan: + 'The Best Investment Research Software & Breaking Stock Market News', + updatedAt: '2026-09-23', + url: 'https://www.benzinga.com/pro' + }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + founded: 2014, + hasSelfHostingAbility: false, + key: 'betterment-advisor-solutions', + name: 'Betterment Advisor Solutions', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + slogan: 'The independent custodian built for independent advisors', + updatedAt: '2026-09-23', + url: 'https://www.betterment.com/advisors' + }, { categories: ['BUDGETING'], founded: 2022, @@ -257,6 +389,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CA', platforms: ['ANDROID', 'IOS'], slogan: 'Be Money Mindful', + updatedAt: '2026-08-17', url: 'https://billi.webflow.io' }, { @@ -269,6 +402,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CA', platforms: ['ANDROID', 'IOS'], slogan: 'Real Portfolios, Trades & Market Insights', + updatedAt: '2026-08-16', url: 'https://blossomsocial.com' }, { @@ -281,6 +415,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CH', platforms: ['ANDROID', 'IOS'], slogan: 'Schweizer Budget App für einfache & smarte Budgetplanung', + updatedAt: '2026-07-05', url: 'https://www.bluebudget.ch' }, { @@ -295,8 +430,29 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$144', slogan: 'Take control with retirement planning tools that begin with you', + updatedAt: '2026-07-05', url: 'https://www.boldin.com' }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'FINANCIAL_PLANNING', + 'STOCK_TRACKING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'borderfolio', + languages: ['English'], + name: 'BorderFolio', + origin: 'GE', + platforms: ['WEB'], + pricingPerYear: '$149', + slogan: + 'Your broker shows what your portfolio is worth. BorderFolio shows how you built it.', + updatedAt: '2026-09-23', + url: 'https://borderfolio.app' + }, { categories: [ 'BUDGETING', @@ -322,6 +478,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CZ', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Your Finances in One Place', + updatedAt: '2026-08-18', url: 'https://budgetbakers.com' }, { @@ -331,6 +488,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['WEB'], slogan: 'Giving life to your finance!', + updatedAt: '2026-07-05', url: 'https://www.budgetpulse.com' }, { @@ -345,6 +503,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$96', regions: ['Global'], slogan: 'Take control of your financial future', + updatedAt: '2026-07-09', url: 'https://www.buxfer.com' }, { @@ -357,6 +516,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€80', slogan: 'Optimize your investments performance', + updatedAt: '2026-07-05', url: 'https://www.mycapitally.com' }, { @@ -368,13 +528,15 @@ export const personalFinanceTools: Product[] = ( note: 'CapMon.org was discontinued in 2023', origin: 'DE', platforms: ['WEB'], - slogan: 'Next Generation Assets Tracking' + slogan: 'Next Generation Assets Tracking', + updatedAt: '2026-07-05' }, { categories: ['INVESTMENT_RESEARCH'], key: 'cbonds', name: 'Cbonds', slogan: 'Financial Market Data Hub', + updatedAt: '2026-08-28', url: 'https://cbonds.com' }, { @@ -382,6 +544,7 @@ export const personalFinanceTools: Product[] = ( key: 'chaikin-analytics', name: 'Chaikin Analytics', slogan: 'Investing tools and research from Marc Chaikin & Team', + updatedAt: '2026-08-28', url: 'https://chaikinanalytics.com' }, { @@ -391,7 +554,8 @@ export const personalFinanceTools: Product[] = ( key: 'cleverbilling', languages: ['Español'], name: 'CleverBilling', - slogan: 'Toma el control total de tus finanzas.' + slogan: 'Toma el control total de tus finanzas.', + updatedAt: '2025-07-27' }, { categories: ['WEALTH_MANAGEMENT'], @@ -401,6 +565,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['WEB'], slogan: 'Next-Level Portfolio Monitoring', + updatedAt: '2026-07-05', url: 'https://www.cobalt.pe' }, { @@ -414,6 +579,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$168', slogan: 'Manage All Your Wallets & Exchanges From One Place', + updatedAt: '2026-07-05', url: 'https://coinstats.app' }, { @@ -428,8 +594,19 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$120', slogan: 'The leading Crypto Portfolio Tracker & Tax Calculator', + updatedAt: '2026-07-05', url: 'https://cointracking.info' }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + hasSelfHostingAbility: true, + key: 'comarch-wealth-management', + name: 'Comarch Wealth Management', + origin: 'PL', + slogan: 'Empower RMs. Engage customers. Enhance business growth.', + updatedAt: '2026-09-23', + url: 'https://www.comarch.com/finance/banking/comarch-wealth-management' + }, { categories: ['WEALTH_MANAGEMENT'], founded: 2019, @@ -438,6 +615,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['IOS', 'WEB'], slogan: 'Modern Wealth & Investment Management', + updatedAt: '2026-07-05', url: 'https://compoundplanning.com' }, { @@ -451,6 +629,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS', 'MACOS', 'WEB'], pricingPerYear: '$95', slogan: 'Do money better with Copilot', + updatedAt: '2026-07-05', url: 'https://www.copilot.money' }, { @@ -463,8 +642,52 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$9.99', slogan: 'Customizable and Secure Personal Finance App', + updatedAt: '2026-07-05', url: 'https://countabout.com' }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + founded: 2025, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'coveredge', + languages: ['English'], + name: 'CoverEdge', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$239.88', + slogan: 'Know what your options income is really earning.', + updatedAt: '2026-09-23', + url: 'https://coveredge.io' + }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + founded: 1987, + hasSelfHostingAbility: false, + key: 'croesus-advisor', + languages: ['English', 'Français'], + name: 'Croesus Advisor', + origin: 'CA', + slogan: + 'A trusted, all-in-one, customizable portfolio management system that empowers top-performing advisors and firms.', + updatedAt: '2026-09-23', + url: 'https://www.croesus.com/solutions/portfolio-management' + }, + { + categories: ['CRYPTOCURRENCY'], + founded: 2021, + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'crypto-excel', + languages: ['English', 'Français'], + name: 'Crypto Excel', + origin: 'FR', + platforms: ['WEB'], + pricingPerYear: '€70.80', + slogan: 'Excel in your investments.', + updatedAt: '2026-09-23', + url: 'https://www.cryptoexcel.io' + }, { categories: ['INVESTMENT_RESEARCH'], hasFreePlan: true, @@ -472,6 +695,7 @@ export const personalFinanceTools: Product[] = ( name: 'Danelfin', pricingPerYear: '$264', slogan: 'AI-Powered Stock Picking', + updatedAt: '2026-08-28', url: 'https://danelfin.com' }, { @@ -482,6 +706,7 @@ export const personalFinanceTools: Product[] = ( name: 'Danti', origin: 'GB', slogan: 'Digitising Generational Wealth', + updatedAt: '2026-07-05', url: 'https://danti.io' }, { @@ -491,14 +716,20 @@ export const personalFinanceTools: Product[] = ( languages: ['English'], name: 'De.Fi', slogan: 'DeFi Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://de.fi' }, { - categories: ['INVESTMENT_RESEARCH', 'WEALTH_MANAGEMENT'], + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], key: 'deepvest', name: 'DeepVest', slogan: 'The AI-Powered Research Platform for Financial Advisors and Investment Managers', + updatedAt: '2026-08-28', url: 'https://www.deepvest.ai' }, { @@ -513,6 +744,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$99', slogan: 'DeFi Portfolio Tracker for All Chains', + updatedAt: '2026-07-05', url: 'https://zerion.io/defi-portfolio-tracker' }, { @@ -527,6 +759,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€24', slogan: 'Democratizing Data Analytics', + updatedAt: '2026-07-05', url: 'https://capitalyse.app/app/degiro' }, { @@ -541,6 +774,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'MACOS', 'WEB', 'WINDOWS'], pricingPerYear: '$150', slogan: 'The app to track all your investments. Make smart moves only.', + updatedAt: '2026-07-05', url: 'https://delta.app' }, { @@ -553,8 +787,24 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$49.90', slogan: 'Dividend Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://www.digrin.com' }, + { + categories: ['INVESTMENT_RESEARCH'], + founded: 2020, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'diversiview', + languages: ['English'], + name: 'Diversiview', + origin: 'AU', + platforms: ['WEB'], + pricingPerYear: 'AUD 490', + slogan: 'Portfolio Analysis & Portfolio Optimization', + updatedAt: '2026-09-23', + url: 'https://diversiview.online' + }, { categories: ['DIVIDEND_TRACKING'], hasFreePlan: true, @@ -562,6 +812,7 @@ export const personalFinanceTools: Product[] = ( name: 'Dividend Watch', pricingPerYear: '$72', slogan: 'The Essential Dividend and Portfolio Tracker', + updatedAt: '2026-08-28', url: 'https://dividend.watch' }, { @@ -570,14 +821,36 @@ export const personalFinanceTools: Product[] = ( name: 'Dividend Wealth', pricingPerYear: '$99.99', slogan: 'Track Your Dividends Like a Pro', + updatedAt: '2026-08-28', url: 'https://dividend-wealth.com' }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'dividendatlas', + languages: ['English', 'Nederlands'], + name: 'DividendAtlas', + origin: 'NL', + platforms: ['WEB'], + pricingPerYear: '€79.90', + slogan: + 'Research every dividend stock that pays. Then track what you own.', + updatedAt: '2026-09-23', + url: 'https://dividendatlas.com' + }, { categories: ['DIVIDEND_TRACKING'], key: 'divtracker', name: 'DivTracker', pricingPerYear: '$29.99', slogan: 'Your Ultimate Dividend Tracker', + updatedAt: '2026-08-28', url: 'https://divtracker.app' }, { @@ -592,6 +865,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€65', slogan: 'Your personal Dividend Calendar', + updatedAt: '2026-07-05', url: 'https://divvydiary.com' }, { @@ -605,8 +879,20 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'WEB'], pricingPerYear: '€57.48', slogan: 'The Portfolio Tracker that replaces your spreadsheets', + updatedAt: '2026-08-16', url: 'https://www.donkycapital.com' }, + { + categories: ['BUDGETING', 'FINANCIAL_ADVISOR', 'FINANCIAL_PLANNING'], + hasSelfHostingAbility: false, + key: 'emoney', + name: 'eMoney', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + slogan: 'Everything you need. Every stage of advice.', + updatedAt: '2026-09-23', + url: 'https://emoneyadvisor.com' + }, { categories: ['FINANCIAL_PLANNING', 'NET_WORTH_TRACKING'], founded: 2009, @@ -617,6 +903,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['WEB'], slogan: 'Get answers to your money questions', + updatedAt: '2026-07-05', url: 'https://www.empower.com' }, { @@ -628,6 +915,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Portfolio Tracker Designed by Professional Investors', + updatedAt: '2026-07-05', url: 'https://8figures.com' }, { @@ -641,6 +929,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '£41.99', slogan: 'Take control of your money', + updatedAt: '2026-08-17', url: 'https://emma-app.com' }, { @@ -648,8 +937,36 @@ export const personalFinanceTools: Product[] = ( key: 'envestnet', name: 'Envestnet', slogan: 'Everybody Deserves Financial Wellness', + updatedAt: '2026-08-28', url: 'https://www.envestnet.com' }, + { + categories: [ + 'BUDGETING', + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'NET_WORTH_TRACKING' + ], + founded: 1985, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'envestnet-moneyguide', + name: 'Envestnet MoneyGuide', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$2000', + slogan: 'A Comprehensive Planning Platform', + updatedAt: '2026-09-23', + url: 'https://www.moneyguidepro.com' + }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + key: 'envestnet-tamarac', + name: 'Envestnet Tamarac', + slogan: 'Envestnet Tamarac. Built for the way RIAs work.', + updatedAt: '2026-09-23', + url: 'https://www.envestnet.com/tamarac' + }, { categories: ['INVESTMENT_RESEARCH'], hasFreePlan: true, @@ -658,13 +975,33 @@ export const personalFinanceTools: Product[] = ( origin: 'US', pricingPerYear: '$83.88', slogan: 'Stock Selection Analytics for Investors', + updatedAt: '2026-08-28', url: 'https://epsmomentum.com' }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'NET_WORTH_TRACKING', + 'STOCK_TRACKING', + 'TAX_REPORTING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'equitystat', + languages: ['English'], + name: 'EquityStat', + platforms: ['WEB'], + slogan: 'Track All Your Stocks In One Place', + updatedAt: '2026-09-23', + url: 'https://equitystat.com' + }, { categories: ['ETF_TRACKING', 'INVESTMENT_RESEARCH'], key: 'etf-action', name: 'ETF Action', slogan: 'Markets through the lens of ETFs', + updatedAt: '2026-08-28', url: 'https://www.etfaction.com' }, { @@ -672,6 +1009,7 @@ export const personalFinanceTools: Product[] = ( key: 'etf-insider', name: 'ETF Insider', slogan: 'Precision asset allocation', + updatedAt: '2026-08-28', url: 'https://etfinsider.co' }, { @@ -680,8 +1018,20 @@ export const personalFinanceTools: Product[] = ( key: 'etf-research-center', name: 'ETF Research Center', slogan: 'A Smarter Approach to Exchange Traded Funds', + updatedAt: '2026-08-28', url: 'https://www.etfrc.com' }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + hasSelfHostingAbility: false, + key: 'etna-financial-advisor-software', + name: 'ETNA Financial Advisor Software', + origin: 'US', + platforms: ['WEB'], + slogan: 'Transform wealth management with our turnkey SaaS solution', + updatedAt: '2026-09-23', + url: 'https://www.etnasoft.com/financial-advisor-software' + }, { categories: ['WEALTH_MANAGEMENT'], founded: 2010, @@ -691,6 +1041,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CH', platforms: ['WEB'], slogan: 'Your financial superpower', + updatedAt: '2026-07-05', url: 'https://www.etops.com' }, { @@ -703,8 +1054,28 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Plan, track, find more margin', + updatedAt: '2026-07-05', url: 'https://www.ramseysolutions.com/money/everydollar' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'excel-price-feed', + languages: ['English'], + name: 'Excel Price Feed', + origin: 'GB', + platforms: ['WINDOWS'], + pricingPerYear: '$165', + slogan: 'Live financial markets data in your Excel spreadsheet.', + updatedAt: '2026-09-23', + url: 'https://www.excelpricefeed.com' + }, { categories: ['NET_WORTH_TRACKING'], founded: 2020, @@ -716,6 +1087,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$100', slogan: 'All your wealth, in one place.', + updatedAt: '2026-07-05', url: 'https://www.exirio.com' }, { @@ -726,6 +1098,7 @@ export const personalFinanceTools: Product[] = ( name: 'Expersoft', origin: 'CH', slogan: 'Investment Management Platforms', + updatedAt: '2026-07-05', url: 'https://www.expersoft.com' }, { @@ -740,6 +1113,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€89.99', slogan: 'Die besten ETFs finden, vergleichen und beobachten', + updatedAt: '2026-08-16', url: 'https://extraetf.com' }, { @@ -747,6 +1121,7 @@ export const personalFinanceTools: Product[] = ( key: 'factorstoday', name: 'FactorsToday', slogan: 'Modern Quantitative Analysis', + updatedAt: '2026-08-28', url: 'https://www.factorstoday.com' }, { @@ -755,6 +1130,7 @@ export const personalFinanceTools: Product[] = ( name: 'FAST Graphs', pricingPerYear: '$191.40', slogan: 'Invest Intelligently with the Most Powerful Stock Analysis Tool', + updatedAt: '2026-08-28', url: 'https://www.fastgraphs.com' }, { @@ -769,8 +1145,22 @@ export const personalFinanceTools: Product[] = ( origin: 'CA', pricingPerYear: '$300', slogan: 'Make better investments.', + updatedAt: '2026-07-05', url: 'https://fey.com' }, + { + categories: ['FINANCIAL_ADVISOR', 'INVESTMENT_RESEARCH'], + founded: 1999, + hasSelfHostingAbility: false, + key: 'fiduciary-focus-toolkit', + name: 'Fiduciary Focus Toolkit', + note: 'Originally named as Fi360 Toolkit', + origin: 'US', + platforms: ['WEB'], + slogan: 'Your all-in-one solution', + updatedAt: '2026-09-23', + url: 'https://www.broadridge.com/hub/fiduciary-governance-solutions/investment-and-account-evaluation-tools' + }, { founded: 2023, hasFreePlan: true, @@ -781,8 +1171,24 @@ export const personalFinanceTools: Product[] = ( origin: 'US', pricingPerYear: '$115', slogan: 'Flexible Financial Management', + updatedAt: '2026-06-04', url: 'https://www.fina.money' }, + { + categories: ['CRYPTOCURRENCY', 'STOCK_TRACKING'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'financial-tech-wiz-trading-journal', + languages: ['English'], + name: 'Financial Tech Wiz Trading Journal', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$119', + slogan: + 'The Trading Journal Built to Track, Analyze, and Improve Your Performance', + updatedAt: '2026-09-23', + url: 'https://journal.financialtechwiz.com' + }, { categories: ['NET_WORTH_TRACKING'], founded: 2023, @@ -794,6 +1200,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€69.99', slogan: 'Portfolio Tracker für dein Vermögen', + updatedAt: '2026-07-05', url: 'https://www.finanzfluss.de/copilot' }, { @@ -807,6 +1214,7 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['ANDROID', 'IOS', 'MACOS'], slogan: 'Finanzen. Magisch. Einfach.', + updatedAt: '2026-07-05', url: 'https://www.finanzguru.de' }, { @@ -818,6 +1226,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Real-Time Portfolio Tracker & Stock Tracker', + updatedAt: '2026-07-05', url: 'https://finary.com' }, { @@ -832,6 +1241,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], slogan: 'The most convenient mobile application for personal finance accounting', + updatedAt: '2026-07-05', url: 'https://finateka.com' }, { @@ -841,6 +1251,7 @@ export const personalFinanceTools: Product[] = ( name: 'Fincake', origin: 'VG', slogan: 'Easy-to-use Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://fincake.io' }, { @@ -852,8 +1263,20 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['WEB'], slogan: 'Wealth Management Software', + updatedAt: '2026-07-05', url: 'https://fincite.de' }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + hasSelfHostingAbility: true, + key: 'finfolio', + name: 'FinFolio', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + slogan: 'Wealth management simplified.', + updatedAt: '2026-09-23', + url: 'https://www.finfolio.com' + }, { categories: ['BUDGETING'], hasSelfHostingAbility: false, @@ -864,6 +1287,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$84.00', slogan: 'Sync your bank to spreadsheets', + updatedAt: '2026-08-17', url: 'https://fintable.io' }, { @@ -871,8 +1295,26 @@ export const personalFinanceTools: Product[] = ( key: 'fintel', name: 'Fintel', slogan: 'Essential Tools for Investors and Traders', + updatedAt: '2026-08-28', url: 'https://fintel.io' }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + hasSelfHostingAbility: false, + key: 'fintellion', + name: 'Fintellion', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$1188', + slogan: + 'Research Companies. Track Market Events. Connect the Intelligence to Client Holdings.', + updatedAt: '2026-09-23', + url: 'https://www.fintellion.ai' + }, { categories: ['ETF_TRACKING', 'STOCK_TRACKING'], founded: 2021, @@ -882,6 +1324,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Grow your wealth in a stress-free way', + updatedAt: '2026-07-05', url: 'https://www.getfinvest.com' }, { @@ -892,6 +1335,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$299.50', slogan: 'Stock screener for investors and traders, financial visualizations', + updatedAt: '2026-08-28', url: 'https://finviz.com' }, { @@ -904,6 +1348,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€69.99', slogan: 'Personal finances, simplified', + updatedAt: '2026-07-05', url: 'https://finwiseapp.io' }, { @@ -917,6 +1362,7 @@ export const personalFinanceTools: Product[] = ( origin: 'UA', pricingPerYear: '$40', slogan: 'A simple solution to track your wealth online', + updatedAt: '2026-07-05', url: 'https://firekit.space' }, { @@ -924,6 +1370,7 @@ export const personalFinanceTools: Product[] = ( key: 'fiscal.ai', name: 'Fiscal.ai', slogan: 'The Modern Financial Data Platform', + updatedAt: '2026-08-28', url: 'https://fiscal.ai' }, { @@ -937,6 +1384,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '€23.88', slogan: 'Your money on autopilot', + updatedAt: '2026-08-17', url: 'https://flowyour.money' }, { @@ -949,8 +1397,24 @@ export const personalFinanceTools: Product[] = ( origin: 'AT', pricingPerYear: '$65', slogan: 'Take control over your investments', + updatedAt: '2026-07-05', url: 'https://www.folishare.com' }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'foremetrics', + languages: ['English'], + name: 'Foremetrics', + origin: 'NL', + platforms: ['WEB'], + pricingPerYear: '€89', + slogan: + 'Stock research, portfolio tracking, and valuation tools in one clear workspace', + updatedAt: '2026-09-23', + url: 'https://foremetrics.ai' + }, { categories: ['BUDGETING', 'NET_WORTH_TRACKING'], hasFreePlan: true, @@ -961,6 +1425,7 @@ export const personalFinanceTools: Product[] = ( origin: 'AU', platforms: ['ANDROID', 'IOS'], slogan: 'Feel good about money', + updatedAt: '2026-08-17', url: 'https://www.frollo.com.au' }, { @@ -974,6 +1439,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WINDOWS'], pricingPerYear: '$99', slogan: 'Powerful portfolio management software', + updatedAt: '2026-07-05', url: 'https://www.fundmanagersoftware.com' }, { @@ -995,8 +1461,24 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$60', regions: ['Global'], slogan: 'Take control of your finances from WhatsApp', + updatedAt: '2026-07-05', url: 'https://gasti.pro' }, + { + categories: ['DIVIDEND_TRACKING', 'STOCK_TRACKING', 'TAX_REPORTING'], + founded: 2026, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'geckopro', + languages: ['English'], + name: 'GeckoPro', + origin: 'NZ', + platforms: ['ANDROID', 'WEB'], + pricingPerYear: 'NZD 79.90', + slogan: 'Portfolio intelligence, without the noise.', + updatedAt: '2026-09-23', + url: 'https://geckopro.app' + }, { categories: ['NET_WORTH_TRACKING', 'STOCK_TRACKING'], founded: 2020, @@ -1009,6 +1491,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€48', slogan: 'Portfolio Tracker, Analysis & Community', + updatedAt: '2026-07-05', url: 'https://www.getquin.com' }, { @@ -1020,6 +1503,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Budget with a why', + updatedAt: '2026-07-05', url: 'https://goodbudget.com' }, { @@ -1030,13 +1514,15 @@ export const personalFinanceTools: Product[] = ( name: 'goSPATZ', note: 'Renamed to Money Peak', origin: 'DE', - slogan: 'Volle Kontrolle über deine Investitionen' + slogan: 'Volle Kontrolle über deine Investitionen', + updatedAt: '2025-04-17' }, { categories: ['INVESTMENT_RESEARCH'], key: 'gurufocus', name: 'GuruFocus', slogan: 'Stock Market Research, Data and Tools', + updatedAt: '2026-08-28', url: 'https://www.gurufocus.com' }, { @@ -1051,6 +1537,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€59.99', slogan: 'Prenez enfin le contrôle de votre argent', + updatedAt: '2026-07-05', url: 'https://get-gustav.com' }, { @@ -1058,8 +1545,28 @@ export const personalFinanceTools: Product[] = ( key: 'hedgefollow', name: 'HedgeFollow', slogan: 'Follow Hedge Funds & Insiders using 13F filings', + updatedAt: '2026-08-28', url: 'https://hedgefollow.com' }, + { + categories: [ + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'NET_WORTH_TRACKING', + 'STOCK_TRACKING' + ], + founded: 2025, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'helm-terminal', + languages: ['English'], + name: 'Helm Terminal', + platforms: ['WEB'], + pricingPerYear: '$149', + slogan: 'Your portfolio. A clearer picture.', + updatedAt: '2026-09-23', + url: 'https://helmterminal.dev' + }, { categories: ['DIVIDEND_TRACKING', 'ETF_TRACKING', 'STOCK_TRACKING'], hasFreePlan: true, @@ -1070,6 +1577,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CH', platforms: ['IOS', 'WEB'], slogan: 'Dein Vermögen im Überblick', + updatedAt: '2026-08-18', url: 'https://www.helvestor.ch' }, { @@ -1082,6 +1590,7 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Die All-in-One Lösung für dein Vermögen.', + updatedAt: '2026-07-05', url: 'https://holistic.capital', useAnonymously: true }, @@ -1094,6 +1603,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS'], slogan: 'Finance App for Couples', + updatedAt: '2026-07-05', url: 'https://www.honeydue.com' }, { @@ -1103,7 +1613,8 @@ export const personalFinanceTools: Product[] = ( key: 'ibank', name: 'iBank', note: 'Renamed to Banktivity', - origin: 'US' + origin: 'US', + updatedAt: '2026-06-23' }, { founded: 2022, @@ -1112,13 +1623,15 @@ export const personalFinanceTools: Product[] = ( name: 'Income Reign', note: 'Income Reign was discontinued in 2025', origin: 'US', - pricingPerYear: '$120' + pricingPerYear: '$120', + updatedAt: '2025-08-27' }, { categories: ['INVESTMENT_RESEARCH'], hasFreePlan: true, key: 'insidearbitrage', name: 'InsideArbitrage', + updatedAt: '2026-08-28', url: 'https://www.insidearbitrage.com' }, { @@ -1130,13 +1643,15 @@ export const personalFinanceTools: Product[] = ( note: 'Intuit Mint was discontinued in 2023', origin: 'US', pricingPerYear: '$60', - slogan: 'Managing money, made simple' + slogan: 'Managing money, made simple', + updatedAt: '2024-10-19' }, { categories: ['INVESTMENT_RESEARCH'], key: 'invesst', name: 'Invesst', slogan: 'Power Your Portfolio with AI', + updatedAt: '2026-08-28', url: 'https://invesst.ai' }, { @@ -1148,34 +1663,102 @@ export const personalFinanceTools: Product[] = ( origin: 'PK', platforms: ['ANDROID', 'IOS'], slogan: 'Advanced portfolio tracking and stock market information', + updatedAt: '2026-07-05', url: 'https://www.investify.pk' }, { - categories: ['NET_WORTH_TRACKING'], - founded: 2021, - hasFreePlan: true, - hasSelfHostingAbility: true, - key: 'invmon', - name: 'InvMon', - note: 'Originally named as A2PB', - origin: 'CH', - platforms: ['MACOS'], - pricingPerYear: '$156', - slogan: 'Track all your assets, investments and portfolios in one place', - url: 'https://invmon.com', - useAnonymously: true - }, - { - categories: ['CRYPTOCURRENCY', 'ETF_TRACKING', 'STOCK_TRACKING'], - hasFreePlan: true, + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: false, hasSelfHostingAbility: false, - key: 'inwestuje', - languages: ['Polski'], - name: 'inwestuje.app', - origin: 'PL', + key: 'investingpro', + name: 'InvestingPro', + origin: 'CY', platforms: ['ANDROID', 'IOS', 'WEB'], - slogan: 'Inwestujesz? Śledź swój majątek w jednym miejscu', - url: 'https://inwestuje.app' + slogan: 'Make your next trade LEGENDARY', + updatedAt: '2026-09-23', + url: 'https://www.investing.com/pro' + }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'STOCK_TRACKING', + 'TAX_REPORTING' + ], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'investment-account-manager', + languages: ['English'], + name: 'Investment Account Manager', + origin: 'US', + platforms: ['WINDOWS'], + pricingPerYear: '$159', + slogan: 'The Software Solution for Investing', + updatedAt: '2026-09-23', + url: 'https://www.investmentaccountmanager.com' + }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'FINANCIAL_PLANNING', + 'STOCK_TRACKING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'investor-pilot', + languages: ['English'], + name: 'Investor Pilot', + origin: 'AU', + platforms: ['WEB'], + pricingPerYear: '$144', + slogan: 'Take control of your investing journey', + updatedAt: '2026-09-23', + url: 'https://investorpilot.co' + }, + { + categories: ['NET_WORTH_TRACKING'], + founded: 2021, + hasFreePlan: true, + hasSelfHostingAbility: true, + key: 'invmon', + name: 'InvMon', + note: 'Originally named as A2PB', + origin: 'CH', + platforms: ['MACOS'], + pricingPerYear: '$156', + slogan: 'Track all your assets, investments and portfolios in one place', + updatedAt: '2026-07-05', + url: 'https://invmon.com', + useAnonymously: true + }, + { + categories: ['CRYPTOCURRENCY', 'ETF_TRACKING', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'inwestuje', + languages: ['Polski'], + name: 'inwestuje.app', + origin: 'PL', + platforms: ['ANDROID', 'IOS', 'WEB'], + slogan: 'Inwestujesz? Śledź swój majątek w jednym miejscu', + updatedAt: '2026-08-16', + url: 'https://inwestuje.app' + }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + founded: 2024, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'istfin', + languages: ['Türkçe'], + name: 'İstfin', + origin: 'TR', + platforms: ['WEB'], + pricingPerYear: '₺1188', + slogan: 'Veriyi Stratejiye Dönüştürün', + updatedAt: '2026-09-23', + url: 'https://istfin.com' }, { categories: ['ETF_TRACKING'], @@ -1188,6 +1771,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '€119', slogan: 'ETF portfolios made simple', + updatedAt: '2026-07-05', url: 'https://www.justetf.com' }, { @@ -1199,6 +1783,7 @@ export const personalFinanceTools: Product[] = ( name: 'Koinly', origin: 'SG', slogan: 'Track all your crypto wallets in one place', + updatedAt: '2026-07-05', url: 'https://koinly.io' }, { @@ -1212,6 +1797,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$468', slogan: 'Comprehensive financial data analysis', + updatedAt: '2026-07-05', url: 'https://www.koyfin.com' }, { @@ -1225,8 +1811,29 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$249', slogan: 'The Time Machine for your Net Worth', + updatedAt: '2026-07-05', url: 'https://www.kubera.com' }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + founded: 2008, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'kwanti', + languages: ['English'], + name: 'Kwanti', + note: 'Originally named as Portfolio Lab', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$2628', + slogan: 'Smart Analytics for Data-Driven Advisors', + updatedAt: '2026-09-23', + url: 'https://kwanti.com' + }, { categories: [ 'CRYPTOCURRENCY', @@ -1240,10 +1847,11 @@ export const personalFinanceTools: Product[] = ( languages: ['English'], name: 'Kyro', platforms: ['WEB'], + updatedAt: '2026-08-27', url: 'https://my.kyro.app' }, { - categories: ['WEALTH_MANAGEMENT'], + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], founded: 2021, hasFreePlan: false, key: 'leafs', @@ -1251,6 +1859,7 @@ export const personalFinanceTools: Product[] = ( name: 'Leafs', origin: 'CH', slogan: 'Sustainability insights for wealth managers', + updatedAt: '2026-07-05', url: 'https://leafs.ch' }, { @@ -1264,6 +1873,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '£26.99', slogan: 'Couples finances, made easy', + updatedAt: '2026-08-17', url: 'https://www.lumio-app.com' }, { @@ -1275,6 +1885,7 @@ export const personalFinanceTools: Product[] = ( name: 'Lunch Money', origin: 'CA', slogan: 'Delightfully simple personal finance and budgeting', + updatedAt: '2026-07-05', url: 'https://lunchmoney.app' }, { @@ -1288,13 +1899,30 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$132', slogan: 'AI Investing Assistant', + updatedAt: '2026-07-05', url: 'https://magnifi.com' }, + { + categories: ['CRYPTOCURRENCY'], + founded: 2023, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'mantapex', + languages: ['Deutsch', 'English', 'Español', 'Français', '中文'], + name: 'Mantapex', + origin: 'NO', + platforms: ['ANDROID', 'WEB'], + pricingPerYear: '$29', + slogan: 'Track Your Crypto Portfolio Across 50+ Chains', + updatedAt: '2026-09-23', + url: 'https://mantapex.com' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'marketinout', name: 'MarketInOut', slogan: 'Stock Screener with Backtesting & Advanced Filters', + updatedAt: '2026-08-28', url: 'https://www.marketinout.com' }, { @@ -1302,6 +1930,7 @@ export const personalFinanceTools: Product[] = ( key: 'marketlog', name: 'Marketlog', slogan: 'Stock Portfolio and Investments Tracker', + updatedAt: '2026-08-28', url: 'https://www.marketlog.com' }, { @@ -1317,6 +1946,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '€168', regions: ['Global'], slogan: 'Financial Intelligence Platform', + updatedAt: '2026-07-05', url: 'https://markets.sh' }, { @@ -1324,6 +1954,7 @@ export const personalFinanceTools: Product[] = ( key: 'marketscreener', name: 'MarketScreener', slogan: 'Financial News & Stock Market Quotes', + updatedAt: '2026-08-28', url: 'https://www.marketscreener.com' }, { @@ -1332,6 +1963,7 @@ export const personalFinanceTools: Product[] = ( name: 'MarketXLS', pricingPerYear: '$850', slogan: 'Real-Time Stock Data & Analysis in Excel', + updatedAt: '2026-08-28', url: 'https://marketxls.com' }, { @@ -1341,6 +1973,7 @@ export const personalFinanceTools: Product[] = ( name: 'Masttro', origin: 'US', slogan: 'Your platform for wealth in full view', + updatedAt: '2026-07-05', url: 'https://masttro.com' }, { @@ -1357,6 +1990,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$145', regions: ['US'], slogan: 'Your financial future, in your control', + updatedAt: '2026-06-04', url: 'https://github.com/maybe-finance/maybe' }, { @@ -1371,6 +2005,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$204', regions: ['CA', 'US'], slogan: 'The smartest way to track your crypto', + updatedAt: '2026-07-05', url: 'https://www.merlincrypto.com' }, { @@ -1383,6 +2018,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS', 'WEB'], pricingPerYear: '$48', slogan: 'Self-manage your wealth. Get fiduciary advice.', + updatedAt: '2026-07-05', url: 'https://www.mezzi.com' }, { @@ -1392,13 +2028,15 @@ export const personalFinanceTools: Product[] = ( key: 'microsoft-money', name: 'Microsoft Money', note: 'Microsoft Money was discontinued in 2010', - origin: 'US' + origin: 'US', + updatedAt: '2024-10-19' }, { categories: ['INVESTMENT_RESEARCH'], key: 'moatmap', name: 'MoatMap', slogan: 'AI Stock Screening & Equity Research', + updatedAt: '2026-08-28', url: 'https://moatmap.ai' }, { @@ -1412,6 +2050,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$99.99', slogan: 'The modern way to manage your money', + updatedAt: '2026-07-05', url: 'https://www.monarch.com' }, { @@ -1425,6 +2064,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'LINUX', 'MACOS', 'WINDOWS'], pricingPerYear: '$100', slogan: 'Personal Finance Manager for Mac, Windows, and Linux', + updatedAt: '2026-07-05', url: 'https://moneydance.com' }, { @@ -1437,6 +2077,7 @@ export const personalFinanceTools: Product[] = ( origin: 'US', pricingPerYear: '$29.99', slogan: 'Personal Accounting Made Easy, Accurate, Comprehensive', + updatedAt: '2026-07-05', url: 'https://www.moneypatrol.com' }, { @@ -1449,6 +2090,7 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Dein smarter Finance Assistant', + updatedAt: '2026-07-05', url: 'https://moneypeak.ai' }, { @@ -1461,6 +2103,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['LINUX', 'MACOS', 'WINDOWS'], pricingPerYear: '$59.99', slogan: 'Have total control of your financial life', + updatedAt: '2026-07-05', url: 'https://www.moneyspire.com' }, { @@ -1472,8 +2115,23 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['IOS', 'MACOS'], slogan: 'Personal Budgeting Software for Mac and iOS', + updatedAt: '2026-07-05', url: 'https://moneywell.app' }, + { + categories: ['BUDGETING', 'FINANCIAL_PLANNING', 'NET_WORTH_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'moneywellth', + languages: ['English'], + name: 'MoneyWellth', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$84.99', + slogan: 'Make Money Simple with MoneyWellth', + updatedAt: '2026-09-23', + url: 'https://www.moneywellth.com' + }, { categories: ['BUDGETING'], key: 'moneywiz', @@ -1482,6 +2140,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS', 'MACOS'], pricingPerYear: '$29.99', slogan: 'Get money management superpowers', + updatedAt: '2026-07-05', url: 'https://www.wiz.money' }, { @@ -1494,6 +2153,7 @@ export const personalFinanceTools: Product[] = ( note: 'Renamed to Nexafin', pricingPerYear: '$60', slogan: 'Gain financial control and keep your data private.', + updatedAt: '2026-07-05', url: 'https://monse.app' }, { @@ -1508,8 +2168,24 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$20', slogan: 'Smart, simple, stress-free money tracking.', + updatedAt: '2026-07-05', url: 'https://www.monsy.app' }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + key: 'morningstar-direct-advisory-suite', + name: 'Morningstar Direct Advisory Suite', + note: 'Originally named as Advisor Workstation', + origin: 'US', + slogan: 'Build trust. Showcase value. Deliver elevated advice at scale.', + updatedAt: '2026-09-23', + url: 'https://www.morningstar.com/business/products/direct-advisory-suite' + }, { categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], hasFreePlan: true, @@ -1521,6 +2197,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], slogan: 'Track your equity, fund, investment trust, ETF and pension investments in one place.', + updatedAt: '2026-07-05', url: 'https://www.morningstar.com/mm' }, { @@ -1540,6 +2217,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$49.99', slogan: 'Keep track of and visualize your investments throughout your day', + updatedAt: '2026-08-16', url: 'https://peeksoft.co' }, { @@ -1552,6 +2230,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$36', slogan: 'Your Personal Finance Command Center', + updatedAt: '2026-07-05', url: 'https://myfinancetools.io' }, { @@ -1565,6 +2244,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: 'PLN 36.10', slogan: 'Manage all your assets and accounts in one place', + updatedAt: '2026-08-16', url: 'https://myfund.pl' }, { @@ -1578,6 +2258,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$1188', slogan: 'Your Complete Crypto Portfolio, Reimagined', + updatedAt: '2026-07-05', url: 'https://www.nansen.ai/crypto-portfolio-tracker' }, { @@ -1591,6 +2272,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$90', slogan: 'The Intelligent Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://www.navexa.com' }, { @@ -1612,6 +2294,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$75', slogan: 'Everything you own. Everything you owe. Everything in one place.', + updatedAt: '2026-09-02', url: 'https://neontra.com' }, { @@ -1623,6 +2306,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€49.99', slogan: 'Your Personal Financial Analyst, powered by AI.', + updatedAt: '2026-07-05', url: 'https://networthy.pro' }, { @@ -1631,13 +2315,34 @@ export const personalFinanceTools: Product[] = ( name: 'Nexafin', platforms: ['WEB'], slogan: 'Your Finances. Finally Clear.', + updatedAt: '2026-07-05', url: 'https://nexafin.com' }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'nitrogen', + name: 'Nitrogen', + note: 'Originally named as Riskalyze', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$1188', + slogan: 'Showcase the value of advice in every client moment.', + updatedAt: '2026-09-23', + url: 'https://nitrogenwealth.com' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'okama', name: 'okama', slogan: 'Efficient Frontier for the investment portfolios', + updatedAt: '2026-08-28', url: 'https://okama.io' }, { @@ -1650,8 +2355,77 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '€49.99', slogan: 'Dividend Day Should Feel Like Payday', + updatedAt: '2026-08-28', url: 'https://onlydividends.app' }, + { + categories: [ + 'FAMILY_OFFICE', + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'WEALTH_MANAGEMENT' + ], + founded: 1999, + hasSelfHostingAbility: false, + key: 'orion-advisor-technology', + name: 'Orion Advisor Technology', + origin: 'US', + platforms: ['WEB'], + slogan: 'Run a firm where every advisor can thrive.', + updatedAt: '2026-09-23', + url: 'https://orion.com/advisor-tech' + }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'orion-risk-intelligence', + name: 'Orion Risk Intelligence', + note: 'Originally named as HiddenLevers', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$2970', + slogan: 'Risk analytics. Built on BeFi.', + updatedAt: '2026-09-23', + url: 'https://orion.com/advisor-tech/risk-intelligence' + }, + { + categories: [ + 'CRYPTOCURRENCY', + 'ETF_TRACKING', + 'FAMILY_OFFICE', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'palance', + languages: ['English', '日本語', '中文'], + name: 'Palance', + platforms: ['WEB'], + pricingPerYear: '$1200', + slogan: 'Markets, in clarity.', + updatedAt: '2026-09-23', + url: 'https://palance.co' + }, + { + categories: ['INVESTMENT_RESEARCH'], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'panda-trading-solutions', + languages: ['English', 'Español', 'Português'], + name: 'Panda Trading Solutions', + origin: 'BR', + platforms: ['WINDOWS'], + pricingPerYear: '$899', + slogan: 'One click on the board. Everything follows.', + updatedAt: '2026-09-23', + url: 'https://tspanda.com' + }, { categories: ['NET_WORTH_TRACKING'], founded: 2020, @@ -1665,6 +2439,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '€99.99', regions: ['AT', 'CH', 'DE'], slogan: 'Dein Vermögen immer im Blick', + updatedAt: '2026-07-05', url: 'https://www.parqet.com' }, { @@ -1679,6 +2454,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$99', slogan: 'Autopilot for your Portfolio', + updatedAt: '2026-08-16', url: 'https://passiv.com' }, { @@ -1698,6 +2474,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€49', slogan: 'Votre patrimoine, enfin clair', + updatedAt: '2026-07-05', url: 'https://mypatrice.com' }, { @@ -1708,6 +2485,7 @@ export const personalFinanceTools: Product[] = ( origin: 'SG', platforms: ['IOS'], slogan: 'Feel in control of your money without spreadsheets or shame', + updatedAt: '2026-07-05', url: 'https://peek.money' }, { @@ -1718,8 +2496,22 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS'], pricingPerYear: '$39.99', slogan: 'Your money. Made simple.', + updatedAt: '2026-07-05', url: 'https://www.getpennies.com' }, + { + categories: ['FAMILY_OFFICE'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'pinion', + languages: ['English'], + name: 'Pinion', + platforms: ['WEB'], + pricingPerYear: '$50', + slogan: 'Track your angel portfolio.', + updatedAt: '2026-09-23', + url: 'https://pinion.vc' + }, { categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], founded: 2022, @@ -1731,6 +2523,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€50', slogan: 'Invest smarter, not harder', + updatedAt: '2026-07-05', url: 'https://pinklion.xyz' }, { @@ -1744,6 +2537,7 @@ export const personalFinanceTools: Product[] = ( origin: 'PL', pricingPerYear: '$74', slogan: 'Free dividend tracker for your portfolio', + updatedAt: '2026-07-05', url: 'https://plainzer.com' }, { @@ -1755,6 +2549,7 @@ export const personalFinanceTools: Product[] = ( origin: 'IT', platforms: ['WEB'], slogan: 'Your Personal Finance Hub', + updatedAt: '2026-07-05', url: 'https://www.plannix.co' }, { @@ -1768,6 +2563,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$74.99', slogan: 'Budgeting App & Finance Planner', + updatedAt: '2026-07-05', url: 'https://pocketguard.com' }, { @@ -1783,8 +2579,22 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$120', regions: ['Global'], slogan: 'Know where your money is going', + updatedAt: '2026-07-05', url: 'https://www.pocketsmith.com' }, + { + categories: ['FINANCIAL_PLANNING', 'WEALTH_MANAGEMENT'], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'portax', + name: 'PORTAX', + origin: 'US', + platforms: ['WINDOWS'], + pricingPerYear: '$899', + slogan: 'After-Tax Portfolio Analysis', + updatedAt: '2026-09-23', + url: 'https://www.portaxsoftware.com' + }, { categories: ['BUDGETING', 'NET_WORTH_TRACKING', 'STOCK_TRACKING'], hasFreePlan: false, @@ -1796,6 +2606,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: 'PLN 168', slogan: 'Wszystkie Twoje inwestycje w jednym miejscu', + updatedAt: '2026-08-16', url: 'https://www.portfeo.pl' }, { @@ -1809,6 +2620,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '£120', slogan: 'Know your wealth. Ask it anything.', + updatedAt: '2026-08-13', url: 'https://portfoliocoach.co.uk' }, { @@ -1822,6 +2634,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€60', slogan: 'Manage all your portfolios', + updatedAt: '2026-07-05', url: 'https://portfoliodividendtracker.com' }, { @@ -1835,6 +2648,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS'], slogan: 'Professional stock portfolio tracking for iPhone, iPad and Apple Watch', + updatedAt: '2026-08-16', url: 'https://www.iportfoliotrader.com' }, { @@ -1846,6 +2660,7 @@ export const personalFinanceTools: Product[] = ( name: 'Portfolio Visualizer', pricingPerYear: '$360', slogan: 'Tools for Better Investors', + updatedAt: '2026-07-05', url: 'https://www.portfoliovisualizer.com' }, { @@ -1853,6 +2668,7 @@ export const personalFinanceTools: Product[] = ( key: 'portfolio123', name: 'Portfolio123', slogan: 'Power Your Portfolio with Backtested Stock Strategies', + updatedAt: '2026-08-28', url: 'https://www.portfolio123.com' }, { @@ -1865,15 +2681,75 @@ export const personalFinanceTools: Product[] = ( origin: 'PL', platforms: ['WEB'], slogan: 'One look. Clear picture of your portfolio.', + updatedAt: '2026-08-13', url: 'https://www.portfolioglance.com' }, + { + categories: ['INVESTMENT_RESEARCH'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'portfoliometrics', + languages: [ + 'Čeština', + 'Deutsch', + 'English', + 'Español', + 'Français', + 'Italiano', + '日本語', + '简体中文', + '繁體中文' + ], + name: 'PortfolioMetrics', + origin: 'CZ', + platforms: ['WEB'], + pricingPerYear: '$139', + slogan: 'What do you want to backtest today?', + updatedAt: '2026-09-23', + url: 'https://portfoliometrics.net', + useAnonymously: true + }, + { + categories: ['FAMILY_OFFICE', 'TAX_REPORTING', 'WEALTH_MANAGEMENT'], + founded: 1999, + hasSelfHostingAbility: false, + key: 'portfolioshop', + name: 'PortfolioShop', + origin: 'US', + platforms: ['WEB'], + slogan: 'Precision in Every Position', + updatedAt: '2026-09-23', + url: 'https://www.portfolioshop.com' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'portfolioslab', name: 'PortfoliosLab', slogan: 'Financial tools for smart investors', + updatedAt: '2026-08-28', url: 'https://portfolioslab.com' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + founded: 2025, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'portfoliotrackr', + languages: ['English'], + name: 'PortfolioTrackr', + origin: 'AE', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$99.99', + slogan: 'Every position. One dashboard.', + updatedAt: '2026-09-23', + url: 'https://portfoliotrackr.com' + }, { categories: ['STOCK_TRACKING'], hasFreePlan: true, @@ -1882,7 +2758,8 @@ export const personalFinanceTools: Product[] = ( name: 'Portfoloo', note: 'Portfoloo was discontinued', slogan: - 'Free Stock Portfolio Tracker with unlimited portfolio and stocks for DIY investors' + 'Free Stock Portfolio Tracker with unlimited portfolio and stocks for DIY investors', + updatedAt: '2026-07-05' }, { categories: ['DIVIDEND_TRACKING', 'STOCK_TRACKING'], @@ -1895,6 +2772,7 @@ export const personalFinanceTools: Product[] = ( origin: 'TH', pricingPerYear: '$96', slogan: 'Portfolio Performance and Dividend Tracker', + updatedAt: '2026-07-05', url: 'https://www.portseido.com' }, { @@ -1908,6 +2786,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$108', slogan: 'Build Financial Plans You Love.', + updatedAt: '2026-07-05', url: 'https://projectionlab.com' }, { @@ -1921,8 +2800,21 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$60', slogan: 'The stock portfolio tracker built for long-term investors', + updatedAt: '2026-07-05', url: 'https://prostocktracker.com' }, + { + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], + founded: 2007, + key: 'pulse-by-assetbook', + languages: ['English'], + name: 'Pulse by AssetBook', + origin: 'US', + platforms: ['WEB'], + slogan: 'Portfolio Management and Reporting Software', + updatedAt: '2026-09-23', + url: 'https://www.assetbook.com' + }, { categories: ['NET_WORTH_TRACKING'], hasSelfHostingAbility: false, @@ -1930,8 +2822,28 @@ export const personalFinanceTools: Product[] = ( name: 'Quantive', platforms: ['WEB'], slogan: 'See your financial life clearly', + updatedAt: '2026-07-05', url: 'https://usequantive.app' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'quotrend', + languages: ['English'], + name: 'QuoTrend', + origin: 'CY', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$154.80', + slogan: 'Know what to trade in your own words.', + updatedAt: '2026-09-23', + url: 'https://quotrend.com' + }, { categories: ['INVESTMENT_RESEARCH', 'NET_WORTH_TRACKING'], hasFreePlan: true, @@ -1943,13 +2855,16 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$99.99', slogan: 'Your entire financial life in one app, monitored continuously by agents', + updatedAt: '2026-07-05', url: 'https://rallies.ai' }, { categories: ['INVESTMENT_RESEARCH'], key: 'reflexivity', name: 'Reflexivity', + note: 'Originally named as Toggle AI', slogan: 'Faster Insights. Better Analysis. Greater Confidence.', + updatedAt: '2026-09-23', url: 'https://reflexivity.com' }, { @@ -1963,8 +2878,28 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['WEB'], slogan: 'Das kostenfreie Tool für Ihren Finanzerfolg', + updatedAt: '2026-08-16', url: 'https://www.rentablo.de' }, + { + categories: [ + 'BUDGETING', + 'FINANCIAL_ADVISOR', + 'FINANCIAL_PLANNING', + 'NET_WORTH_TRACKING' + ], + founded: 2015, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'rightcapital', + name: 'RightCapital', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$1799.40', + slogan: 'Financial planning software done right', + updatedAt: '2026-09-23', + url: 'https://www.rightcapital.com' + }, { categories: ['BUDGETING', 'NET_WORTH_TRACKING'], founded: 2015, @@ -1974,8 +2909,23 @@ export const personalFinanceTools: Product[] = ( origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Track your net worth', + updatedAt: '2026-07-05', url: 'https://www.rocketmoney.com' }, + { + categories: ['DIVIDEND_TRACKING', 'ETF_TRACKING', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'safe-dividend-tracker', + languages: ['English'], + name: 'Safe Dividend Tracker', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$95.88', + slogan: 'The Smarter Way to Build Dividend Income', + updatedAt: '2026-09-23', + url: 'https://safedividendtracker.com' + }, { categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], founded: 2019, @@ -1985,7 +2935,8 @@ export const personalFinanceTools: Product[] = ( name: 'Sarmaaya.pk Portfolio Tracking', note: 'Sarmaaya.pk Portfolio Tracking was discontinued in 2024', origin: 'PK', - slogan: 'Unified platform for financial research and portfolio tracking' + slogan: 'Unified platform for financial research and portfolio tracking', + updatedAt: '2026-07-05' }, { categories: ['INVESTMENT_RESEARCH'], @@ -1998,6 +2949,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$239', slogan: 'Stock Market Analysis & Tools for Investors', + updatedAt: '2026-07-05', url: 'https://seekingalpha.com' }, { @@ -2008,6 +2960,7 @@ export const personalFinanceTools: Product[] = ( origin: 'RO', platforms: ['WEB'], slogan: 'Track your net worth. Project every possible future.', + updatedAt: '2026-07-05', url: 'https://www.segmio.com' }, { @@ -2017,6 +2970,7 @@ export const personalFinanceTools: Product[] = ( origin: 'GB', slogan: 'Award-winning investment, trading and portfolio management tools', + updatedAt: '2026-08-28', url: 'https://www.sharescope.co.uk' }, { @@ -2031,6 +2985,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$135', regions: ['Global'], slogan: 'Stock Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://www.sharesight.com' }, { @@ -2040,7 +2995,8 @@ export const personalFinanceTools: Product[] = ( key: 'sharesmaster', name: 'SharesMaster', note: 'SharesMaster was discontinued', - slogan: 'Free Stock Portfolio Tracker' + slogan: 'Free Stock Portfolio Tracker', + updatedAt: '2026-07-05' }, { categories: ['STOCK_TRACKING'], @@ -2052,6 +3008,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€80', slogan: 'Stock Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://simpleportfolio.app' }, { @@ -2063,6 +3020,7 @@ export const personalFinanceTools: Product[] = ( name: 'Simplifi by Quicken', origin: 'US', platforms: ['ANDROID', 'IOS', 'WEB'], + updatedAt: '2026-07-05', url: 'https://www.quicken.com/products/simplifi' }, { @@ -2071,6 +3029,7 @@ export const personalFinanceTools: Product[] = ( name: 'Simply Safe Dividends', pricingPerYear: '$468', slogan: 'Proven dividend research and tracking tools', + updatedAt: '2026-08-28', url: 'https://www.simplysafedividends.com' }, { @@ -2084,8 +3043,30 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$120', slogan: 'Smart portfolio tracker for informed investors', + updatedAt: '2026-07-05', url: 'https://simplywall.st' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + founded: 2024, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'sirius-investors', + languages: ['English'], + name: 'Sirius Investors', + origin: 'NL', + platforms: ['WEB'], + pricingPerYear: '$190', + slogan: + 'Professional-Grade Investment Research with Automated Portfolio Management', + updatedAt: '2026-09-23', + url: 'https://www.siriusinvestors.com' + }, { categories: ['BUDGETING'], hasFreePlan: true, @@ -2097,6 +3078,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '£47.99', slogan: 'Cut the cost of living and build your savings', + updatedAt: '2026-08-17', url: 'https://snoop.app' }, { @@ -2110,6 +3092,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$80', slogan: 'Simple and powerful portfolio tracker', + updatedAt: '2026-07-05', url: 'https://snowball-analytics.com' }, { @@ -2123,19 +3106,22 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$14.99', slogan: 'The only app that gets your money into shape', + updatedAt: '2026-08-17', url: 'https://www.spendee.com' }, { key: 'splashmoney', name: 'SplashMoney', origin: 'US', - slogan: 'Manage your money anytime, anywhere.' + slogan: 'Manage your money anytime, anywhere.', + updatedAt: '2025-09-14' }, { - categories: ['WEALTH_MANAGEMENT'], + categories: ['FINANCIAL_ADVISOR', 'WEALTH_MANAGEMENT'], key: 'ssc-black-diamond', name: 'SS&C Black Diamond Wealth Solutions', slogan: 'The Cornerstone of a Successful Business', + updatedAt: '2026-08-28', url: 'https://www.sscblackdiamond.com' }, { @@ -2143,8 +3129,25 @@ export const personalFinanceTools: Product[] = ( key: 'statfolio', name: 'Statfolio', slogan: 'Take control of your investments', + updatedAt: '2026-08-28', url: 'https://statfolio.net' }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + founded: 2010, + key: 'statmetrics', + name: 'Statmetrics', + origin: 'DE', + platforms: ['ANDROID'], + slogan: 'Mobile App Solution for investment analysis and management', + updatedAt: '2026-09-23', + url: 'https://statmetrics.org' + }, { categories: ['INVESTMENT_RESEARCH'], hasFreePlan: true, @@ -2152,6 +3155,7 @@ export const personalFinanceTools: Product[] = ( name: 'Stock Analysis', pricingPerYear: '$79', slogan: 'Free Online Stock Information for Investors', + updatedAt: '2026-08-28', url: 'https://stockanalysis.com' }, { @@ -2163,14 +3167,45 @@ export const personalFinanceTools: Product[] = ( origin: 'DE', platforms: ['ANDROID', 'IOS', 'WEB'], slogan: 'Track all your Investments', + updatedAt: '2026-07-05', url: 'https://stockevents.app' }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + founded: 2025, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'stock-expert-ai', + name: 'Stock Expert AI', + origin: 'US', + platforms: ['WEB'], + slogan: 'Research US stocks with AI.', + updatedAt: '2026-09-23', + url: 'https://www.stockexpertai.com' + }, + { + categories: ['DIVIDEND_TRACKING', 'ETF_TRACKING', 'STOCK_TRACKING'], + founded: 2010, + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'stock-portfolio-organizer', + languages: ['English'], + name: 'Stock Portfolio Organizer', + note: 'License is a perpetual license', + origin: 'AU', + platforms: ['WINDOWS'], + pricingPerYear: '$99', + slogan: 'The Ultimate Stock Portfolio Management Software', + updatedAt: '2026-09-23', + url: 'https://www.stockportfolioorganizer.com' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'stockcharts', name: 'StockCharts', pricingPerYear: '$239.40', slogan: 'Advanced Charting, Screening & Financial Analysis Tools', + updatedAt: '2026-08-28', url: 'https://stockcharts.com' }, { @@ -2180,8 +3215,28 @@ export const personalFinanceTools: Product[] = ( origin: 'FI', platforms: ['WEB'], slogan: 'Supercharge your investments tracking experience', + updatedAt: '2026-07-05', url: 'https://stockle.app' }, + { + categories: [ + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'STOCK_TRACKING', + 'TAX_REPORTING' + ], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'stockmarket-plus', + languages: ['English'], + name: 'StockMarket Plus', + origin: 'AU', + platforms: ['WINDOWS'], + pricingPerYear: 'AUD 288', + slogan: 'Share Portfolio Management Software Australia', + updatedAt: '2026-09-23', + url: 'https://stockmarketplus.com.au' + }, { categories: ['STOCK_TRACKING'], founded: 2008, @@ -2190,7 +3245,22 @@ export const personalFinanceTools: Product[] = ( name: 'StockMarketEye', origin: 'FR', note: 'StockMarketEye was discontinued in 2023', - slogan: 'A Powerful Portfolio & Investment Tracking App' + slogan: 'A Powerful Portfolio & Investment Tracking App', + updatedAt: '2026-07-05' + }, + { + categories: ['DIVIDEND_TRACKING', 'STOCK_TRACKING', 'TAX_REPORTING'], + hasFreePlan: true, + hasSelfHostingAbility: true, + key: 'stockmaster', + languages: ['English'], + name: 'StockMaster', + origin: 'AU', + platforms: ['WINDOWS'], + pricingPerYear: '$275', + slogan: 'Australia Leading Portfolio Management Software', + updatedAt: '2026-09-23', + url: 'https://supertech.com.au/stockmaster.html' }, { categories: ['INVESTMENT_RESEARCH'], @@ -2198,6 +3268,7 @@ export const personalFinanceTools: Product[] = ( name: 'Stockopedia', pricingPerYear: '€550', slogan: 'Data-Driven Stock Research for Active Investors', + updatedAt: '2026-08-28', url: 'https://www.stockopedia.com' }, { @@ -2211,6 +3282,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$79.99', slogan: 'Investment Research and Portfolio Management', + updatedAt: '2026-07-05', url: 'https://www.stockrover.com' }, { @@ -2219,8 +3291,23 @@ export const personalFinanceTools: Product[] = ( name: 'Stock Unlock', pricingPerYear: '$90', slogan: 'Unique Stock Insights & Portfolio Tracking', + updatedAt: '2026-08-28', url: 'https://stockunlock.com' }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: true, + key: 'stockwarepro', + languages: ['English'], + name: 'StockwarePro', + origin: 'IN', + platforms: ['WINDOWS'], + pricingPerYear: '$70', + slogan: 'Signals are often lagging, AI gives us the leading edge!', + updatedAt: '2026-09-23', + url: 'https://www.stockwarepro.com' + }, { categories: ['STOCK_TRACKING'], hasFreePlan: true, @@ -2232,14 +3319,32 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€49.90', slogan: 'Visualize all of your portfolios', + updatedAt: '2026-07-05', url: 'https://stonksfolio.com' }, + { + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], + hasFreePlan: false, + key: 'stratifi', + name: 'StratiFi', + platforms: ['WEB'], + pricingPerYear: '$5995', + slogan: + 'Use AI trained by top independent wealth firms, engineered with sophisticated quant finance & grounded in proven behavioral finance.', + updatedAt: '2026-09-23', + url: 'https://www.stratifi.com' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'streamxls', name: 'StreamXLS', pricingPerYear: '$590', slogan: 'Excel bridge to IBKR TWS', + updatedAt: '2026-08-28', url: 'https://streamxls.com' }, { @@ -2252,6 +3357,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS'], pricingPerYear: '$20', slogan: 'AI-Powered Portfolio & Net Worth Tracker', + updatedAt: '2026-07-05', url: 'https://www.sumio.app' }, { @@ -2259,6 +3365,7 @@ export const personalFinanceTools: Product[] = ( key: 'tc2000', name: 'TC2000', slogan: 'Helping traders think for themselves for over 30 years', + updatedAt: '2026-08-28', url: 'https://www.tc2000.com' }, { @@ -2266,6 +3373,7 @@ export const personalFinanceTools: Product[] = ( key: 'tickeron', name: 'Tickeron', slogan: 'AI Trading Agents, Tools and News', + updatedAt: '2026-08-28', url: 'https://tickeron.com' }, { @@ -2274,6 +3382,7 @@ export const personalFinanceTools: Product[] = ( name: 'Tickertape', pricingPerYear: '₹2999', slogan: 'Financial freedom begins here', + updatedAt: '2026-08-28', url: 'https://www.tickertape.in' }, { @@ -2282,6 +3391,7 @@ export const personalFinanceTools: Product[] = ( key: 'tikr', name: 'TIKR', slogan: 'Invest like Wall Street with TIKR Terminal', + updatedAt: '2026-08-28', url: 'https://www.tikr.com' }, { @@ -2295,6 +3405,7 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$79', slogan: 'Your financial life in a spreadsheet, automatically updated each day', + updatedAt: '2026-07-05', url: 'https://tiller.com' }, { @@ -2308,6 +3419,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€35', slogan: 'Your key to empowered wealth management', + updatedAt: '2026-08-13', url: 'https://www.tinywallet.de' }, { @@ -2315,6 +3427,7 @@ export const personalFinanceTools: Product[] = ( key: 'tipranks', name: 'TipRanks', slogan: 'Make Smarter, Data-Driven Investment Decisions', + updatedAt: '2026-08-28', url: 'https://www.tipranks.com' }, { @@ -2328,14 +3441,35 @@ export const personalFinanceTools: Product[] = ( platforms: ['IOS'], pricingPerYear: '$24.99', slogan: 'Make your money go further with daily budgets', + updatedAt: '2026-08-18', url: 'https://www.todays-budget.com' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'DIVIDEND_TRACKING', + 'ETF_TRACKING', + 'STOCK_TRACKING', + 'TAX_REPORTING' + ], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'track-my-shares', + languages: ['English'], + name: 'Track My Shares', + platforms: ['WEB'], + pricingPerYear: '$49.99', + slogan: 'The portfolio tracker that handles your tax time too.', + updatedAt: '2026-09-23', + url: 'https://trackmyshares.com' + }, { categories: ['ETF_TRACKING'], founded: 2016, key: 'trackinsight', name: 'Trackinsight', slogan: 'Empowering ETF Investors', + updatedAt: '2026-08-28', url: 'https://www.trackinsight.com' }, { @@ -2348,6 +3482,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€40', slogan: 'See your real investment performance — across every broker', + updatedAt: '2026-08-16', url: 'https://trackinv.com' }, { @@ -2362,13 +3497,31 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$99.99', slogan: 'Follow the Performance, Payments, and Diversification of Your Dividend Portfolio', + updatedAt: '2026-08-16', url: 'https://www.trackyourdividends.com' }, + { + categories: ['CRYPTOCURRENCY', 'STOCK_TRACKING'], + founded: 2026, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'trade-journal-ai', + languages: ['English'], + name: 'Trade Journal AI', + origin: 'US', + platforms: ['IOS', 'WEB'], + pricingPerYear: '$195', + slogan: + 'The AI trading journal that reads every entry — not just every trade', + updatedAt: '2026-09-23', + url: 'https://tradejournal.ai' + }, { key: 'tradebb', name: 'TradeBB', slogan: 'Trading journal for tracking, reviewing, and improving your trades', + updatedAt: '2026-08-28', url: 'https://www.tradebb.ai' }, { @@ -2378,8 +3531,37 @@ export const personalFinanceTools: Product[] = ( pricingPerYear: '$219', regions: ['US'], slogan: 'Take Control Of Trader Taxes', + updatedAt: '2026-08-28', url: 'https://tradelog.com' }, + { + categories: ['CRYPTOCURRENCY', 'ETF_TRACKING', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'tradersforge-journal', + languages: ['English', 'Español', 'Português'], + name: 'TradersForge Journal', + origin: 'US', + platforms: ['IOS', 'WEB'], + pricingPerYear: '$100', + slogan: 'Your Trading Journal — now with Forge.', + updatedAt: '2026-09-23', + url: 'https://app.tradersforge.net' + }, + { + categories: ['CRYPTOCURRENCY', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'traderswatcher', + languages: ['English'], + name: 'TradersWatcher', + origin: 'CA', + platforms: ['WEB'], + pricingPerYear: '$290', + slogan: 'The journal that watches you trade.', + updatedAt: '2026-09-23', + url: 'https://traderswatcher.com' + }, { founded: 2011, hasFreePlan: false, @@ -2390,6 +3572,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$360', slogan: 'The Trading Journal to Improve Your Trading Performance', + updatedAt: '2026-07-05', url: 'https://www.tradervue.com' }, { @@ -2397,6 +3580,7 @@ export const personalFinanceTools: Product[] = ( name: 'TradeZella', pricingPerYear: '$315', slogan: 'Meet Your AI Trading Partner', + updatedAt: '2026-08-28', url: 'https://www.tradezella.com' }, { @@ -2405,6 +3589,7 @@ export const personalFinanceTools: Product[] = ( key: 'tradingview', name: 'TradingView', slogan: 'Track All Markets', + updatedAt: '2026-08-28', url: 'https://www.tradingview.com' }, { @@ -2418,6 +3603,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€80.04', slogan: 'Investing that never bores you', + updatedAt: '2026-08-16', url: 'https://www.treestep.fr' }, { @@ -2439,6 +3625,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€60', slogan: 'The Extra Leaf for Your Portfolio', + updatedAt: '2026-07-05', url: 'https://trefolio.com' }, { @@ -2447,8 +3634,23 @@ export const personalFinanceTools: Product[] = ( name: 'Trendlyne', pricingPerYear: '₹2190', slogan: 'The Stock Market Platform to Stay Ahead', + updatedAt: '2026-08-28', url: 'https://trendlyne.com' }, + { + categories: ['CRYPTOCURRENCY', 'INVESTMENT_RESEARCH'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'trendspider', + languages: ['English'], + name: 'TrendSpider', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$708', + slogan: 'Welcome to the AI-Powered Super Platform for Active Investors', + updatedAt: '2026-09-23', + url: 'https://trendspider.com' + }, { categories: ['NET_WORTH_TRACKING'], founded: 2020, @@ -2460,7 +3662,8 @@ export const personalFinanceTools: Product[] = ( note: 'Renamed to Parqet', origin: 'DE', regions: ['AT', 'CH', 'DE'], - slogan: 'Dein Vermögen immer im Blick' + slogan: 'Dein Vermögen immer im Blick', + updatedAt: '2026-07-05' }, { categories: ['NET_WORTH_TRACKING', 'STOCK_TRACKING'], @@ -2473,6 +3676,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€35.90', slogan: 'Your complete portfolio and expense tracker. Actually private.', + updatedAt: '2026-09-09', url: 'https://www.turbobulls.com' }, { @@ -2480,16 +3684,62 @@ export const personalFinanceTools: Product[] = ( key: 'tweenvest', name: 'Tweenvest', slogan: 'Analyzing stocks has never been easier', + updatedAt: '2026-08-28', url: 'https://www.tweenvest.com' }, + { + categories: [ + 'CRYPTOCURRENCY', + 'ETF_TRACKING', + 'INVESTMENT_RESEARCH', + 'STOCK_TRACKING' + ], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'tykr', + languages: ['English'], + name: 'Tykr', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$99.99', + slogan: 'Clear Confident Investing', + updatedAt: '2026-09-23', + url: 'https://tykr.com' + }, + { + categories: ['CRYPTOCURRENCY', 'STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'ultratrader', + name: 'UltraTrader', + platforms: ['ANDROID', 'IOS', 'WEB'], + pricingPerYear: '$108', + slogan: 'The Best Trading Journal for Web & Mobile', + updatedAt: '2026-09-23', + url: 'https://ultratrader.app' + }, { categories: ['INVESTMENT_RESEARCH'], key: 'uncle-stock', name: 'Uncle Stock', pricingPerYear: '$130', slogan: 'Fundamental Stock Screener', + updatedAt: '2026-08-28', url: 'https://www.unclestock.com' }, + { + categories: ['STOCK_TRACKING'], + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'upogee', + languages: ['English', 'Español'], + name: 'Upogee', + origin: 'ES', + platforms: ['WEB'], + slogan: 'See whether what you’re doing with your investments is working.', + updatedAt: '2026-09-23', + url: 'https://upogee.com' + }, { categories: ['STOCK_TRACKING'], hasFreePlan: true, @@ -2501,6 +3751,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$300', slogan: 'Your Portfolio. Revealed.', + updatedAt: '2026-07-05', url: 'https://www.utluna.com', useAnonymously: true }, @@ -2510,6 +3761,7 @@ export const personalFinanceTools: Product[] = ( name: 'Validea', slogan: 'Factor-Based Portfolios and Investment Research Utilizing Proven Long-Term Strategies', + updatedAt: '2026-08-28', url: 'https://www.validea.com' }, { @@ -2521,8 +3773,38 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€78', slogan: 'Track your real portfolio. Not a watchlist.', + updatedAt: '2026-07-05', url: 'https://valuedge.app' }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'valuescreener', + languages: ['English'], + name: 'ValueScreener', + origin: 'US', + platforms: ['WEB'], + pricingPerYear: '$228', + slogan: + 'We draft the numbers. You write the reason. We tell you the day one breaks.', + updatedAt: '2026-09-23', + url: 'https://valuescreener.ai' + }, + { + categories: ['INVESTMENT_RESEARCH', 'STOCK_TRACKING'], + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'vectorvest', + languages: ['English'], + name: 'VectorVest', + origin: 'US', + platforms: ['ANDROID', 'IOS', 'WEB', 'WINDOWS'], + pricingPerYear: '$499', + slogan: 'Protect & grow your stock portfolio in only 10 minutes a day', + updatedAt: '2026-09-23', + url: 'https://www.vectorvest.com' + }, { categories: ['FAMILY_OFFICE', 'WEALTH_MANAGEMENT'], founded: 2020, @@ -2533,6 +3815,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$348', slogan: 'Virtual Family Office for Smart Wealth Management', + updatedAt: '2026-07-05', url: 'https://vyzer.co' }, { @@ -2546,6 +3829,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '€90', slogan: 'Personal finance reimagined with AI', + updatedAt: '2026-07-05', url: 'https://walletguide.com' }, { @@ -2557,7 +3841,8 @@ export const personalFinanceTools: Product[] = ( note: 'wallmine was discontinued in 2024', origin: 'CZ', pricingPerYear: '$600', - slogan: 'Make Smarter Investments' + slogan: 'Make Smarter Investments', + updatedAt: '2025-12-13' }, { categories: ['INVESTMENT_RESEARCH'], @@ -2570,8 +3855,24 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$234', slogan: 'Stock market analysis for the serious part-time investor', + updatedAt: '2026-07-05', url: 'https://www.wallstreetzen.com' }, + { + categories: ['FAMILY_OFFICE', 'TAX_REPORTING'], + founded: 2001, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'wealth-write-up', + languages: ['English', 'Français'], + name: 'Wealth Write.Up', + origin: 'CA', + platforms: ['WEB'], + pricingPerYear: 'CAD 899', + slogan: 'The Competitive Edge in Investment Accounting', + updatedAt: '2026-09-23', + url: 'https://wealthwriteup.com' + }, { categories: ['FAMILY_OFFICE', 'WEALTH_MANAGEMENT'], founded: 2015, @@ -2581,6 +3882,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CH', platforms: ['WEB'], slogan: 'Manage wealth data more efficiently', + updatedAt: '2026-07-05', url: 'https://www.wealtharc.com' }, { @@ -2593,6 +3895,7 @@ export const personalFinanceTools: Product[] = ( origin: 'AE', platforms: ['WEB'], slogan: 'Portfolio Management System', + updatedAt: '2026-07-05', url: 'https://wealthbrain.com' }, { @@ -2607,6 +3910,7 @@ export const personalFinanceTools: Product[] = ( origin: 'CA', platforms: ['IOS', 'LINUX', 'MACOS', 'WEB', 'WINDOWS'], slogan: 'Open-Source, Offline & Private Portfolio Tracker', + updatedAt: '2026-07-05', url: 'https://wealthfolio.app' }, { @@ -2621,6 +3925,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$50', slogan: 'See all your investments in one place', + updatedAt: '2026-07-05', url: 'https://wealthica.com' }, { @@ -2632,6 +3937,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$60', slogan: 'Personal Finance & Budgeting App', + updatedAt: '2026-07-05', url: 'https://www.wealthposition.com' }, { @@ -2644,6 +3950,7 @@ export const personalFinanceTools: Product[] = ( origin: 'IN', platforms: ['WEB'], slogan: 'One app to manage all your investments', + updatedAt: '2026-07-05', url: 'https://www.wealthy.in/tracker' }, { @@ -2651,7 +3958,8 @@ export const personalFinanceTools: Product[] = ( key: 'whal', name: 'Whal', origin: 'US', - slogan: 'Manage your investments in one place' + slogan: 'Manage your investments in one place', + updatedAt: '2026-07-05' }, { categories: ['INVESTMENT_RESEARCH'], @@ -2659,13 +3967,19 @@ export const personalFinanceTools: Product[] = ( name: 'Wisesheets', pricingPerYear: '$60', slogan: 'The Ultimate Spreadsheet Add-On for Stock Investors', + updatedAt: '2026-08-28', url: 'https://www.wisesheets.io' }, { - categories: ['INVESTMENT_RESEARCH', 'WEALTH_MANAGEMENT'], + categories: [ + 'FINANCIAL_ADVISOR', + 'INVESTMENT_RESEARCH', + 'WEALTH_MANAGEMENT' + ], key: 'ycharts', name: 'YCharts', slogan: 'Financial Research and Proposal Platform', + updatedAt: '2026-08-28', url: 'https://ycharts.com' }, { @@ -2680,7 +3994,8 @@ export const personalFinanceTools: Product[] = ( note: 'yeekatee was discontinued in 2024', origin: 'CH', regions: ['Global'], - slogan: 'Connect. Share. Invest.' + slogan: 'Connect. Share. Invest.', + updatedAt: '2026-07-05' }, { categories: ['BUDGETING'], @@ -2693,6 +4008,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['ANDROID', 'IOS', 'WEB'], pricingPerYear: '$109', slogan: 'Change Your Relationship With Money', + updatedAt: '2026-07-05', url: 'https://www.ynab.com' }, { @@ -2701,6 +4017,7 @@ export const personalFinanceTools: Product[] = ( key: 'zacks', name: 'Zacks', slogan: 'Stock Research, Analysis, & Recommendations', + updatedAt: '2026-08-28', url: 'https://www.zacks.com' }, { @@ -2708,6 +4025,7 @@ export const personalFinanceTools: Product[] = ( key: 'zenvesto', name: 'Zenvesto', slogan: 'Smart Investment Portfolio Tracker', + updatedAt: '2026-08-28', url: 'https://zenvesto.com' }, { @@ -2721,6 +4039,7 @@ export const personalFinanceTools: Product[] = ( platforms: ['WEB'], pricingPerYear: '$84', slogan: 'Your solution for investing success', + updatedAt: '2026-07-05', url: 'https://ziggma.com' } ] satisfies Product[] diff --git a/libs/common/src/lib/types/product-category.type.ts b/libs/common/src/lib/types/product-category.type.ts index 7fae17a72f..12976f0323 100644 --- a/libs/common/src/lib/types/product-category.type.ts +++ b/libs/common/src/lib/types/product-category.type.ts @@ -4,6 +4,7 @@ export type ProductCategory = | 'DIVIDEND_TRACKING' | 'ETF_TRACKING' | 'FAMILY_OFFICE' + | 'FINANCIAL_ADVISOR' | 'FINANCIAL_PLANNING' | 'INVESTMENT_RESEARCH' | 'NET_WORTH_TRACKING' diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.html b/libs/ui/src/lib/accounts-table/accounts-table.component.html index a01abff1a8..60be93ad8a 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.html +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -50,13 +50,15 @@ Name - - {{ element.name }} +
+ + {{ element.name }} +
Total diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index 5051c9aa5a..4040b45c57 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -107,6 +107,7 @@ const locales = { DIVIDEND_TRACKING: $localize`Dividend Tracking`, ETF_TRACKING: $localize`ETF Tracking`, FAMILY_OFFICE: $localize`Family Office`, + FINANCIAL_ADVISOR: $localize`Financial Advisor`, FINANCIAL_PLANNING: $localize`Financial Planning`, INVESTMENT_RESEARCH: $localize`Investment Research`, NET_WORTH_TRACKING: $localize`Net Worth Tracking`, diff --git a/package-lock.json b/package-lock.json index 9ed3b35966..b3eae247c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.72.0", + "version": "3.73.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.72.0", + "version": "3.73.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -49,7 +49,7 @@ "@openrouter/ai-sdk-provider": "3.0.0", "@prisma/adapter-pg": "7.10.0", "@prisma/client": "7.10.0", - "@rekog/mcp-nest": "2.0.2", + "@rekog/mcp-nest": "2.0.7", "@simplewebauthn/browser": "13.3.0", "@simplewebauthn/server": "13.3.1", "ai": "7.0.37", @@ -13614,14 +13614,13 @@ } }, "node_modules/@rekog/mcp-nest": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@rekog/mcp-nest/-/mcp-nest-2.0.2.tgz", - "integrity": "sha512-kuye6wmRk5Gw4KZSCSXd83cWznRw4eFbvNUXsd8+1dYcS4uWKVVbRvxQIKNCyxc2UcljpsmLpnksr1NCRn3YAQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@rekog/mcp-nest/-/mcp-nest-2.0.7.tgz", + "integrity": "sha512-8DWrSapEA9Z/YJL9dFmj7sSbemmeQmf0VkGkW6Sn1itwKFf0n9hzTiwWt8XBtZvV5JVDNCtvRZKYYKgNjDcYPg==", "license": "MIT", "dependencies": { - "multer": "^2.2.0", - "path-to-regexp": "^8.4.2", - "rxjs": "^7.8.2" + "multer": "^2.3.0", + "path-to-regexp": "^8.4.2" }, "peerDependencies": { "@modelcontextprotocol/core": "^2.0.0-beta.5", @@ -13630,9 +13629,10 @@ "@nestjs/common": ">=9.0.0", "@nestjs/core": ">=9.0.0", "@nestjs/microservices": ">=9.0.0", - "@nestjs/platform-fastify": "^11.1.5", + "@nestjs/platform-fastify": "^11.1.5 || ^12.0.0", "express": ">=4.0.0", "reflect-metadata": "^0.2.2", + "rxjs": "^7.1.0", "zod": "^4.3.5" }, "peerDependenciesMeta": { @@ -13641,13 +13641,65 @@ } } }, - "node_modules/@rekog/mcp-nest/node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", + "node_modules/@rekog/mcp-nest/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@rekog/mcp-nest/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@rekog/mcp-nest/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@rekog/mcp-nest/node_modules/multer": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.4.0.tgz", + "integrity": "sha512-7dqa0ZcFfzbefdTuIkzOSMvZWC0J7FLqBOjJUZvDCXShIURWKxAyTT1wHhnE5q19c7jOJf43IYYKjBmZVZmvhg==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@rekog/mcp-nest/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/@rolldown/binding-android-arm64": { diff --git a/package.json b/package.json index 83aff10108..5648ac6693 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.72.0", + "version": "3.73.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", @@ -93,7 +93,7 @@ "@openrouter/ai-sdk-provider": "3.0.0", "@prisma/adapter-pg": "7.10.0", "@prisma/client": "7.10.0", - "@rekog/mcp-nest": "2.0.2", + "@rekog/mcp-nest": "2.0.7", "@simplewebauthn/browser": "13.3.0", "@simplewebauthn/server": "13.3.1", "ai": "7.0.37",