diff --git a/.eslintrc.json b/.eslintrc.json index 79d34dd0..75e36246 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -39,6 +39,7 @@ "plugin:@typescript-eslint/stylistic-type-checked" ], "rules": { + "@typescript-eslint/consistent-indexed-object-style": "off", "@typescript-eslint/dot-notation": "off", "@typescript-eslint/explicit-member-accessibility": [ "off", @@ -142,8 +143,7 @@ // The following rules are part of @typescript-eslint/stylistic-type-checked // and can be remove once solved - "@typescript-eslint/prefer-nullish-coalescing": "warn", // TODO: Requires strictNullChecks: true - "@typescript-eslint/consistent-indexed-object-style": "warn" + "@typescript-eslint/prefer-nullish-coalescing": "warn" // TODO: Requires strictNullChecks: true } } ], diff --git a/CHANGELOG.md b/CHANGELOG.md index 26952ed0..8263c054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added pagination to the users table of the admin control panel + +### Changed + +- Extracted the historical market data editor to a reusable component + +## 2.125.0 - 2024-11-30 + +### Changed + +- Improved the style of the symbol search component +- Extended the users table in the admin control panel +- Refreshed the cryptocurrencies list +- Increased the default request timeout (`REQUEST_TIMEOUT`) +- Upgraded `cheerio` from version `1.0.0-rc.12` to `1.0.0` +- Upgraded `prisma` from version `5.22.0` to `6.0.0` + +## 2.124.1 - 2024-11-25 + +### Fixed + +- Fixed the tables style related to sticky columns + +## 2.124.0 - 2024-11-24 + +### Added + +- Added pagination parameters (`skip`, `take`) to the endpoint `GET api/v1/admin/user` +- Added pagination response (`count`) to the endpoint `GET api/v1/admin/user` +- Added `GHOSTFOLIO` as a new data source type + +### Changed + +- Extended the allocations by ETF holding on the allocations page by the parent ETFs (experimental) +- Improved the language localization for German (`de`) +- Upgraded `countries-and-timezones` from version `3.4.1` to `3.7.2` +- Upgraded `Nx` from version `20.0.6` to `20.1.2` + +## 2.123.0 - 2024-11-16 + +### Added + +- Added a blog post: _Black Weeks 2024_ + +### Changed + +- Moved the chart of the holdings tab on the home page from experimental to general availability +- Extended the assistant by a holding selector +- Separated the _FIRE_ / _X-ray_ page +- Improved the usability to customize the rule thresholds in the _X-ray_ page by introducing range sliders (experimental) +- Improved the language localization for German (`de`) +- Improved the language localization for Italian (`it`) +- Upgraded `ngx-skeleton-loader` from version `7.0.0` to `9.0.0` +- Upgraded `prisma` from version `5.21.1` to `5.22.0` +- Upgraded `uuid` from version `9.0.1` to `11.0.2` + +## 2.122.0 - 2024-11-07 + +### Changed + +- Upgraded `countries-list` from version `3.1.0` to `3.1.1` + +### Fixed + +- Fixed an issue with the algebraic sign in the chart of the holdings tab on the home page (experimental) +- Improved the exception handling in the user authorization service +- Disabled the caching of the benchmarks in the markets overview if sharing the _Fear & Greed Index_ (market mood) is enabled + +## 2.121.1 - 2024-11-02 + +### Added + +- Set the stack and container names in the `docker-compose` files (`docker-compose.yml`, `docker-compose.build.yml` and `docker-compose.dev.yml`) + +### Changed + +- Reverted the permissions (`chmod 0700`) on `entrypoint.sh` in the `Dockerfile` +- Upgraded the _Stripe_ dependencies + +## 2.120.0 - 2024-10-30 + +### Added + +- Added support for log levels (`LOG_LEVELS`) to conditionally log `prisma` query events (`debug` or `verbose`) + ### Changed - Restructured the resources page +- Renamed the static portfolio analysis rule from _Allocation Cluster Risk_ to _Economic Market Cluster Risk_ (Developed Markets and Emerging Markets) - Improved the language localization for German (`de`) - Switched the `consistent-generic-constructors` rule from `warn` to `error` in the `eslint` configuration +- Switched the `consistent-indexed-object-style` rule from `warn` to `off` in the `eslint` configuration - Switched the `consistent-type-assertions` rule from `warn` to `error` in the `eslint` configuration - Switched the `prefer-optional-chain` rule from `warn` to `error` in the `eslint` configuration +- Upgraded `Nx` from version `20.0.3` to `20.0.6` ## 2.119.0 - 2024-10-26 @@ -29,15 +119,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue with the X-axis scale of the dividend timeline on the analysis page - Fixed an issue with the X-axis scale of the investment timeline on the analysis page - Fixed an issue with the X-axis scale of the portfolio evolution chart on the analysis page -- Fixed an issue in the calculation of the static portfolio analysis rule: Allocation Cluster Risk (Developed Markets) -- Fixed an issue in the calculation of the static portfolio analysis rule: Allocation Cluster Risk (Emerging Markets) +- Fixed an issue in the calculation of the static portfolio analysis rule: _Allocation Cluster Risk_ (Developed Markets) +- Fixed an issue in the calculation of the static portfolio analysis rule: _Allocation Cluster Risk_ (Emerging Markets) ## 2.118.0 - 2024-10-23 ### Added -- Added a new static portfolio analysis rule: Allocation Cluster Risk (Developed Markets) -- Added a new static portfolio analysis rule: Allocation Cluster Risk (Emerging Markets) +- Added a new static portfolio analysis rule: _Allocation Cluster Risk_ (Developed Markets) +- Added a new static portfolio analysis rule: _Allocation Cluster Risk_ (Emerging Markets) - Added support for mutual funds in the _EOD Historical Data_ service ### Changed diff --git a/Dockerfile b/Dockerfile index 0e5c0d27..e6c38f27 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,7 +61,6 @@ RUN apt-get update && apt-get install -y --no-install-suggests \ COPY --chown=node:node --from=builder /ghostfolio/dist/apps /ghostfolio/apps COPY --chown=node:node ./docker/entrypoint.sh /ghostfolio/entrypoint.sh -RUN chmod 0700 /ghostfolio/entrypoint.sh WORKDIR /ghostfolio/apps/api EXPOSE ${PORT:-3333} USER node diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index e0444d11..4cc4d467 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -352,7 +352,13 @@ export class AdminController { @Get('user') @HasPermission(permissions.accessAdminControl) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async getUsers(): Promise { - return this.adminService.getUsers(); + public async getUsers( + @Query('skip') skip?: number, + @Query('take') take?: number + ): Promise { + return this.adminService.getUsers({ + skip: isNaN(skip) ? undefined : skip, + take: isNaN(take) ? undefined : take + }); } } diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 860f1985..fb6e90f5 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -140,7 +140,7 @@ export class AdminService { const [settings, transactionCount, userCount] = await Promise.all([ this.propertyService.get(), this.prismaService.order.count(), - this.prismaService.user.count() + this.countUsersWithAnalytics() ]); return { @@ -429,8 +429,19 @@ export class AdminService { }; } - public async getUsers(): Promise { - return { users: await this.getUsersWithAnalytics() }; + public async getUsers({ + skip, + take = Number.MAX_SAFE_INTEGER + }: { + skip?: number; + take?: number; + }): Promise { + const [count, users] = await Promise.all([ + this.countUsersWithAnalytics(), + this.getUsersWithAnalytics({ skip, take }) + ]); + + return { count, users }; } public async patchAssetProfileData({ @@ -508,6 +519,22 @@ export class AdminService { return response; } + private async countUsersWithAnalytics() { + let where: Prisma.UserWhereInput; + + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + where = { + NOT: { + Analytics: null + } + }; + } + + return this.prismaService.user.count({ + where + }); + } + private getExtendedPrismaClient() { Logger.debug('Connect extended prisma client', 'AdminService'); @@ -640,8 +667,14 @@ export class AdminService { return { marketData, count: marketData.length }; } - private async getUsersWithAnalytics(): Promise { - let orderBy: any = { + private async getUsersWithAnalytics({ + skip, + take + }: { + skip?: number; + take?: number; + }): Promise { + let orderBy: Prisma.UserOrderByWithRelationInput = { createdAt: 'desc' }; let where: Prisma.UserWhereInput; @@ -649,7 +682,7 @@ export class AdminService { if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { orderBy = { Analytics: { - updatedAt: 'desc' + lastRequestAt: 'desc' } }; where = { @@ -661,6 +694,8 @@ export class AdminService { const usersWithAnalytics = await this.prismaService.user.findMany({ orderBy, + skip, + take, where, select: { _count: { @@ -670,6 +705,7 @@ export class AdminService { select: { activityCount: true, country: true, + dataProviderGhostfolioDailyRequests: true, updatedAt: true } }, @@ -677,8 +713,7 @@ export class AdminService { id: true, role: true, Subscription: true - }, - take: 30 + } }); return usersWithAnalytics.map( @@ -706,6 +741,7 @@ export class AdminService { subscription, accountCount: _count.Account || 0, country: Analytics?.country, + dailyApiRequests: Analytics?.dataProviderGhostfolioDailyRequests || 0, lastActivity: Analytics?.updatedAt, transactionCount: _count.Order || 0 }; diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 2803a058..4fbdafb0 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -31,6 +31,7 @@ import { AuthDeviceModule } from './auth-device/auth-device.module'; import { AuthModule } from './auth/auth.module'; import { BenchmarkModule } from './benchmark/benchmark.module'; import { CacheModule } from './cache/cache.module'; +import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module'; import { PublicModule } from './endpoints/public/public.module'; import { ExchangeRateModule } from './exchange-rate/exchange-rate.module'; import { ExportModule } from './export/export.module'; @@ -76,6 +77,7 @@ import { UserModule } from './user/user.module'; ExchangeRateModule, ExchangeRateDataModule, ExportModule, + GhostfolioModule, HealthModule, ImportModule, InfoModule, diff --git a/apps/api/src/app/auth/jwt.strategy.ts b/apps/api/src/app/auth/jwt.strategy.ts index a8ad8fd0..7a3fb224 100644 --- a/apps/api/src/app/auth/jwt.strategy.ts +++ b/apps/api/src/app/auth/jwt.strategy.ts @@ -46,7 +46,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { update: { country, activityCount: { increment: 1 }, - updatedAt: new Date() + lastRequestAt: new Date() }, where: { userId: user.id } }); @@ -60,7 +60,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { ); } } catch (error) { - if (error?.getStatus() === StatusCodes.TOO_MANY_REQUESTS) { + if (error?.getStatus?.() === StatusCodes.TOO_MANY_REQUESTS) { throw error; } else { throw new HttpException( diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/app/benchmark/benchmark.service.ts index 36f19684..a659281d 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/app/benchmark/benchmark.service.ts @@ -437,7 +437,7 @@ export class BenchmarkService { }; }); - if (storeInCache) { + if (!enableSharing && storeInCache) { const expiration = addHours(new Date(), 2); await this.redisCacheService.set( diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/get-dividends.dto.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-dividends.dto.ts new file mode 100644 index 00000000..6df457c6 --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-dividends.dto.ts @@ -0,0 +1,15 @@ +import { Granularity } from '@ghostfolio/common/types'; + +import { IsIn, IsISO8601, IsOptional } from 'class-validator'; + +export class GetDividendsDto { + @IsISO8601() + from: string; + + @IsIn(['day', 'month'] as Granularity[]) + @IsOptional() + granularity: Granularity; + + @IsISO8601() + to: string; +} diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/get-historical.dto.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-historical.dto.ts new file mode 100644 index 00000000..385c51d5 --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-historical.dto.ts @@ -0,0 +1,15 @@ +import { Granularity } from '@ghostfolio/common/types'; + +import { IsIn, IsISO8601, IsOptional } from 'class-validator'; + +export class GetHistoricalDto { + @IsISO8601() + from: string; + + @IsIn(['day', 'month'] as Granularity[]) + @IsOptional() + granularity: Granularity; + + @IsISO8601() + to: string; +} diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/get-quotes.dto.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-quotes.dto.ts new file mode 100644 index 00000000..e83c1be8 --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/get-quotes.dto.ts @@ -0,0 +1,10 @@ +import { Transform } from 'class-transformer'; +import { IsString } from 'class-validator'; + +export class GetQuotesDto { + @IsString({ each: true }) + @Transform(({ value }) => + typeof value === 'string' ? value.split(',') : value + ) + symbols: string[]; +} 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 new file mode 100644 index 00000000..788cfd1b --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts @@ -0,0 +1,196 @@ +import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; +import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { parseDate } from '@ghostfolio/common/helper'; +import { + DataProviderGhostfolioStatusResponse, + DividendsResponse, + HistoricalResponse, + LookupResponse, + QuotesResponse +} from '@ghostfolio/common/interfaces'; +import { permissions } from '@ghostfolio/common/permissions'; +import { RequestWithUser } from '@ghostfolio/common/types'; + +import { + Controller, + Get, + HttpException, + Inject, + Param, + Query, + UseGuards +} from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; +import { AuthGuard } from '@nestjs/passport'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; + +import { GetDividendsDto } from './get-dividends.dto'; +import { GetHistoricalDto } from './get-historical.dto'; +import { GetQuotesDto } from './get-quotes.dto'; +import { GhostfolioService } from './ghostfolio.service'; + +@Controller('data-providers/ghostfolio') +export class GhostfolioController { + public constructor( + private readonly ghostfolioService: GhostfolioService, + @Inject(REQUEST) private readonly request: RequestWithUser + ) {} + + @Get('dividends/:symbol') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getDividends( + @Param('symbol') symbol: string, + @Query() query: GetDividendsDto + ): Promise { + const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); + + if ( + this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + + try { + const dividends = await this.ghostfolioService.getDividends({ + symbol, + from: parseDate(query.from), + granularity: query.granularity, + to: parseDate(query.to) + }); + + await this.ghostfolioService.incrementDailyRequests({ + userId: this.request.user.id + }); + + return dividends; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } + + @Get('historical/:symbol') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getHistorical( + @Param('symbol') symbol: string, + @Query() query: GetHistoricalDto + ): Promise { + const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); + + if ( + this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + + try { + const historicalData = await this.ghostfolioService.getHistorical({ + symbol, + from: parseDate(query.from), + granularity: query.granularity, + to: parseDate(query.to) + }); + + await this.ghostfolioService.incrementDailyRequests({ + userId: this.request.user.id + }); + + return historicalData; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } + + @Get('lookup') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async lookupSymbol( + @Query('includeIndices') includeIndicesParam = 'false', + @Query('query') query = '' + ): Promise { + const includeIndices = includeIndicesParam === 'true'; + const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); + + if ( + this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + + try { + const result = await this.ghostfolioService.lookup({ + includeIndices, + query: query.toLowerCase() + }); + + await this.ghostfolioService.incrementDailyRequests({ + userId: this.request.user.id + }); + + return result; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } + + @Get('quotes') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getQuotes( + @Query() query: GetQuotesDto + ): Promise { + const maxDailyRequests = await this.ghostfolioService.getMaxDailyRequests(); + + if ( + this.request.user.dataProviderGhostfolioDailyRequests > maxDailyRequests + ) { + throw new HttpException( + getReasonPhrase(StatusCodes.TOO_MANY_REQUESTS), + StatusCodes.TOO_MANY_REQUESTS + ); + } + + try { + const quotes = await this.ghostfolioService.getQuotes({ + symbols: query.symbols + }); + + await this.ghostfolioService.incrementDailyRequests({ + userId: this.request.user.id + }); + + return quotes; + } catch { + throw new HttpException( + getReasonPhrase(StatusCodes.INTERNAL_SERVER_ERROR), + StatusCodes.INTERNAL_SERVER_ERROR + ); + } + } + + @Get('status') + @HasPermission(permissions.enableDataProviderGhostfolio) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getStatus(): Promise { + return this.ghostfolioService.getStatus({ user: this.request.user }); + } +} diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.module.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.module.ts new file mode 100644 index 00000000..01691bcf --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.module.ts @@ -0,0 +1,83 @@ +import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { CryptocurrencyModule } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.module'; +import { AlphaVantageService } from '@ghostfolio/api/services/data-provider/alpha-vantage/alpha-vantage.service'; +import { CoinGeckoService } from '@ghostfolio/api/services/data-provider/coingecko/coingecko.service'; +import { YahooFinanceDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service'; +import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; +import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; +import { EodHistoricalDataService } from '@ghostfolio/api/services/data-provider/eod-historical-data/eod-historical-data.service'; +import { FinancialModelingPrepService } from '@ghostfolio/api/services/data-provider/financial-modeling-prep/financial-modeling-prep.service'; +import { GoogleSheetsService } from '@ghostfolio/api/services/data-provider/google-sheets/google-sheets.service'; +import { ManualService } from '@ghostfolio/api/services/data-provider/manual/manual.service'; +import { RapidApiService } from '@ghostfolio/api/services/data-provider/rapid-api/rapid-api.service'; +import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; +import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; + +import { Module } from '@nestjs/common'; + +import { GhostfolioController } from './ghostfolio.controller'; +import { GhostfolioService } from './ghostfolio.service'; + +@Module({ + controllers: [GhostfolioController], + imports: [ + CryptocurrencyModule, + DataProviderModule, + MarketDataModule, + PrismaModule, + PropertyModule, + RedisCacheModule, + SymbolProfileModule + ], + providers: [ + AlphaVantageService, + CoinGeckoService, + ConfigurationService, + DataProviderService, + EodHistoricalDataService, + FinancialModelingPrepService, + GhostfolioService, + GoogleSheetsService, + ManualService, + RapidApiService, + YahooFinanceService, + YahooFinanceDataEnhancerService, + { + inject: [ + AlphaVantageService, + CoinGeckoService, + EodHistoricalDataService, + FinancialModelingPrepService, + GoogleSheetsService, + ManualService, + RapidApiService, + YahooFinanceService + ], + provide: 'DataProviderInterfaces', + useFactory: ( + alphaVantageService, + coinGeckoService, + eodHistoricalDataService, + financialModelingPrepService, + googleSheetsService, + manualService, + rapidApiService, + yahooFinanceService + ) => [ + alphaVantageService, + coinGeckoService, + eodHistoricalDataService, + financialModelingPrepService, + googleSheetsService, + manualService, + rapidApiService, + yahooFinanceService + ] + } + ] +}) +export class GhostfolioModule {} diff --git a/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts new file mode 100644 index 00000000..7858e24f --- /dev/null +++ b/apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts @@ -0,0 +1,304 @@ +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; +import { + GetDividendsParams, + GetHistoricalParams, + GetQuotesParams, + GetSearchParams +} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; +import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; +import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { + DEFAULT_CURRENCY, + DERIVED_CURRENCIES +} from '@ghostfolio/common/config'; +import { PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS } from '@ghostfolio/common/config'; +import { + DataProviderInfo, + DividendsResponse, + HistoricalResponse, + LookupItem, + LookupResponse, + QuotesResponse +} from '@ghostfolio/common/interfaces'; +import { UserWithSettings } from '@ghostfolio/common/types'; + +import { Injectable, Logger } from '@nestjs/common'; +import { DataSource } from '@prisma/client'; +import { Big } from 'big.js'; + +@Injectable() +export class GhostfolioService { + public constructor( + private readonly configurationService: ConfigurationService, + private readonly dataProviderService: DataProviderService, + private readonly prismaService: PrismaService, + private readonly propertyService: PropertyService + ) {} + + public async getDividends({ + from, + granularity, + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbol, + to + }: GetDividendsParams) { + const result: DividendsResponse = { dividends: {} }; + + try { + const promises: Promise<{ + [date: string]: IDataProviderHistoricalResponse; + }>[] = []; + + for (const dataProviderService of this.getDataProviderServices()) { + promises.push( + dataProviderService + .getDividends({ + from, + granularity, + requestTimeout, + symbol, + to + }) + .then((dividends) => { + result.dividends = dividends; + + return dividends; + }) + ); + } + + await Promise.all(promises); + + return result; + } catch (error) { + Logger.error(error, 'GhostfolioService'); + + throw error; + } + } + + public async getHistorical({ + from, + granularity, + requestTimeout, + to, + symbol + }: GetHistoricalParams) { + const result: HistoricalResponse = { historicalData: {} }; + + try { + const promises: Promise<{ + [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; + }>[] = []; + + for (const dataProviderService of this.getDataProviderServices()) { + promises.push( + dataProviderService + .getHistorical({ + from, + granularity, + requestTimeout, + symbol, + to + }) + .then((historicalData) => { + result.historicalData = historicalData[symbol]; + + return historicalData; + }) + ); + } + + await Promise.all(promises); + + return result; + } catch (error) { + Logger.error(error, 'GhostfolioService'); + + throw error; + } + } + + public async getMaxDailyRequests() { + return parseInt( + ((await this.propertyService.getByKey( + PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS + )) as string) || '0', + 10 + ); + } + + public async getQuotes({ requestTimeout, symbols }: GetQuotesParams) { + const results: QuotesResponse = { quotes: {} }; + + try { + const promises: Promise[] = []; + + for (const dataProvider of this.getDataProviderServices()) { + const maximumNumberOfSymbolsPerRequest = + dataProvider.getMaxNumberOfSymbolsPerRequest?.() ?? + Number.MAX_SAFE_INTEGER; + + for ( + let i = 0; + i < symbols.length; + i += maximumNumberOfSymbolsPerRequest + ) { + const symbolsChunk = symbols.slice( + i, + i + maximumNumberOfSymbolsPerRequest + ); + + const promise = Promise.resolve( + dataProvider.getQuotes({ requestTimeout, symbols: symbolsChunk }) + ); + + promises.push( + promise.then(async (result) => { + for (const [symbol, dataProviderResponse] of Object.entries( + result + )) { + dataProviderResponse.dataSource = 'GHOSTFOLIO'; + + if ( + [ + ...DERIVED_CURRENCIES.map(({ currency }) => { + return `${DEFAULT_CURRENCY}${currency}`; + }), + `${DEFAULT_CURRENCY}USX` + ].includes(symbol) + ) { + continue; + } + + results.quotes[symbol] = dataProviderResponse; + + for (const { + currency, + factor, + rootCurrency + } of DERIVED_CURRENCIES) { + if (symbol === `${DEFAULT_CURRENCY}${rootCurrency}`) { + results.quotes[`${DEFAULT_CURRENCY}${currency}`] = { + ...dataProviderResponse, + currency, + marketPrice: new Big( + result[`${DEFAULT_CURRENCY}${rootCurrency}`].marketPrice + ) + .mul(factor) + .toNumber(), + marketState: 'open' + }; + } + } + } + }) + ); + } + + await Promise.all(promises); + } + + return results; + } catch (error) { + Logger.error(error, 'GhostfolioService'); + + throw error; + } + } + + public async getStatus({ user }: { user: UserWithSettings }) { + return { + dailyRequests: user.dataProviderGhostfolioDailyRequests, + dailyRequestsMax: await this.getMaxDailyRequests(), + subscription: user.subscription + }; + } + + public async incrementDailyRequests({ userId }: { userId: string }) { + await this.prismaService.analytics.update({ + data: { + dataProviderGhostfolioDailyRequests: { increment: 1 }, + lastRequestAt: new Date() + }, + where: { userId } + }); + } + + public async lookup({ + includeIndices = false, + query + }: GetSearchParams): Promise { + const results: LookupResponse = { items: [] }; + + if (!query) { + return results; + } + + try { + let lookupItems: LookupItem[] = []; + const promises: Promise<{ items: LookupItem[] }>[] = []; + + if (query?.length < 2) { + return { items: lookupItems }; + } + + for (const dataProviderService of this.getDataProviderServices()) { + promises.push( + dataProviderService.search({ + includeIndices, + query + }) + ); + } + + const searchResults = await Promise.all(promises); + + for (const { items } of searchResults) { + if (items?.length > 0) { + lookupItems = lookupItems.concat(items); + } + } + + const filteredItems = lookupItems + .filter(({ currency }) => { + // Only allow symbols with supported currency + return currency ? true : false; + }) + .sort(({ name: name1 }, { name: name2 }) => { + return name1?.toLowerCase().localeCompare(name2?.toLowerCase()); + }) + .map((lookupItem) => { + lookupItem.dataProviderInfo = this.getDataProviderInfo(); + lookupItem.dataSource = 'GHOSTFOLIO'; + + return lookupItem; + }); + + results.items = filteredItems; + return results; + } catch (error) { + Logger.error(error, 'GhostfolioService'); + + throw error; + } + } + + private getDataProviderInfo(): DataProviderInfo { + return { + isPremium: false, + name: 'Ghostfolio Premium', + url: 'https://ghostfol.io' + }; + } + + private getDataProviderServices() { + return this.configurationService + .get('DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER') + .map((dataSource) => { + return this.dataProviderService.getDataProvider(DataSource[dataSource]); + }); + } +} diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 30415970..e51696b5 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -582,12 +582,13 @@ export class ImportService { const assetProfiles: { [assetProfileIdentifier: string]: Partial; } = {}; + const dataSources = await this.dataProviderService.getDataSources(); for (const [ index, { currency, dataSource, symbol, type } ] of activitiesDto.entries()) { - if (!this.configurationService.get('DATA_SOURCES').includes(dataSource)) { + if (!dataSources.includes(dataSource)) { throw new Error( `activities.${index}.dataSource ("${dataSource}") is not valid` ); diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index bd291c51..904a9709 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -7,6 +7,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { DEFAULT_CURRENCY, + HEADER_KEY_TOKEN, PROPERTY_BETTER_UPTIME_MONITOR_ID, PROPERTY_COUNTRIES_OF_SUBSCRIBERS, PROPERTY_DEMO_USER_ID, @@ -23,10 +24,10 @@ import { import { InfoItem, Statistics, - Subscription + SubscriptionOffer } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; -import { SubscriptionOffer } from '@ghostfolio/common/types'; +import { SubscriptionOfferKey } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; @@ -101,7 +102,7 @@ export class InfoService { isUserSignupEnabled, platforms, statistics, - subscriptions + subscriptionOffers ] = await Promise.all([ this.benchmarkService.getBenchmarkAssetProfiles(), this.getDemoAuthToken(), @@ -110,7 +111,7 @@ export class InfoService { orderBy: { name: 'asc' } }), this.getStatistics(), - this.getSubscriptions() + this.getSubscriptionOffers() ]); if (isUserSignupEnabled) { @@ -125,7 +126,7 @@ export class InfoService { isReadOnlyMode, platforms, statistics, - subscriptions, + subscriptionOffers, baseCurrency: DEFAULT_CURRENCY, currencies: this.exchangeRateDataService.getCurrencies() }; @@ -142,7 +143,7 @@ export class InfoService { }, { Analytics: { - updatedAt: { + lastRequestAt: { gt: subDays(new Date(), aDays) } } @@ -314,8 +315,8 @@ export class InfoService { return statistics; } - private async getSubscriptions(): Promise<{ - [offer in SubscriptionOffer]: Subscription; + private async getSubscriptionOffers(): Promise<{ + [offer in SubscriptionOfferKey]: SubscriptionOffer; }> { if (!this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { return undefined; @@ -347,7 +348,7 @@ export class InfoService { )}&to${format(new Date(), DATE_FORMAT)}`, { headers: { - Authorization: `Bearer ${this.configurationService.get( + [HEADER_KEY_TOKEN]: `Bearer ${this.configurationService.get( 'API_KEY_BETTER_UPTIME' )}` }, diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts index cd199482..ab7bf2eb 100644 --- a/apps/api/src/app/portfolio/current-rate.service.ts +++ b/apps/api/src/app/portfolio/current-rate.service.ts @@ -52,27 +52,24 @@ export class CurrentRateService { .then((dataResultProvider) => { const result: GetValueObject[] = []; - for (const dataGatheringItem of dataGatheringItems) { - if ( - dataResultProvider?.[dataGatheringItem.symbol]?.dataProviderInfo - ) { + for (const { dataSource, symbol } of dataGatheringItems) { + if (dataResultProvider?.[symbol]?.dataProviderInfo) { dataProviderInfos.push( - dataResultProvider[dataGatheringItem.symbol].dataProviderInfo + dataResultProvider[symbol].dataProviderInfo ); } - if (dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice) { + if (dataResultProvider?.[symbol]?.marketPrice) { result.push({ - dataSource: dataGatheringItem.dataSource, + dataSource, + symbol, date: today, - marketPrice: - dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice, - symbol: dataGatheringItem.symbol + marketPrice: dataResultProvider?.[symbol]?.marketPrice }); } else { quoteErrors.push({ - dataSource: dataGatheringItem.dataSource, - symbol: dataGatheringItem.symbol + dataSource, + symbol }); } } diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 326dda15..f2415dff 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -74,12 +74,15 @@ export class PortfolioController { @Get('details') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) + @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getDetails( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('range') dateRange: DateRange = 'max', + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string, @Query('withMarkets') withMarketsParam = 'false' ): Promise { @@ -95,6 +98,8 @@ export class PortfolioController { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, + filterBySymbol, filterByTags }); @@ -289,17 +294,22 @@ export class PortfolioController { @Get('dividends') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getDividends( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('groupBy') groupBy?: GroupBy, @Query('range') dateRange: DateRange = 'max', + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, + filterBySymbol, filterByTags }); @@ -356,21 +366,26 @@ export class PortfolioController { @Get('holdings') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) + @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getHoldings( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('holdingType') filterByHoldingType?: string, @Query('query') filterBySearchQuery?: string, @Query('range') dateRange: DateRange = 'max', + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, filterByHoldingType, filterBySearchQuery, + filterBySymbol, filterByTags }); @@ -386,17 +401,22 @@ export class PortfolioController { @Get('investments') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getInvestments( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('groupBy') groupBy?: GroupBy, @Query('range') dateRange: DateRange = 'max', + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, + filterBySymbol, filterByTags }); @@ -451,13 +471,16 @@ export class PortfolioController { @Get('performance') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(PerformanceLoggingInterceptor) + @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) @Version('2') public async getPerformanceV2( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('range') dateRange: DateRange = 'max', + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string, @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' ): Promise { @@ -466,6 +489,8 @@ export class PortfolioController { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, + filterBySymbol, filterByTags }); diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d88d925a..15ca227e 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -7,10 +7,10 @@ import { UserService } from '@ghostfolio/api/app/user/user.service'; import { getFactor } from '@ghostfolio/api/helper/portfolio.helper'; import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment'; import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account'; -import { AllocationClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/developed-markets'; -import { AllocationClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/emerging-markets'; import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment'; import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment'; +import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; +import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; @@ -413,15 +413,16 @@ export class PortfolioService { ); } - const dataGatheringItems = positions.map(({ dataSource, symbol }) => { + const assetProfileIdentifiers = positions.map(({ dataSource, symbol }) => { return { dataSource, symbol }; }); - const symbolProfiles = - await this.symbolProfileService.getSymbolProfiles(dataGatheringItems); + const symbolProfiles = await this.symbolProfileService.getSymbolProfiles( + assetProfileIdentifiers + ); const symbolProfileMap: { [symbol: string]: EnhancedSymbolProfile } = {}; for (const symbolProfile of symbolProfiles) { @@ -848,7 +849,7 @@ export class PortfolioService { if (isEmpty(historicalData)) { try { historicalData = await this.dataProviderService.getHistoricalRaw({ - dataGatheringItems: [ + assetProfileIdentifiers: [ { dataSource: DataSource.YAHOO, symbol: aSymbol } ], from: portfolioStart, @@ -953,7 +954,7 @@ export class PortfolioService { return !quantity.eq(0); }); - const dataGatheringItems = positions.map(({ dataSource, symbol }) => { + const assetProfileIdentifiers = positions.map(({ dataSource, symbol }) => { return { dataSource, symbol @@ -961,7 +962,10 @@ export class PortfolioService { }); const [dataProviderResponses, symbolProfiles] = await Promise.all([ - this.dataProviderService.getQuotes({ user, items: dataGatheringItems }), + this.dataProviderService.getQuotes({ + user, + items: assetProfileIdentifiers + }), this.symbolProfileService.getSymbolProfiles( positions.map(({ dataSource, symbol }) => { return { dataSource, symbol }; @@ -1193,16 +1197,16 @@ export class PortfolioService { userSettings ) : undefined, - allocationClusterRisk: + economicMarketClusterRisk: summary.ordersCount > 0 ? await this.rulesService.evaluate( [ - new AllocationClusterRiskDevelopedMarkets( + new EconomicMarketClusterRiskDevelopedMarkets( this.exchangeRateDataService, marketsTotalInBaseCurrency, markets.developedMarkets.valueInBaseCurrency ), - new AllocationClusterRiskEmergingMarkets( + new EconomicMarketClusterRiskEmergingMarkets( this.exchangeRateDataService, marketsTotalInBaseCurrency, markets.emergingMarkets.valueInBaseCurrency diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index 7c1df023..ae0260d8 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -1,8 +1,16 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; -import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { + DEFAULT_LANGUAGE_CODE, + PROPERTY_STRIPE_CONFIG +} from '@ghostfolio/common/config'; import { parseDate } from '@ghostfolio/common/helper'; -import { SubscriptionOffer, UserWithSettings } from '@ghostfolio/common/types'; +import { SubscriptionOffer } from '@ghostfolio/common/interfaces'; +import { + SubscriptionOfferKey, + UserWithSettings +} from '@ghostfolio/common/types'; import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type'; import { Injectable, Logger } from '@nestjs/common'; @@ -17,14 +25,17 @@ export class SubscriptionService { public constructor( private readonly configurationService: ConfigurationService, - private readonly prismaService: PrismaService + private readonly prismaService: PrismaService, + private readonly propertyService: PropertyService ) { - this.stripe = new Stripe( - this.configurationService.get('STRIPE_SECRET_KEY'), - { - apiVersion: '2024-04-10' - } - ); + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + this.stripe = new Stripe( + this.configurationService.get('STRIPE_SECRET_KEY'), + { + apiVersion: '2024-09-30.acacia' + } + ); + } } public async createCheckoutSession({ @@ -36,6 +47,18 @@ export class SubscriptionService { priceId: string; user: UserWithSettings; }) { + const subscriptionOffers: { + [offer in SubscriptionOfferKey]: SubscriptionOffer; + } = + ((await this.propertyService.getByKey(PROPERTY_STRIPE_CONFIG)) as any) ?? + {}; + + const subscriptionOffer = Object.values(subscriptionOffers).find( + (subscriptionOffer) => { + return subscriptionOffer.priceId === priceId; + } + ); + const checkoutSessionCreateParams: Stripe.Checkout.SessionCreateParams = { cancel_url: `${this.configurationService.get('ROOT_URL')}/${ user.Settings?.settings?.language ?? DEFAULT_LANGUAGE_CODE @@ -47,6 +70,13 @@ export class SubscriptionService { quantity: 1 } ], + locale: + (user.Settings?.settings + ?.language as Stripe.Checkout.SessionCreateParams.Locale) ?? + DEFAULT_LANGUAGE_CODE, + metadata: subscriptionOffer + ? { subscriptionOffer: JSON.stringify(subscriptionOffer) } + : {}, mode: 'payment', payment_method_types: ['card'], success_url: `${this.configurationService.get( @@ -73,17 +103,25 @@ export class SubscriptionService { public async createSubscription({ duration = '1 year', + durationExtension, price, userId }: { duration?: StringValue; + durationExtension?: StringValue; price: number; userId: string; }) { + let expiresAt = addMilliseconds(new Date(), ms(duration)); + + if (durationExtension) { + expiresAt = addMilliseconds(expiresAt, ms(durationExtension)); + } + await this.prismaService.subscription.create({ data: { + expiresAt, price, - expiresAt: addMilliseconds(new Date(), ms(duration)), User: { connect: { id: userId @@ -95,10 +133,21 @@ export class SubscriptionService { public async createSubscriptionViaStripe(aCheckoutSessionId: string) { try { + let durationExtension: StringValue; + const session = await this.stripe.checkout.sessions.retrieve(aCheckoutSessionId); + const subscriptionOffer: SubscriptionOffer = JSON.parse( + session.metadata.subscriptionOffer ?? '{}' + ); + + if (subscriptionOffer) { + durationExtension = subscriptionOffer.durationExtension; + } + await this.createSubscription({ + durationExtension, price: session.amount_total / 100, userId: session.client_reference_id }); @@ -121,7 +170,7 @@ export class SubscriptionService { return new Date(a.expiresAt) > new Date(b.expiresAt) ? a : b; }); - let offer: SubscriptionOffer = price ? 'renewal' : 'default'; + let offer: SubscriptionOfferKey = price ? 'renewal' : 'default'; if (isBefore(createdAt, parseDate('2023-01-01'))) { offer = 'renewal-early-bird-2023'; diff --git a/apps/api/src/app/symbol/symbol.controller.ts b/apps/api/src/app/symbol/symbol.controller.ts index b3b9dc10..89cdd416 100644 --- a/apps/api/src/app/symbol/symbol.controller.ts +++ b/apps/api/src/app/symbol/symbol.controller.ts @@ -2,6 +2,7 @@ import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard' import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; +import { LookupResponse } from '@ghostfolio/common/interfaces'; import type { RequestWithUser } from '@ghostfolio/common/types'; import { @@ -21,7 +22,6 @@ import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { isDate, isEmpty } from 'lodash'; -import { LookupItem } from './interfaces/lookup-item.interface'; import { SymbolItem } from './interfaces/symbol-item.interface'; import { SymbolService } from './symbol.service'; @@ -41,7 +41,7 @@ export class SymbolController { public async lookupSymbol( @Query('includeIndices') includeIndicesParam = 'false', @Query('query') query = '' - ): Promise<{ items: LookupItem[] }> { + ): Promise { const includeIndices = includeIndicesParam === 'true'; try { diff --git a/apps/api/src/app/symbol/symbol.service.ts b/apps/api/src/app/symbol/symbol.service.ts index 2baca18d..56befb9b 100644 --- a/apps/api/src/app/symbol/symbol.service.ts +++ b/apps/api/src/app/symbol/symbol.service.ts @@ -5,13 +5,15 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; -import { HistoricalDataItem } from '@ghostfolio/common/interfaces'; +import { + HistoricalDataItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { UserWithSettings } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { format, subDays } from 'date-fns'; -import { LookupItem } from './interfaces/lookup-item.interface'; import { SymbolItem } from './interfaces/symbol-item.interface'; @Injectable() @@ -84,7 +86,7 @@ export class SymbolService { try { historicalData = await this.dataProviderService.getHistoricalRaw({ - dataGatheringItems: [{ dataSource, symbol }], + assetProfileIdentifiers: [{ dataSource, symbol }], from: date, to: date }); @@ -104,8 +106,8 @@ export class SymbolService { includeIndices?: boolean; query: string; user: UserWithSettings; - }): Promise<{ items: LookupItem[] }> { - const results: { items: LookupItem[] } = { items: [] }; + }): Promise { + const results: LookupResponse = { items: [] }; if (!query) { return results; diff --git a/apps/api/src/app/user/update-user-setting.dto.ts b/apps/api/src/app/user/update-user-setting.dto.ts index 13a3a5d2..b34b6fae 100644 --- a/apps/api/src/app/user/update-user-setting.dto.ts +++ b/apps/api/src/app/user/update-user-setting.dto.ts @@ -64,6 +64,14 @@ export class UpdateUserSettingDto { @IsOptional() 'filters.assetClasses'?: string[]; + @IsString() + @IsOptional() + 'filters.dataSource'?: string; + + @IsString() + @IsOptional() + 'filters.symbol'?: string; + @IsArray() @IsOptional() 'filters.tags'?: string[]; diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 556d2834..54dafda2 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -4,10 +4,10 @@ import { environment } from '@ghostfolio/api/environments/environment'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment'; import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account'; -import { AllocationClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/developed-markets'; -import { AllocationClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/emerging-markets'; import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment'; import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment'; +import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; +import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; @@ -37,7 +37,7 @@ import { UserWithSettings } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { Prisma, Role, User } from '@prisma/client'; -import { differenceInDays } from 'date-fns'; +import { differenceInDays, subDays } from 'date-fns'; import { sortBy, without } from 'lodash'; const crypto = require('crypto'); @@ -60,6 +60,13 @@ export class UserService { return this.prismaService.user.count(args); } + public createAccessToken(password: string, salt: string): string { + const hash = crypto.createHmac('sha512', salt); + hash.update(password); + + return hash.digest('hex'); + } + public async getUser( { Account, id, permissions, Settings, subscription }: UserWithSettings, aLocale = locale @@ -176,7 +183,9 @@ export class UserService { Settings: Settings as UserWithSettings['Settings'], thirdPartyId, updatedAt, - activityCount: Analytics?.activityCount + activityCount: Analytics?.activityCount, + dataProviderGhostfolioDailyRequests: + Analytics?.dataProviderGhostfolioDailyRequests }; if (user?.Settings) { @@ -217,14 +226,14 @@ export class UserService { undefined, {} ).getSettings(user.Settings.settings), - AllocationClusterRiskDevelopedMarkets: - new AllocationClusterRiskDevelopedMarkets( + EconomicMarketClusterRiskDevelopedMarkets: + new EconomicMarketClusterRiskDevelopedMarkets( undefined, undefined, undefined ).getSettings(user.Settings.settings), - AllocationClusterRiskEmergingMarkets: - new AllocationClusterRiskEmergingMarkets( + EconomicMarketClusterRiskEmergingMarkets: + new EconomicMarketClusterRiskEmergingMarkets( undefined, undefined, undefined @@ -300,6 +309,7 @@ export class UserService { // Reset holdings view mode user.Settings.settings.holdingsViewMode = undefined; } else if (user.subscription?.type === 'Premium') { + currentPermissions.push(permissions.enableDataProviderGhostfolio); currentPermissions.push(permissions.reportDataGlitch); currentPermissions = without( @@ -358,13 +368,6 @@ export class UserService { }); } - public createAccessToken(password: string, salt: string): string { - const hash = crypto.createHmac('sha512', salt); - hash.update(password); - - return hash.digest('hex'); - } - public async createUser({ data }: { @@ -426,17 +429,6 @@ export class UserService { return user; } - public async updateUser(params: { - where: Prisma.UserWhereUniqueInput; - data: Prisma.UserUpdateInput; - }): Promise { - const { where, data } = params; - return this.prismaService.user.update({ - data, - where - }); - } - public async deleteUser(where: Prisma.UserWhereUniqueInput): Promise { try { await this.prismaService.access.deleteMany({ @@ -473,6 +465,32 @@ export class UserService { }); } + public async resetAnalytics() { + return this.prismaService.analytics.updateMany({ + data: { + dataProviderGhostfolioDailyRequests: 0 + }, + where: { + updatedAt: { + gte: subDays(new Date(), 1) + } + } + }); + } + + public async updateUser({ + data, + where + }: { + data: Prisma.UserUpdateInput; + where: Prisma.UserWhereUniqueInput; + }): Promise { + return this.prismaService.user.update({ + data, + where + }); + } + public async updateUserSetting({ emitPortfolioChangedEvent, userId, diff --git a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json index c63ba5c7..ac215738 100644 --- a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json +++ b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json @@ -1,6 +1,8 @@ { + "3": "The Three Musketeers", "7": "Lucky7", "42": "42 Coin", + "47": "President Trump", "300": "300 token", "365": "365Coin", "369": "Nikola Tesla Token", @@ -18,14 +20,15 @@ "2192": "LERNITAS", "$MAID": "MaidCoin", "$ROPE": "Rope", - "$TIME": "Madagascar Token", "$TREAM": "World Stream Finance", "00": "ZER0ZER0", "007": "007 coin", + "0DOG": "Bitcoin Dogs", "0KN": "0 Knowledge Network", "0NE": "Stone", "0X1": "0x1.tools: AI Multi-tool Plaform", "0XBTC": "0xBitcoin", + "0XCOCO": "0xCoco", "0XDEV": "DEVAI", "0XG": "0xGpu.ai", "0XGAS": "0xGasless", @@ -62,6 +65,7 @@ "1UP": "Uptrennd", "1WO": "1World", "2022M": "2022MOON", + "21BTC": "21.co Wrapped BTC", "21X": "21X", "2BACCO": "2BACCO Coin", "2BASED": "2Based Finance", @@ -81,6 +85,7 @@ "32BIT": "32Bitcoin", "360NS": "360 NOSCOPE INSTASWAP WALLBANG", "37C": "37Protocol", + "3AC": "THREE ARROWZ CAPITEL", "3AIR": "3air", "3CEO": "FLOKI SHIBA PEPE CEO", "3CRV": "LP 3pool Curve", @@ -90,6 +95,7 @@ "3KM": "3 Kingdoms Multiverse", "3P": "Web3Camp", "3ULL": "3ULL Coin", + "3ULLV1": "Playa3ull Games v1", "3XD": "3DChain", "404A": "404Aliens", "404BLOCKS": "404Blocks", @@ -97,12 +103,16 @@ "4ART": "4ART Coin", "4CHAN": "4Chan", "4CZ": "FourCZ", + "4DOGE": "4DOGE", "4JNET": "4JNET", "4MW": "For Meta World", + "4P": "4P FOUR", "4RZ": "4REALZA COIN", "4TOKEN": "Ignore Fud", + "4WIN": "4TRUMP", "4WMM": "4-Way Mirror Money", "50C": "50Cent", + "50TRUMP": "50TRUMP", "50X": "50x.com", "5IRE": "5ire", "77G": "GraphenTech", @@ -112,15 +122,18 @@ "8BT": "8 Circuit Studios", "8PAY": "8Pay", "8X8": "8X8 Protocol", + "99BTC": "99 Bitcoins", "9DOGS": "NINE DOGS", "9GAG": "9GAG", "9MM": "Shigure UI", "A": "Alpha Token", + "A1INCH": "1inch (Arbitrum Bridge)", "A2A": "A2A", "A4": "A4 Finance", "A4M": "AlienForm", "A51": "A51 Finance", "A5T": "Alpha5", + "A8": "Ancient8", "AA": "Alva", "AAA": "Moon Rabbit", "AAB": "AAX Token", @@ -129,29 +142,44 @@ "AAG": "AAG Ventures", "AAI": "AutoAir AI", "AAPX": "AMPnet", + "AARDY": "Baby Aardvark", + "AARK": "Aark", "AART": "ALL.ART", "AAST": "AASToken", "AAT": "Agricultural Trade Chain", "AAVE": "Aave", + "AAVEE": "AAVE.e (Avalanche Bride)", + "AAVEGOTCHIFOMO": "Aavegotchi FOMO", + "AAX": "Academic Labs", "AAZ": "ATLAZ", + "AB1INCH": "1inch (Avalanche Bride)", "ABA": "EcoBall", "ABBC": "ABBC Coin", "ABC": "ABC Chain", "ABCC": "ABCC Token", "ABCD": "Crypto Inu", + "ABCM": "ABCMETA", + "ABCRV": "Curve DAO Token (Arbitrum Bridge)", "ABD": "AB DEFI", + "ABDS": "ABDS Token", + "ABE": "ABE", "ABEL": "Abelian", "ABET": "Altbet", "ABEY": "Abey", "ABIC": "Arabic", "ABJ": "Abjcoin", "ABL": "Airbloc", + "ABLE": "Able Finance", + "ABLINK": "Chainlink (Arbitrum Bridge)", "ABN": "Antofy", "ABO": "Albino", "ABOND": "ApeBond", "ABONDV1": "ApeSwap", "ABR": "Allbridge", "ABT": "ArcBlock", + "ABUL": "Abulaba", + "ABUNI": "Uniswap Protocol Token (Arbitrum Bridge)", + "ABUSDC": "USD Coin (Arbitrum Bridge)", "ABX": "Arbidex", "ABY": "ArtByte", "ABYSS": "Abyss Finance", @@ -167,14 +195,17 @@ "ACDC": "Volt", "ACE": "Fusionist", "ACEN": "Acent", + "ACEO": "Ace of Pentacles", "ACES": "AcesCoin", "ACET": "Acet", "ACETH": "Acether", "ACH": "Alchemy Pay", + "ACHAIN": "Achain", "ACHC": "AchieveCoin", "ACHI": "achi", "ACID": "AcidCoin", "ACK": "Arcade Kingdoms", + "ACL": "Auction Light", "ACM": "AC Milan Fan Token", "ACN": "AvonCoin", "ACOIN": "ACoin", @@ -184,7 +215,8 @@ "ACRE": "Arable Protocol", "ACRIA": "Acria.AI", "ACS": "Access Protocol", - "ACT": "Achain", + "ACSI": "ACryptoSI", + "ACT": "Act I The AI Prophecy", "ACTA": "Acta Finance", "ACTIN": "Actinium", "ACTN": "Action Coin", @@ -197,9 +229,12 @@ "ADAB": "Adab Solutions", "ADACASH": "ADACash", "ADAI": "Aave DAI", + "ADAM": "Adam Back", "ADANA": "Adanaspor Fan Token", "ADAO": "ADADao", "ADAPAD": "ADAPad", + "ADASOL": "ADA", + "ADASTRA": "Ad Astra", "ADAT": "Adadex Tools", "ADAX": "ADAX", "ADB": "Adbank", @@ -208,6 +243,7 @@ "ADD": "ADD.xyz", "ADDAMS": "ADDAMS AI", "ADDY": "Adamant", + "ADE": "AADex Finance", "ADEL": "Akropolis Delphi", "ADF": "Art de Finance", "ADH": "Adhive", @@ -218,6 +254,7 @@ "ADN": "Aladdin", "ADNT": "Aiden", "ADO": "ADO Protocol", + "ADOG": "America Dog", "ADOGE": "Arbidoge", "ADON": "Adonis", "ADP": "Adappter Token", @@ -270,6 +307,7 @@ "AFR": "Afreum", "AFRO": "Afrostar", "AFROX": "AfroDex", + "AFSUI": "Aftermath Staked SUI", "AFTT": "Africa Trading Chain", "AFX": "Afrix", "AFYON": "Afyonspor Fan Token", @@ -278,12 +316,16 @@ "AGA": "AGA Token", "AGATA": "Agatech", "AGB": "Apes Go Bananas", + "AGC": "Argocoin", + "AGENT": "AgentLayer", "AGET": "Agetron", + "AGETH": "Kelp Gain", "AGEUR": "agEUR", "AGF": "Augmented Finance", "AGG": "AGG", "AGI": "Delysium", "AGII": "AGII", + "AGIL": "Agility LSD", "AGIV1": "SingularityNET v1", "AGIX": "SingularityNET", "AGLA": "Angola", @@ -298,6 +340,7 @@ "AGRS": "Agoras Token", "AGS": "Aegis", "AGT": "aGifttoken", + "AGURI": "Aguri-Chan", "AGV": "Astra Guild Ventures", "AGVC": "AgaveCoin", "AGVE": "Agave", @@ -305,6 +348,7 @@ "AHOO": "Ahoolee", "AHT": "AhaToken", "AI": "Sleepless", + "AI16Z": "ai16z", "AIA": "AIA Chain", "AIAI": "All In AI", "AIAKITA": "AiAkita", @@ -316,11 +360,13 @@ "AIBK": "AIB Utility Token", "AIBU": "AIBUZZ TOKEN", "AIC": "AI Crypto", + "AICELL": "AICell", "AICH": "AIChain", "AICO": "AICON", "AICODE": "AI CODE", "AICORE": "AICORE", "AID": "AidCoin", + "AIDA": "Ai-Da robot", "AIDI": "Aidi Inu", "AIDOC": "AI Doctor", "AIDOG": "AiDoge", @@ -333,6 +379,7 @@ "AIEN": "AIENGLISH", "AIF": "AI FREEDOM TOKEN", "AIFLOKI": "AI Floki", + "AIFUN": "AI Agent Layer", "AIG": "A.I Genesis", "AIGPU": "AIGPU Token", "AII": "Artificial Idiot", @@ -340,13 +387,16 @@ "AIKEK": "AlphaKEK.AI", "AILINK": "AiLink Token", "AIM": "ModiHost", + "AIMAGA": "Presidentexe", "AIMARKET": "Acria.AI AIMARKET", "AIMBOT": "AimBot AI", "AIMEE": "AIMEE", + "AIMET": "AI Metaverse", "AIMR": "MeromAI", "AIMS": "HighCastle Token", "AIMX": "Aimedis", "AIN": "AI Network", + "AINA": "Ainastasia", "AINN": "AINN", "AINU": "Ainu Token", "AION": "Aion", @@ -358,11 +408,14 @@ "AIPEPE": "AI PEPE KING", "AIPG": "AI Power Grid", "AIPIN": "AI PIN", + "AIPO": "Aipocalypto", "AIR": "Altair", "AIRB": "BillionAir", "AIRBTC": "AIRBTC", + "AIRDROP": "AIRDROP2049", "AIRE": "Tokenaire", "AIRI": "aiRight", + "AIRIAN": "AIRian", "AIRT": "Aircraft", "AIRTNT": "Tenti", "AIRTOKEN": "AirToken", @@ -370,6 +423,7 @@ "AIS": "AISwap", "AISCII": "AISCII", "AISHIB": "ARBSHIB", + "AIST": "Artificial intelligence staking token", "AIT": "AIT Protocol", "AITECH": "Artificial Intelligence Utility Token", "AITEK": "AI Technology", @@ -382,22 +436,32 @@ "AIUS": "Arbius", "AIWALLET": "AiWallet Token", "AIX": "Aigang", + "AIXBT": "aixbt by Virtuals", + "AIXERC": "AI-X", "AJNA": "Ajna Protocol", + "AJUN": "Ajuna Network", "AK12": "AK12", "AKA": "Akroma", "AKI": "Aki Network", + "AKIT": "Akita Inu", "AKITA": "Akita Inu", + "AKITAI": "AKITA INU", "AKITAX": "Akitavax", "AKN": "Akoin", "AKNC": "Aave KNC v1", + "AKOBI": "AKOBI", "AKREP": "Antalyaspor Token", "AKRO": "Akropolis", "AKT": "Akash Network", "AKTIO": "AKTIO Coin", - "ALA": "ALA", + "AL": "ArchLoot", + "ALA": "Alanyaspor Fan Token", "ALAN": "Alan the Alien", + "ALASKA": "Alaska", + "ALATOKEN": "ALA", "ALB": "Alien Base", "ALBART": "Albärt", + "ALBE": "ALBETROS", "ALBEDO": "ALBEDO", "ALBT": "AllianceBlock", "ALC": "Arab League Coin", @@ -409,6 +473,7 @@ "ALD": "AladdinDAO", "ALDIN": "Alaaddin.ai", "ALE": "Ailey", + "ALEO": "ALEO", "ALEPH": "Aleph.im", "ALEX": "ALEX Lab", "ALEXANDRITE": "Alexandrite", @@ -423,7 +488,9 @@ "ALIAS": "Alias", "ALIC": "AliCoin", "ALICE": "My Neighbor Alice", + "ALICEA": "Alice AI", "ALIEN": "AlienCoin", + "ALIENPEP": "Alien Pepe", "ALIF": " ALIF COIN", "ALINK": "Aave LINK v1", "ALIS": "ALISmedia", @@ -432,22 +499,29 @@ "ALIX": "AlinX", "ALKI": "Alkimi", "ALLBI": "ALL BEST ICO", + "ALLC": "All Crypto Mechanics", "ALLEY": "NFT Alley", "ALLIN": "All in", "ALM": "Alium Finance", + "ALMAN": "Alman", "ALMC": "Awkward Look Monkey Club", "ALME": "Alita", "ALN": "Aluna", + "ALNV1": "Aluna v1", "ALOHA": "Aloha", "ALOT": "Dexalot", "ALP": "Alphacon", "ALPA": "Alpaca", "ALPACA": "Alpaca Finance", + "ALPACAS": "Bitcoin Mascot", "ALPH": "Alephium", "ALPHA": "Alpha Finance Lab", "ALPHAAI": "Alpha AI", "ALPHABET": "Alphabet", "ALPHAC": "Alpha Coin", + "ALPHAF": "Alpha Fi", + "ALPHAG": "Alpha Gardeners", + "ALPHAPETTO": "Alpha Petto Shells", "ALPHAS": "Alpha Shards", "ALPHR": "Alphr", "ALPINE": "Alpine F1 Team Fan Token", @@ -465,6 +539,7 @@ "ALUSD": "Alchemix USD", "ALUX": "Alux Bank", "ALV": "Allive", + "ALV1": "ArchLoot v1", "ALVA": "Alvara Protocol", "ALWAYS": "Always Evolving", "ALX": "ALAX", @@ -484,6 +559,9 @@ "AMDC": "Allmedi Coin", "AMDG": "AMDG", "AME": "Amepay", + "AMER": "America", + "AMERI": "AMERICAN EAGLE", + "AMERIC": "American True Hero", "AMERICA": "America", "AMERICANCOIN": "AmericanCoin", "AMF": "AddMeFast", @@ -514,6 +592,7 @@ "ANAL": "AnalCoin", "ANALOS": "analoS", "ANALY": "Analysoor", + "ANAT": "Anatolia Token", "ANB": "Angryb", "ANC": "Anchor Protocol", "ANCHOR": "AnchorSwap", @@ -526,15 +605,21 @@ "ANDWU": "Chinese Andy", "ANDX": "Arrano", "ANDY": "ANDY", + "ANDYB": "AndyBlast", + "ANDYBNB": "Andy", + "ANDYBSC": "ANDY", + "ANDYMAN": "ANDYMAN", + "ANDYSOL": "Andy on SOL", "ANGEL": "Crypto Angel", "ANGL": "Angel Token", "ANGLE": "ANGLE", "ANGO": "Aureus Nummus Gold", "ANGRYSLERF": "ANGRYSLERF", - "ANI": "Animecoin", + "ANI": "Anime Token", "ANIM": "Animalia", "ANIMA": "Realm Anima", "ANIME": "Anime", + "ANIMECOIN": "Animecoin", "ANJ": "Aragon Court", "ANJI": "Anji", "ANK": "AlphaLink", @@ -551,6 +636,7 @@ "ANONCOIN": "Anoncoin", "ANRX": "AnRKey X", "ANS": "ANS Crypto Coin", + "ANSOM": "Ansom", "ANSR": "Answerly", "ANT": "Aragon", "ANTC": "AntiLitecoin", @@ -559,11 +645,14 @@ "ANTI": "Anti Bitcoin", "ANTIS": "Antis Inu", "ANTS": "ANTS Reloaded", + "ANTT": "Antara Token", "ANUS": "URANUS", "ANV": "Aniverse", + "ANVL": "Anvil", "ANW": "Anchor Neural World", "ANY": "Anyswap", "ANYONE": "ANyONe Protocol", + "ANZENUSD": "Anzen Finance", "AOC": "Alickshundra Occasional-Cortex", "AOG": "AgeOfGods", "AOK": "AOK", @@ -576,12 +665,15 @@ "APCG": "ALLPAYCOIN", "APD": "Aptopad", "APE": "ApeCoin", - "APECOIN": "Asia Pacific Electronic Coin", "APED": "Baddest Alpha Ape Bundle", - "APES": "Alpha Petto Shells", + "APEDEV": "The dev is an Ape", + "APEFUN": "Ape", + "APEPE": "Ape and Pepe", + "APES": "APES", "APETARDIO": "Apetardio", "APEWIFHAT": "ApeWifHat", "APEX": "ApeX Protocol", + "APEXA": "Apex AI", "APEXCOIN": "ApexCoin", "APEXT": "ApexToken", "APFC": "APF coin", @@ -594,11 +686,15 @@ "APL": "Apollo Currency", "APM": "apM Coin", "APN": "Apron", + "APO": "Apollo Caps ETF", "APOD": "AirPod", + "APOL": "Apollo FTW", + "APOLL": "Apollon Limassol", "APOLLO": "Apollo Crypto", "APP": "Moon App", "APPA": "Dappad", "APPC": "AppCoins", + "APPEALUSD": "Appeal dollar", "APPLE": "AppleSwap", "APRICOT": "Apricot Finance", "APRIL": "April", @@ -626,6 +722,7 @@ "AQUAC": "Aquachain", "AQUACITY": "Aquacity", "AQUAGOAT": "Aqua Goat", + "AQUAGOATV1": "Aqua Goat v1", "AQUAP": "Planet Finance", "AQUARI": "Aquari", "AR": "Arweave", @@ -635,14 +732,17 @@ "ARB": "Arbitrum", "ARBI": "Arbi", "ARBIT": "Arbit Coin", + "ARBP": "ARB Protocol", "ARBS": "Arbswap", "ARBT": "ARBITRAGE", "ARBUZ": "ARBUZ", - "ARC": "ArcticCoin", - "ARCA": "Arca", + "ARC": "Neko Arc", + "ARCA": "Legend of Arcadia", "ARCAD": "Arcadeum", "ARCADE": "ARCADE", + "ARCADECITY": "Arcade City", "ARCADEF": "arcadefi", + "ARCADEN": "ArcadeNetwork", "ARCANE": "Arcane Token", "ARCAS": "Arcas", "ARCH": "Archway", @@ -650,10 +750,10 @@ "ARCHCOIN": "ArchCoin", "ARCHE": "Archean", "ARCHIVE": "Chainback", - "ARCHL": "ArchLoot", "ARCO": "AquariusCoin", "ARCONA": "Arcona", "ARCT": "ArbitrageCT", + "ARCTICCOIN": "ArcticCoin", "ARCX": "ARC Governance", "ARDR": "Ardor", "ARDX": "ArdCoin", @@ -672,6 +772,7 @@ "ARI10": "Ari10", "ARIA": "Legends of Aria", "ARIA20": "Arianee", + "ARIT": "ArithFi", "ARIX": "Arix", "ARK": "ARK", "ARKEN": "Arken Finance", @@ -680,12 +781,15 @@ "ARKM": "Arkham", "ARKN": "Ark Rivals", "ARKY": "Arky", + "ARKYS": "Arky Satoshi's Dog", "ARM": "Armory Coin", "ARMA": "Aarma", "ARMOR": "ARMOR", "ARMR": "ARMR", "ARMS": "2Acoin", + "ARMY": "Army of Fortune Coin", "ARNA": "ARNA Panacea", + "ARNC": "Arnoya classic", "ARNM": "Arenum", "ARNO": "ARNO", "ARNX": "Aeron", @@ -715,9 +819,11 @@ "ARTG": "Goya Giant Token", "ARTH": "ARTH", "ARTI": "Arti Project", + "ARTIF": "Artificial Intelligence", "ARTII": "ARTII Token", "ARTL": "ARTL", "ARTM": "ARTM", + "ARTMETIS": "Staked Metis Token", "ARTP": "ArtPro", "ARTR": "Artery Network", "ARTT": "ARTT Network", @@ -738,6 +844,7 @@ "ASG": "Asgard", "ASGC": "ASG", "ASH": "ASH", + "ASHS": "AshSwap", "ASI": "Artificial Superintelligence Alliance", "ASIA": "Asia Coin", "ASIMI": "ASIMI", @@ -745,10 +852,12 @@ "ASK": "Permission Coin", "ASKO": "Asko", "ASM": "Assemble Protocol", + "ASMO": "AS Monaco Fan Token", "ASN": "Ascension Coin", "ASNT": "Assent Protocol", "ASP": "Aspire", "ASPC": "Astropup Coin", + "ASPIRIN": "Aspirin", "ASPO": "ASPO Shards", "ASQT": "ASQ Protocol", "ASR": "AS Roma Fan Token", @@ -767,13 +876,16 @@ "ASTRAFER": "Astrafer", "ASTRAFERV1": "Astrafer v1", "ASTRAL": "Astral", - "ASTRO": "AstroSwap", + "ASTRO": "Astroport", "ASTROC": "Astroport Classic", "ASTROLION": "AstroLion", "ASTRONAUT": "Astronaut", + "ASTROO": "Astroon", "ASTROP": "AstroPepeX", + "ASTROS": "AstroSwap", "ASTX": "Asterix Labs", "ASUNA": "Asuna Hentai", + "ASUSHI": "Sushi (Arbitrum Bridge)", "ASVA": "Asva", "ASW": "AdaSwap", "ASY": "ASYAGRO", @@ -790,19 +902,23 @@ "ATFI": "Atlantic Finance Token", "ATFS": "ATFS Project", "ATH": "Aethir", + "ATHCAT": "ATH CAT", "ATHE": "Atheios", "ATHEN": "Athenas AI", + "ATHENA": "Athena DexFi", "ATHVODKA": "All Time High Vodka", "ATID": "AstridDAO Token", "ATK": "Attack Wagon", "ATKN": "A-Token", "ATL": "ATLANT", + "ATLA": "Atleta Network", "ATLAS": "Star Atlas", "ATLX": "Atlantis Loans Polygon", "ATM": "Atletico de Madrid Fan Token", "ATMA": "ATMA", "ATMC": "Autumncoin", "ATMCHAIN": "ATMChain", + "ATMCOIN": "ATM", "ATMI": "Atonomi", "ATMOS": "Novusphere", "ATN": "ATN", @@ -820,6 +936,7 @@ "ATRI": "Atari Token", "ATRNO": "AETERNUS", "ATROFA": "Atrofarm", + "ATRS": "Attarius Network", "ATS": "Atlas DEX", "ATT": "Attila", "ATTR": "Attrace", @@ -835,6 +952,7 @@ "AUDT": "Auditchain", "AUDX": "eToro Australian Dollar", "AUK": "Aukcecoin", + "AUKI": "Auki Labs", "AUN": "Authoreon", "AUNIT": "Aunit", "AUPC": "Authpaper", @@ -850,19 +968,21 @@ "AURUM": "Aurum", "AURY": "Aurory", "AUSCM": "Auric Network", - "AUSD": "Appeal dollar", + "AUSD": "AUSD", "AUSDC": "Aave USDC v1", "AUSDT": "aUSDT", "AUT": "Autoria", "AUTHORSHIP": "Authorship", "AUTISM": "AUTISM", "AUTO": "Auto", - "AUTON": "Autonio", "AUTUMN": "Autumn", + "AUVERSE": "AuroraVerse", "AUX": "Auxilium", "AV": "Avatar Coin", "AVA": "Travala", + "AVACN": "AVACOIN", "AVAI": "Orca AVAI", + "AVAIL": "Avail", "AVAL": "Avaluse", "AVALON": "Avalon", "AVALOX": "AVALOX", @@ -873,8 +993,11 @@ "AVAV": "AVAV", "AVAX": "Avalanche", "AVAXIOU": "Avalanche IOU", + "AVB": "Autonomous Virtual Beings", "AVDO": "AvocadoCoin", "AVE": "Avesta", + "AVEN": "Aventis AI", + "AVENT": "Aventa", "AVG": "Avocado DAO", "AVH": "Animation Vision Cash", "AVI": "Aviator", @@ -921,6 +1044,8 @@ "AXN": "Axion", "AXNT": "Axentro", "AXO": "Axo", + "AXOL": "Axol", + "AXON": "AxonDAO Governance Token", "AXPR": "aXpire", "AXR": "AXRON", "AXS": "Axie Infinity Shards", @@ -962,6 +1087,7 @@ "BABY": "BabySwap", "BABYANDY": "Baby Andy", "BABYB": "Baby Bali", + "BABYBI": "Baby Bitcoin", "BABYBINANCE": "BABYBINANCE", "BABYBITC": "BabyBitcoin", "BABYBNB": "BabyBNB", @@ -972,12 +1098,17 @@ "BABYBOMEOW": "Baby of BOMEOW", "BABYBONK": "Baby Bonk", "BABYBTC": "BABYBTC", + "BABYC": "Baby Cat", "BABYCAT": "Baby Cat Coin", + "BABYCATE": "BabyCate", "BABYCATS": "Baby Cat Coin", "BABYCEO": "Baby Doge CEO", "BABYCRASH": "BabyCrash", "BABYCRAZYT": "BABY CRAZY TIGER", "BABYCUBAN": "Baby Cuban", + "BABYCZHAO": "Baby Czhao", + "BABYD": "Baby Dragon", + "BABYDENG": "Baby Moo Deng", "BABYDOGE": "BabyDoge", "BABYDOGEINU": "BABY DOGE INU", "BABYDOGEZILLA": "BabyDogeZilla", @@ -986,10 +1117,14 @@ "BABYFB": "Baby Floki Billionaire", "BABYFLOKI": "BabyFloki", "BABYFLOKIZILLA": "BabyFlokiZilla", + "BABYG": "BabyGME", "BABYGME": "Baby GameStop", + "BABYGOAT": "Baby Goat", "BABYGOLDEN": "Baby Golden Coin", "BABYGROK": "Baby Grok", "BABYGUMMY": "BABY GUMMY", + "BABYHARRIS": "Baby Harris", + "BABYHIPPO": "BABY HIPPO", "BABYHKTIGER": "BabyHkTiger", "BABYHONK": "Baby Honk", "BABYJERRY": "Baby Jerry", @@ -997,19 +1132,31 @@ "BABYKABOSU": "Baby Kabosu", "BABYKITTY": "BabyKitty", "BABYLONG": "Baby Long", + "BABYM": "BabyMAGA", "BABYMAGA": "Baby Maga", + "BABYME": "Baby Meme Coin", "BABYMEME": "Baby Memecoin", + "BABYMIGGLES": "Baby Miggles", + "BABYMO": "Baby Moon Floki", + "BABYMU": "Baby Musk", "BABYMUSK": "Baby Musk", "BABYMYRO": "Babymyro", + "BABYNEIRO": "Baby Neiro", "BABYOKX": "BABYOKX", + "BABYP": "BabyPepe", + "BABYPEIPEI": "Baby PeiPei", "BABYPEPE": "Babypepe (BSC)", + "BABYPNUT": "Baby Pnut", + "BABYPOPCAT": "Baby PopCat", "BABYPORK": "Baby Pepe Fork", "BABYRATS": "Baby Rats", "BABYRWA": "BabyRWA", + "BABYS": "Baby Slerf", "BABYSAITAMA": "Baby Saitama", "BABYSHARK": "Baby Shark", "BABYSHIB": "Baby Shiba Inu", "BABYSHIBAINU": "Baby Shiba Inu", + "BABYSHIRO": "Baby Shiro Neko", "BABYSHIV": "Baby Shiva", "BABYSLERF": "BabySlerf", "BABYSOL": "Baby Solana", @@ -1019,15 +1166,19 @@ "BABYTK": "Baby Tiger King", "BABYTOMCAT": "Baby Tomcat", "BABYTOSHI": "Baby Toshi", + "BABYTR": "BABYTRUMP", "BABYTROLL": "Baby Troll", "BABYTRUMP": "BABYTRUMP", "BABYWIF": "babydogwifhat", + "BABYWLFI": "Baby WLFI", "BABYX": "Baby X", "BAC": "Basis Cash", "BACK": "DollarBack", "BACOIN": "BACoin", "BACON": "BaconDAO (BACON)", "BAD": "Bad Idea AI", + "BADA": "Bad Alien Division", + "BADC": "BADCAT", "BADCAT": "Andy’s Alter Ego", "BADGER": "Badger DAO", "BAFC": "BabyApeFunClub", @@ -1041,32 +1192,46 @@ "BAKAC": "Baka Casino", "BAKE": "BakeryToken", "BAKED": "Baked", + "BAKEDB": "Baked Beans Token", + "BAKEDTOKEN": "Baked", + "BAKSO": "Disney Sumatran Tiger", "BAKT": "Backed Protocol", "BAL": "Balancer", "BALA": "Shambala", "BALD": "Bald", "BALIN": "Balin Bank", + "BALL": "Game 5 BALL", "BALLZ": "Wolf Wif", + "BALN": "Balanced", "BALPHA": "bAlpha", "BALT": "Brett's cat", "BALTO": "Balto Token", "BAMA": "BabyAMA", "BAMBIT": "BAMBIT", "BAMBOO": "BambooDeFi", + "BAMITCOIN": "Bamit", "BAN": "Banano", "BANANA": "Banana Gun", + "BANANAF": "Banana For Scale", "BANANAS": "Monkey Peepo", "BANC": "Babes and Nerds", "BANCA": "BANCA", "BAND": "Band Protocol", "BANDEX": "Banana Index", + "BANDIT": "Bandit on Base", "BANG": "BANG", + "BANGY": "BANGY", "BANK": "Float Protocol", + "BANKA": "Bank AI", + "BANKC": "Bankcoin", + "BANKER": "BankerCoinAda", "BANKETH": "BankEth", + "BANKSY": "BANKSY", "BANNER": "BannerCoin", "BANUS": "Banus.Finance", "BANX": "Banx.gg", "BAO": "Bao Finance", + "BAOBAO": "BaoBao", "BAOE": "Business Age of Empires", "BAOM": "Battle of Memes", "BAOS": "BaoBaoSol", @@ -1074,15 +1239,33 @@ "BARA": "Capybara", "BARC": "The Blu Arctic Water Company", "BAREBEARS": "BAREBEARS", + "BARIO": "Bario", "BARK": "Bored Ark", "BARRON": "Time Traveler", + "BARS": "Banksters Token", + "BARSIK": "Hasbulla's Cat", "BART": "BarterTrade", + "BARTKRC": "BART Token", + "BARY": "Bary", "BAS": "Basis Share", - "BASE": "Base Protocol", "BASEAI": "BaseAI", + "BASECAT": "BASE CAT", + "BASECOIN": "BASECOIN", "BASED": "Based Money", "BASEDAI": "BasedAI", + "BASEDCHILL": "Based Chill Guy", + "BASEDCOPE": "COPE", + "BASEDFINANCE": "Based", + "BASEDHOPPY": "Based Hoppy (basedhoppy.vip)", + "BASEDP": "Based Pepe", + "BASEDR": "Based Rabbit", + "BASEDS": "BasedSwap", + "BASEDV1": "Based Money v1", "BASEHEROES": "Baseheroes", + "BASEPROTOCOL": "Base Protocol", + "BASESWAPX": "BaseX", + "BASEVE": "Base Velocimeter", + "BASEX": "Base Terminal", "BASH": "LuckChain", "BASHC": "BashCoin", "BASHOS": "Bashoswap", @@ -1094,6 +1277,8 @@ "BASTET": "Bastet Goddess", "BAT": "Basic Attention Token", "BATH": "Battle Hero", + "BATMAN": "BATMAN", + "BATO": "Batonex Token", "BATS": "Batcoin", "BAVA": "Baklava", "BAX": "BABB", @@ -1109,6 +1294,7 @@ "BBC": "Bull BTC Club", "BBCC": "BaseballCardCoin", "BBCG": "BBC Gold Coin", + "BBCH": "Binance Wrapped BCH", "BBCT": "TraDove B2BCoin", "BBDC": "Block Beats Network", "BBDT": "BBD Token", @@ -1122,19 +1308,24 @@ "BBL": "beoble", "BBN": "BBNCOIN", "BBO": "Bigbom", + "BBONK": "BitBonk", "BBOS": "Blackbox Foundation", "BBP": "BiblePay", "BBR": "Boolberry", "BBRETT": "Baby Brett", "BBS": "BBSCoin", + "BBSOL": "Bybit Staked SOL", "BBT": "BitBook", "BBTC": "Binance Wrapped BTC", "BBTF": "Block Buster Tech Inc", "BBUSD": "BounceBit USD", + "BBYDEV": "The Dev is a Baby", "BC": "Bitcoin Confidential", "BCA": "Bitcoin Atom", "BCAC": "Business Credit Alliance Chain", + "BCAI": "Bright Crypto Ai", "BCAP": "Blockchain Capital", + "BCAPV1": "Blockchain Capital v1", "BCAT": "BitClave", "BCAU": "BetaCarbon", "BCB": "BCB Blockchain", @@ -1183,7 +1374,7 @@ "BD20": "BRC-20 DEX", "BDAY": "Birthday Cake", "BDB": "Big Data Block", - "BDC": "Based", + "BDC": "BILLION•DOLLAR•CAT", "BDCC": "BDCC COIN", "BDCLBSC": "BorderCollieBSC", "BDG": "BitDegree", @@ -1205,7 +1396,7 @@ "BEAMMW": "Beam", "BEAN": "Bean", "BEANS": "Moonbeans", - "BEAST": "CryptoBeast", + "BEAST": "MrBeast", "BEAT": "BEAT Token", "BEATLES": "JohnLennonC0IN", "BEATS": "Sol Beats", @@ -1214,8 +1405,11 @@ "BECH": "Beauty Chain", "BECN": "Beacon", "BECO": "BecoSwap Token", + "BECX": "BETHEL", "BED": "Bankless BED Index", "BEE": "Herbee", + "BEEF": "PepeBull", + "BEEG": "Beeg Blue Whale", "BEEP": "BEEP", "BEER": "BEERCOIN", "BEERUSCAT": "BeerusCat", @@ -1229,19 +1423,27 @@ "BEFX": "Belifex", "BEFY": "Befy Protocol", "BEG": "BEG", + "BEIBEI": "Chinese BEIBEI", "BEL": "Bella Protocol", "BELA": "Bela", + "BELL": "Bellscoin", + "BELLE": "Isabelle", + "BELLS": "Bellscoin", "BELR": "Belrium", "BELT": "Belt", "BELUGA": "Beluga", "BEM": "BEMIL Coin", + "BEMC": "BemChain", "BEMD": "Betterment Digital", "BEN": "Ben", "BEND": "BendDao", + "BENDER": "BENDER", "BENDOG": "Ben the Dog", "BENG": "Based Peng", + "BENI": "Beni", "BENJACOIN": "Benjacoin", - "BENJI": "BenjiRolls", + "BENJI": "Basenji", + "BENJIROLLS": "BenjiRolls", "BENK": "BENK", "BENT": "Bent Finance", "BENTO": "Bento", @@ -1252,9 +1454,12 @@ "BEPE": "Blast Pepe", "BEPR": "Blockchain Euro Project", "BEPRO": "BEPRO Network", + "BERF": "BERF", "BERN": "BERNcash", "BERNIE": "BERNIE SENDERS", "BERRY": "Berry", + "BERRYS": "BerrySwap", + "BERT": "Bertram The Pomeranian", "BES": "battle esports coin", "BESA": "Besa Gaming", "BESHARE": "Beshare Token", @@ -1264,6 +1469,7 @@ "BETACOIN": "BetaCoin", "BETBOX": "betbox", "BETF": "Betform", + "BETFI": "Betfin", "BETH": "Beacon ETH", "BETHER": "Bethereum", "BETR": "BetterBetting", @@ -1290,6 +1496,7 @@ "BFK WARZONE": "BFK Warzone", "BFLOKI": "BurnFloki", "BFLY": "Butterfly Protocol", + "BFM": "BenefitMine", "BFT": "BF Token", "BFTB": "Brazil Fan Token", "BFTC": "BITS FACTOR", @@ -1297,12 +1504,14 @@ "BG": "BunnyPark Game", "BGB": "Bitget token", "BGBP": "Binance GBP Stable Coin", + "BGBV1": "Bitget Token v1", "BGC": "Bee Token", "BGG": "BGG Token", "BGLD": "Based Gold", "BGONE": "BigONE Token", "BGPT": "BlockGPT", "BGS": "Battle of Guardians Share", + "BGSOL": "Bitget SOL Staking", "BGUY": "The Big Guy", "BGVT": "Bit Game Verse Token", "BHAO": "Bithao", @@ -1323,6 +1532,7 @@ "BIBL": "Biblecoin", "BIBO": "Bible of Memes", "BIC": "Bikercoins", + "BICHO": "bicho", "BICITY": "BiCity AI Projects", "BICO": "Biconomy", "BICS": "Biceps", @@ -1335,10 +1545,13 @@ "BIDP": "BID Protocol", "BIDR": "Binance IDR Stable Coin", "BIDZ": "BIDZ Coin", + "BIDZV1": "BIDZ Coin v1", "BIFI": "Beefy.Finance", "BIFIF": "BiFi", "BIG": "Big Eyes", "BIGBANGCORE": "BigBang Core", + "BIGCOIN": "BigCoin", + "BIGFOOT": "BigFoot Town", "BIGHAN": "BighanCoin", "BIGLEZ": "THE BIG LEZ SHOW", "BIGMIKE": "Big Mike", @@ -1350,11 +1563,17 @@ "BIIS": "biis (Ordinals)", "BIKI": "BIKI", "BILL": "TillBilly", + "BILLI": "Billi", "BILLICAT": "BilliCat", + "BILLY": "Billy ", + "BILLYBSC": "BILLY", "BIM": "BitminerCoin", + "BINANCED": "BinanceDog On Sol", + "BINANCEDOG": "Binancedog", "BIND": "Compendia", "BINEM": "Binemon", "BINGO": "Tomorrowland", + "BINK": "Big Dog Fink", "BINO": "Binopoly", "BINS": "Bitsense", "BINTEX": "Bintex Futures", @@ -1375,6 +1594,7 @@ "BIRD": "Bird.Money", "BIRDCHAIN": "Birdchain", "BIRDDOG": "Bird Dog", + "BIRDO": "Bird Dog", "BIS": "Bismuth", "BISKIT": "Biskit Protocol", "BISO": "BISOSwap", @@ -1395,11 +1615,13 @@ "BITCI": "Bitcicoin", "BITCM": "Bitcomo", "BITCNY": "bitCNY", + "BITCO": "Bitcoin Black Credit Card", "BITCOINC": "Bitcoin Classic", "BITCOINP": "Bitcoin Private", "BITCOINV": "BitcoinV", "BITCONNECT": "BitConnect Coin", "BITCRATIC": "Bitcratic Token", + "BITE": "Bitether", "BITF": "Bit Financial", "BITFLIP": "BitFlip", "BITG": "Bitcoin Green", @@ -1413,19 +1635,24 @@ "BITOK": "BitOKX", "BITORB": "BitOrbit", "BITRA": "Bitratoken", + "BITRADIO": "Bitradio", "BITREWARDS": "BitRewards", "BITROLIUM": "Bitrolium", "BITRUE": "Bitrue Coin", "BITS": "BitstarCoin", "BITSD": "Bits Digit", + "BITSERIAL": "BitSerial", "BITSILVER": "bitSilver", "BITSPACE": "Bitspace", "BITSZ": "Bitsz", "BITT": "BiTToken", "BITTO": "BITTO", + "BITTON": "Bitton", "BITUNE": "Bitune", "BITUSD": "bitUSD", + "BITV": "Bitvolt", "BITVOLT": "BitVolt", + "BITWORLD": "Bit World Token", "BITX": "BitScreener", "BITZ": "Bitz Coin", "BIUT": "Bit Trust System", @@ -1442,19 +1669,23 @@ "BKING": "King Arthur", "BKK": "BKEX Token", "BKN": "Brickken", + "BKOK": "BKOK FinTech", "BKPT": "Biokript", "BKR": "Balkari Token", "BKRW": "Binance KRW", "BKS": "Barkis Network", "BKT": "Blocktrade token", "BKX": "BANKEX", + "BL00P": "BLOOP", "BLA": "BlaBlaGame", "BLAC": "Blacksmith Token", "BLACK": "BLACKHOLE PROTOCOL", "BLACKD": "Blackder AI", "BLACKDRAGON": "Black Dragon", + "BLACKR": "BLACK ROCK", "BLACKROCK": "BlackRock", "BLACKSALE": "Black Sale", + "BLACKST": "Black Stallion", "BLACKSWAN": "BlackSwan AI", "BLADE": "BladeWarrior", "BLAKEBTC": "BlakeBitcoin", @@ -1462,6 +1693,7 @@ "BLAS": "BlakeStar", "BLAST": "BLAST", "BLASTA": "BlastAI", + "BLASTUP": "BlastUP", "BLAUNCH": "B-LAUNCH", "BLAZE": "Blaze", "BLAZEX": "BlazeX", @@ -1474,11 +1706,13 @@ "BLEPE": "Blepe", "BLERF": "BLERF", "BLES": "Blind Boxes", + "BLET": "Brainlet", "BLF": "Baby Luffy", "BLHC": "BlackholeCoin", "BLI": "BALI TOKEN", "BLID": "Bolide", "BLIN": "Blin Metaverse", + "BLIND": "Blindsight", "BLING": "PLEB DREKE", "BLINK": "BlockMason Link", "BLINU": "Baby Lambo Inu", @@ -1488,11 +1722,14 @@ "BLKC": "BlackHat Coin", "BLKD": "Blinked", "BLKS": "Blockshipping", + "BLM": "Blombard", "BLN": "Bulleon", "BLNM": "Bolenum", "BLOB": "Blob", "BLOC": "Blockcloud", "BLOCK": "Blockasset", + "BLOCKB": "Block Browser", + "BLOCKF": "Block Farm Club", "BLOCKIFY": "Blockify.Games", "BLOCKN": "BlockNet", "BLOCKPAY": "BlockPay", @@ -1502,6 +1739,7 @@ "BLOCKW": "Blockwise", "BLOCM": "BLOC.MONEY", "BLOCX": "BLOCX.", + "BLOGGE": "Bloggercube", "BLOK": "Bloktopia", "BLOO": "bloo foster coin", "BLOODY": "Bloody Token", @@ -1509,6 +1747,7 @@ "BLOOMT": "Bloom Token", "BLOVELY": "Baby Lovely Inu", "BLOX": "BLOX", + "BLOXT": "Blox Token", "BLP": "BullPerks", "BLRY": "BillaryCoin", "BLS": "Blocks Space", @@ -1518,14 +1757,22 @@ "BLTG": "Block-Logic", "BLTV": "BLTV Token", "BLU": "BlueCoin", - "BLUE": "Ethereum Blue", + "BLUB": "BLUB", + "BLUE": "Blue Protocol", + "BLUEBUTT": "BLUE BUTT CHEESE", + "BLUEG": "Blue Guy", "BLUEM": "BlueMove", + "BLUEN": "Blue Norva", "BLUES": "Blueshift", + "BLUESC": "BluesCrypto", "BLUESPARROW": "BlueSparrow Token", "BLUESPARROWOLD": "BlueSparrowToken", + "BLUEW": "Blue Whale", + "BLUFF": "BluffCat", "BLUI": "Blui", "BLUR": "Blur", "BLURT": "Blurt", + "BLUSD": "Boosted LUSD", "BLUT": "Bluetherium", "BLV": "Blockvest", "BLV3": "Crypto Legions V3", @@ -1554,8 +1801,11 @@ "BMON": "Binamon", "BMONEY": "B-money", "BMP": "Brother Music Platform", + "BMS": "BMS COIN", "BMT": "BMChain", + "BMTC": "Metabit", "BMW": "BMW", + "BMWUKONG": "Black Myth WuKong", "BMX": "BitMart Token", "BMXT": "Bitmxittz", "BMXX": "Multiplier", @@ -1566,9 +1816,12 @@ "BNBBUNNY": "BNB BUNNY", "BNBCAT": "BNBcat", "BNBCH": "BNB Cash", + "BNBD": "BNBDOG", "BNBDOG": "BNB DOG INU", "BNBDOGE": "BNBdoge", "BNBDRGN": "BNBDragon", + "BNBE": "BNBEE", + "BNBFLOKI": "BNB FLOKI", "BNBFROG": "BNBFROG", "BNBH": "BnbHeroes Token", "BNBLION": "BNB LION", @@ -1586,6 +1839,7 @@ "BNIX": "BNIX Token", "BNK": "Bankera", "BNN": "Banyan Network", + "BNOM": "BitNomad", "BNP": "BenePit", "BNPL": "BNPL Pay", "BNR": "BiNeuro", @@ -1593,7 +1847,9 @@ "BNS": "BNS token", "BNSAI": "bonsAI Network", "BNSD": "BNSD Finance", + "BNSOL": "Binance Staked SOL", "BNSOLD": "BNS token ", + "BNSV1": "BNS token v1", "BNSX": "Bitcoin Name Service System", "BNT": "Bancor Network Token", "BNTE": "Bountie", @@ -1602,8 +1858,10 @@ "BNU": "ByteNext", "BNUSD": "Balanced Dollars", "BNX": "BinaryX", + "BNY": "TaskBunny", "BOA": "BOSAGORA", "BOAI": "BOLICAI", + "BOAM": "BOOK OF AI MEOW", "BOARD": "SurfBoard Finance", "BOAT": "Doubloon", "BOBA": "Boba Network", @@ -1613,7 +1871,10 @@ "BOBBYM": "Bobby Moore", "BOBC": "Bobcoin", "BOBE": "BOOK OF BILLIONAIRES", + "BOBER": "BOBER", + "BOBFUN": "BOB", "BOBO": "BOBO", + "BOBOT": "Bobo The Bear", "BOBS": "Bob's Repair", "BOBT": "BOB Token", "BOBUKI": "Bobuki Neko", @@ -1621,6 +1882,7 @@ "BOCA": "BookOfPussyCats", "BOCAC": "BocaChica token", "BOCAT": "BOCAT", + "BOD": "Book of Donald Trump", "BODA": "Based Yoda", "BODAV2": "BODA Token", "BODE": "Book of Derp", @@ -1630,13 +1892,16 @@ "BODOG": "Book of Doge", "BODYP": "Body Profile", "BOE": "Bodhi", + "BOF": "Balls of Fate", "BOG": "Bogged Finance", "BOGCOIN": "Bogcoin", + "BOGD": "Bogdanoff", "BOGE": "Boge", "BOGEY": "Bogey", "BOGGY": "Boggy Coin", "BOJAK": "Based Wojak", "BOJI": "BOJI Token", + "BOJIV1": "BOJI Token v1", "BOK": "Blockium", "BOKI": "BOOK OF KILLER", "BOKU": "Boryoku Dragonz", @@ -1645,16 +1910,19 @@ "BOLI": "BolivarCoin", "BOLT": "Bolt", "BOLTT": "BolttCoin", + "BOM": "Book Of Matt Furie", "BOMA": "Book of Maga", "BOMB": "BOMB", "BOMBC": "BombCoin", "BOMBM": "Bomb Money", + "BOMBO": "BOMBO", "BOMBS": "Bomb Shelter Inu", "BOME": "BOOK OF MEME", "BOME2": "Book of Meme 2.0", "BOMEDOGE": "BOOK OF DOGE MEMES", "BOMEOW": "Book of Meow", "BOMES": "BOOK OF MEMES", + "BOMET": "BOME TRUMP", "BOMK": "BOMK", "BON": "Bonpay", "BONA": "Bonafi", @@ -1663,19 +1931,27 @@ "BONDLY": "Bondly", "BONDLYV1": "Bondly Finance", "BONE": "Bone ShibaSwap", - "BONES": "BonesCoin", + "BONES": "Moonshots Farm", + "BONESCOIN": "BonesCoin", + "BONESV1": "Squirrel Finance", "BONFIRE": "Bonfire", "BONG": "BonkWifGlass", + "BONGO": "BONGO CAT", "BONIX": "Blockonix", "BONK": "Bonk", + "BONKBNB": "Bonk BNB", "BONKCON": "Bonkcon", + "BONKEA": "Bonk Earn", + "BONKEY": "Bonkey", "BONKFA": "Bonk of America", "BONKFORK": "BonkFork", "BONKGROK": "Bonk Grok", "BONKH": "BonkHoneyHNTMobileSOL", "BONKIN": "Bonkinu", "BONKKONG": "BONK KONG", + "BONKONBASE": "Bonk on Base", "BONKONETH": "Bonk On ETH", + "BONKW": "bonkwifhat", "BONO": "Bonorum Coin", "BONTE": "Bontecoin", "BONUS": "BonusBlock", @@ -1686,15 +1962,23 @@ "BOOFI": "Boo Finance", "BOOK": "Solbook", "BOOKIE": "BookieBot", - "BOOM": "BOOM DAO", + "BOOKO": "Book of Pets", + "BOOKOF": "BOOK OF NOTHING", + "BOOM": "Boomco", "BOOMCOIN": "Boom Token", + "BOOMDAO": "BOOM DAO", "BOOMER": "Boomer", "BOONS": "BOONSCoin", "BOOP": "Boop", - "BOOST": "Boost", + "BOOS": "Boost Trump Campaign", + "BOOST": "PodFast", + "BOOSTCO": "Boost", "BOOSTO": "BOOSTO", "BOOT": "Bostrom", "BOP": "Boring Protocol", + "BOPB": "BIOPOP", + "BOPE": "Book of Pepe", + "BOPPY": "BOPPY", "BOR": "BoringDAO", "BORA": "BORA", "BORED": "Bored Museum", @@ -1702,6 +1986,7 @@ "BORING": "BoringDAO", "BORK": "Bork", "BORKIE": "Borkie", + "BORPA": "Borpa", "BORUTO": "Boruto Inu", "BOS": "BOScoin", "BOSE": "Bitbose", @@ -1724,32 +2009,48 @@ "BOUTS": "BoutsPro", "BOW": "Archer Swap", "BOWE": "Book of Whales", + "BOWSC": "BowsCoin", + "BOWSER": "Bowser", "BOX": "ContentBox", "BOXETH": "Cat-in-a-Box Ether", "BOXT": "BOX Token", "BOXX": "Blockparty", "BOXY": "BoxyCoin", - "BOYS": "CRASHBOYS", + "BOYS": "BOYSCLUB (boysclubonbase.com)", + "BOYSC": "Boy's club", "BOYSCLUB": "Matt Furie's Boys Club", "BOZO": "BOZO", "BOZOH": "bozo Hybrid", "BOZY": "Book of Crazy", "BP": "BunnyPark", "BPAD": "BlokPad", + "BPADA": "Binance-Peg Cardano (Binance Bridge)", + "BPAVAX": "Binance-Peg Avalanche (Binance Bridge)", "BPAY": "BNBPay", + "BPBCH": "Binance-Peg Bitcoin Cash (Binance Bridge)", + "BPBTT": "Binance-Peg BitTorrent", "BPD": "Beautiful Princess Disorder", + "BPDAI": "Binance-Peg Dai (Binance Bridge)", + "BPDOGE": "Binance-Peg DogeZilla (Binance Bridge)", "BPEPEF": "Baby Pepe Floki", "BPET": "BPET", "BPINKY": "BPINKY", "BPL": "BlockPool", "BPLC": "BlackPearl Token", + "BPLINK": "Binance-Peg Chainlink (Binance Bridge)", + "BPLTC": "Binance-Peg Litecoin", + "BPMATIC": "Binance-Peg Polygon (Binance Bridge)", "BPN": "beepnow", + "BPNEAR": "Binance-Peg NEAR Protocol", "BPOKO": "BabyPoko", "BPRIVA": "Privapp Network", "BPRO": "BitCloud Pro", "BPS": "BitcoinPoS", + "BPSHIB": "Binance-Peg Shiba Inu (Binance Bridge)", "BPT": "BlackPool Token", "BPTC": "Business Platform Tomato Coin", + "BPUNI": "Binance-Peg Uniswap Protocol Token (Binance Bridge)", + "BPUSDC": "Binance-Peg USD Coin (Binance Bridge)", "BPX": "Black Phoenix", "BQ": "Bitqy", "BQC": "BQCoin", @@ -1761,11 +2062,12 @@ "BRACE": "Bitci Racing Token", "BRAIN": "BrainCoin", "BRAINERS": "Brainers", + "BRAINLET": "Brainlet", "BRAINZ": "Brainz Finance", "BRAM": "Defibox bRAM", "BRANA": "Branaverse", "BRAND": "BrandProtect", - "BRAT": "BROTHER", + "BRAT": "Peak Brat", "BRATT": "Son of Brett", "BRAWL": "BitBrawl", "BRAZ": "Brazio", @@ -1780,10 +2082,13 @@ "BREE": "CBDAO", "BREED": "BreederDAO", "BREPE": "BREPE", - "BRETT": "Brett", + "BRETARDIO": "Bretardio", + "BRETT": "Brett Base", "BRETTA": "Bretta", - "BRETTBASE": "Brett Base", - "BRETTETH": "Brett ETH", + "BRETTFYI": "Brett", + "BRETTGOLD": "Brett Gold", + "BRETTONETH": "Brett ETH", + "BRETTSUI": "Brett (brettsui.com)", "BREW": "CafeSwap Token", "BREWERY": "Brewery Consortium Coin", "BREWLABS": "Brewlabs", @@ -1792,7 +2097,8 @@ "BRGX": "Bridge$", "BRI": "Baroin", "BRIA": "Briacoin", - "BRIAN": "Brianwifhat", + "BRIAN": "Brian Arm Strong", + "BRIANWIF": "Brianwifhat", "BRIC": "BrightCoin", "BRICK": "Brickchain FInance", "BRICKS": "MyBricks", @@ -1800,6 +2106,7 @@ "BRIGHT": "Bright Token", "BRIGHTU": "Bright Union", "BRIK": "BrikBit", + "BRIL": "Brilliantcrypto", "BRISE": "Bitgert", "BRIT": "BritCoin", "BRITT": "Britt", @@ -1813,17 +2120,22 @@ "BRN": "BRN Metaverse", "BRNK": "Brank", "BRNX": "Bronix", - "BRO": "Bitradio", + "BRO": "Bro the cat", "BROCK": "Bitrock", "BROGG": "Brett's Dog", + "BROKE": "Broke Again", + "BROKIE": "Brokie", "BRONZ": "BitBronze", "BROOT": "BROOT", + "BROTHER": "BROTHER", "BROWN": "BrowniesSwap", + "BROZ": "Brozinkerbell", "BRRR": "Burrow", "BRS": "Broovs Projects", "BRT": "Bikerush", "BRTR": "Barter", "BRTX": "Bertinity", + "BRUH": "Bruh", "BRUNE": "BitRunes", "BRUSH": "PaintSwap", "BRUV": "Bruv", @@ -1839,17 +2151,20 @@ "BSAFU": "BlockSAFU", "BSATOSHI": "BabySatoshi", "BSB": "Based Street Bets", - "BSC": "BowsCoin", + "BSC": "BSC Layer", "BSCAKE": "Bunscake", "BSCBURN": "BSCBURN", + "BSCC": "BSCCAT", "BSCGIRL": "Binance Smart Chain Girl", "BSCH": "BitSchool", "BSCM": "BSC MemePad", "BSCPAD": "BSCPAD", "BSCPAY": "BSC PAYMENTS", "BSCS": "BSC Station", + "BSCST": "Starter", "BSCV": "Bscview", - "BSE": "BitSerial", + "BSDETH": "Based ETH", + "BSE": "base season", "BSEND": "BitSend", "BSFM": "BABY SAFEMOON", "BSG": "Baby Squid Game", @@ -1858,6 +2173,7 @@ "BSHARE": "Bomb Money", "BSHIB": "Based Shiba Inu", "BSI": "Bali Social Integrated", + "BSK": "BTCSKR", "BSKT": "BasketCoin", "BSL": "BankSocial", "BSOL": "BlazeStake Staked SOL", @@ -1894,12 +2210,15 @@ "BTC": "Bitcoin", "BTC2": "Bitcoin 2", "BTC2XFLI": "BTC 2x Flexible Leverage Index", + "BTC70000": "BTC 70000", "BTCA": "BITCOIN ADDITIONAL", "BTCAB": "Bitcoin Avalanche Bridged", + "BTCACT": "BITCOIN Act", "BTCAS": "BitcoinAsia", "BTCAT": "Bitcoin Cat", "BTCB": "Bitcoin BEP2", "BTCBR": "Bitcoin BR", + "BTCBRV1": "Bitcoin BR v1", "BTCC": "Bitcoin Core", "BTCD": "BitcoinDark", "BTCDRAGON": "BTC Dragon", @@ -1916,6 +2235,7 @@ "BTCM": "BTCMoon", "BTCMT": "Minto", "BTCN": "BitcoiNote", + "BTCNOW": "Blockchain Technology Co.", "BTCP": "Bitcoin Palladium", "BTCPAY": "Bitcoin Pay", "BTCPX": "BTC Proxy", @@ -1931,7 +2251,9 @@ "BTCZ": "BitcoinZ", "BTD": "Bitcloud", "BTDX": "Bitcloud 2.0", - "BTE": "BTEcoin", + "BTE": "Betero", + "BTECOIN": "BTEcoin", + "BTEV1": "Betero v1", "BTEX": "BTEX", "BTF": "Blockchain Traded Fund", "BTFA": "Banana Task Force Ape", @@ -1944,6 +2266,7 @@ "BTMG": "Bitcademy Football", "BTMI": "BitMiles", "BTMK": "BitMark", + "BTMT": "BITmarkets Token", "BTMXBULL": "3X Long BitMax Token Token", "BTNT": "BitNautic Token", "BTNTV2": "BitNautic Token", @@ -1993,11 +2316,14 @@ "BUCKY": "Bucky", "BUD": "Buddy", "BUDDHA": "Buddha", + "BUDDY": "BUDDY", "BUDG": "Bulldogswap", + "BUENO": "Bueno", "BUF": "Buftoad", "BUFF": "Buffalo Swap", "BUFFDOGE": "Buff Doge", "BUFFET": "Worried", + "BUFFI": "Bufficorn", "BUGATTI": "BUGATTI", "BUGG": "Bugg Inu", "BUGS": "Bugs Bunny", @@ -2007,15 +2333,20 @@ "BUILDTEAM": "BuildTeam", "BUK": "CryptoBuk", "BUL": "bul", + "BULDAK": "Buldak", "BULEI": "Bulei", "BULL": "Bullieverse", "BULLC": "BuySell", + "BULLF": "BULL FINANCE", + "BULLI": "Bullish On Ethereum", "BULLINU": "Bull inu", "BULLION": "BullionFX", + "BULLISH": "bullish", "BULLMOON": "Bull Moon", "BULLPEPE": "Bullpepe", "BULLS": "Bull Coin", "BULLSH": "Bullshit Inu", + "BULLY": "Dolos The Bully", "BULLYINGCAT": "Bullying Cat", "BULT": "Bullit", "BUM": "WillyBumBum", @@ -2025,9 +2356,12 @@ "BUND": "Bund V2.0", "BUNDL": "Bundl Tools", "BUNI": "Bunicorn", + "BUNN": "Bunni", "BUNNY": "Pancake Bunny", "BUNNYINU": "Bunny Inu", + "BUNNYM": "BUNNY MEV BOT", "BUNNYROCKET": "BunnyRocket", + "BURG": "Burger", "BURGER": "Burger Swap", "BURN": "BurnedFi", "BURNDOGE": "BurnDoge", @@ -2042,10 +2376,12 @@ "BUSDC": "BUSD", "BUSY": "Busy DAO", "BUT": "BitUP Token", + "BUTT": "Buttercat", "BUX": "BUX", "BUXCOIN": "Buxcoin", "BUY": "Burency", "BUYI": "Buying.com", + "BUYT": "Buy the DIP", "BUZZ": "BuzzCoin", "BV3A": "Buccaneer V3 Arbitrum", "BVC": "BeaverCoin", @@ -2053,7 +2389,8 @@ "BVND": "Binance VND", "BVO": "BRAVO Pay", "BVT": "BovineVerse Token", - "BWB": "Bit World Token", + "BWB": "Bitget Wallet Token", + "BWEN": "Baby Wen", "BWF": "Beowulf", "BWJ": "Baby WOJ", "BWK": "Bulwark", @@ -2063,6 +2400,7 @@ "BWS": "BitcoinWSpectrum", "BWT": "Bittwatt", "BWT2": "Bitwin 2.0", + "BWULL": "Bwull", "BWX": "Blue Whale", "BX": "BlockXpress", "BXA": "Blockchain Exchange Alliance", @@ -2081,12 +2419,14 @@ "BYAT": "Byat", "BYC": "ByteCent", "BYG": "Black Eye Galaxy", + "BYT": "ByteAI", "BYTE": "Byte", "BYTES": "Neo Tokyo", "BYTHER": "Bytether ", "BYTS": "Bytus", "BYTZ": "BYTZ", "BZ": "Bit-Z", + "BZE": "BeeZee", "BZENIQ": "Wrapped Zeniq (BNB)", "BZET": "Bzetcoin", "BZKY": "Bizkey", @@ -2097,7 +2437,6 @@ "BZX": "Bitcoin Zero", "BZZ": "Swarmv", "BZZONE": "Bzzone", - "BamitCoin": "BAM", "C2": "Coin.2", "C20": "Crypto20", "C25": "C25 Coin", @@ -2115,6 +2454,7 @@ "CACHE": "Cache", "CACHEGOLD": "CACHE Gold", "CACTUS": "CACTUS", + "CADAI": "CADAI", "CADC": "CAD Coin", "CADINU": "Canadian Inuit Dog", "CADN": "Content and AD Network", @@ -2144,6 +2484,7 @@ "CAMEL": "The Camel", "CAMLY": "Camly Coin", "CAMP": "Camp", + "CAMT": "CAMELL", "CAN": "Channels", "CANCER": "Cancer", "CAND": "Canary Dollar", @@ -2176,6 +2517,7 @@ "CARDSWAP": "CardSwap", "CARE": "Carebit", "CARES": "CareCoin", + "CARL": "Carl", "CARLO": "Carlo", "CARO": "Meta Ricaro", "CAROL": "CAROLToken", @@ -2185,46 +2527,67 @@ "CART": "CryptoArt.Ai", "CARTAXI": "CarTaxi", "CARTERCOIN": "CarterCoin", + "CARV": "CARV", "CAS": "Cashaa", "CASH": "CashCoin", + "CASHLY": "Cashly", "CASHT": "Cash Tech", "CASINU": "Casinu Inu", "CASIO": "CasinoXMetaverse", "CASPER": "Casper DeFi", "CAST": "Castello Coin", "CASTLE": "bitCastle", - "CAT": "Cat Token", + "CAT": "Simon's Cat", "CATA": "CATAMOTO", + "CATABSC": "CATA BSC", "CATAI": "Catgirl AI", + "CATALORIAN": "CATALORIAN", + "CATANA": "Catana", "CATBA": "CATBA INU", + "CATBAL": "Catbal", "CATBOY": "Catboy", "CATC": "Catcoin", "CATCEO": "CATCEO", "CATCH": "SpaceCatch", - "CATCOIN": "CatCoin Cash", + "CATCO": "CatCoin", + "CATCOIN": "CatCoin", "CATCOINETH": "Catcoin", + "CATCOINV2": "CatCoin Cash", + "CATDOG": "Cat-Dog", "CATDOGE": "CAT DOGE", - "CATE": "CateCoin", + "CATEC": "Cate Coin", + "CATECOIN": "CateCoin", "CATELON": "CatElonMars", "CATEX": "CATEX", "CATFISH": "Catfish", "CATGAME": "Cookie Cat Game", "CATGIRL": "Catgirl", + "CATGOKU": "Catgoku", "CATGPT": "CatGPT", "CATHAT": "catwifhat", "CATHEON": "Catheon Gaming", "CATHERO": "Cat Hero", + "CATI": "Catizen", + "CATINU": "CAT INU", "CATKING": "CAT KING", + "CATLIFE": "Cat Life", "CATMAN": "Catman", "CATME": "ELON’S CAT", "CATO": "CATO", "CATPAY": "CATpay", "CATPEPE": "CAT PEPE", "CATS": "CatCoin Token", + "CATSC": "Catscoin", "CATSHIRA": "Shira Cat", + "CATSO": "Cats Of Sol", + "CATSON": "Catson", + "CATSV1": "CatCoin Token v1", + "CATSY": "CAT SYLVESTER", "CATT": "Catex", + "CATTO": "Cat Token", "CATVAX": "Catvax", "CATVILLS": "Catvills Coin", + "CATW": "Cat wif Hands", "CATWARRIOR": "Cat warrior", "CATWIF": "CatWifHat", "CATX": "CAT.trade Protocol", @@ -2241,8 +2604,11 @@ "CBABY": "Cosmo Baby", "CBANK": "Crypto Bank", "CBAT": "Compound Basic Attention Token", + "CBBTC": "Coinbase Wrapped BTC", + "CBBTCBASE": "cbBTC", "CBC": "Casino Betting Coin", "CBD": "CBD Crystals", + "CBDAI": "Dai (Cronos Bridge)", "CBDC": "CannaBCoin", "CBDG": "CBD Global", "CBE": "The Chain of Business Entertainment", @@ -2252,10 +2618,12 @@ "CBG": "Chainbing", "CBIXP": "Cubiex Power", "CBK": "Cobak Token", + "CBL": "Credbull", "CBM": "CryptoBonusMiles", "CBNT": "Create Breaking News Together", "CBOT": "C-BOT", - "CBP": "ComBox", + "CBP": "CashBackPro", + "CBPAY": "COINBAR PAY", "CBRL": "Crypto BRL", "CBRT": "Cybereits Token", "CBS": "Cerberus", @@ -2277,6 +2645,7 @@ "CCC": "CCCoin", "CCCX": "Clipper Coin Capital", "CCD": "Concordium", + "CCDS": "CCDS INTERNATIONAL", "CCE": "CloudCoin", "CCGDS": "CCGDS", "CCH": "Coinchase", @@ -2311,6 +2680,7 @@ "CDX": "CDX Network", "CDY": "Bitcoin Candy", "CDragon": "Clumsy Dragon", + "CEC": "Counterfire Economic Coin", "CEDEX": "CEDEX Coin", "CEEK": "CEEK Smart VR Token", "CEFS": "CryptopiaFeeShares", @@ -2326,12 +2696,17 @@ "CEM": "Crypto Emergency", "CEN": "Coinsuper Ecosystem Network", "CENNZ": "Centrality Token", + "CENS": "Censored Ai", "CENT": "CENTERCOIN", + "CENTA": "Centaurify", "CENTRA": "Centra", + "CENTS": "Centience", "CENX": "Centcex", "CEODOGE": "CEO DOGE", + "CERBER": "CERBEROGE", "CERE": "Cere Network", "CERES": "Ceres", + "CES": "swap.coffee", "CESC": "Crypto Escudo", "CET": "CoinEx Token", "CETH": "Compound Ethereum", @@ -2348,6 +2723,7 @@ "CFL365": "CFL365 Finance", "CFLASH": "Flash", "CFLO": "Chain Flowers", + "CFN": "Cockfight Network", "CFT": "CryptoForecast", "CFTY": "Crafty", "CFX": "Conflux Network", @@ -2355,11 +2731,13 @@ "CFXT": "Chainflix", "CFun": "CFun", "CGA": "Cryptographic Anomaly", + "CGAR": "CryptoGuards", "CGG": "Chain Guardians", "CGL": "Crypto Gladiator Shards", "CGLD": "Celo Gold", "CGO": "Comtech Gold", "CGPT": "ChainGPT", + "CGPU": "CloudGPU", "CGS": "Crypto Gladiator Shards", "CGT": "Coin Gabbar Token", "CGU": "Crypto Gaming United", @@ -2369,6 +2747,7 @@ "CHAD": "Chad Coin", "CHADCAT": "CHAD CAT", "CHADS": "CHADS VC", + "CHAI": "Chroma AI", "CHAIN": "Chain Games", "CHAINCADE": "ChainCade", "CHAL": "Chalice Finance", @@ -2377,8 +2756,10 @@ "CHAMPZ": "Champz", "CHAN": "ChanCoin", "CHANCE": "Ante Casino", + "CHANG": "Chang", "CHANGE": "ChangeX", "CHAO": "23 Skidoo", + "CHAOS": "chaos and disorder", "CHAPZ": "Chappyz", "CHARGED": "GoCharge Tech", "CHARIZARD": "Charizard Inu", @@ -2389,7 +2770,9 @@ "CHARTIQ": "ChartIQ", "CHASH": "CleverHash", "CHAT": "Solchat", + "CHATAI": "ChatAI Token", "CHATGPT": "AI Dragon", + "CHATTY": "ChatGPT's Mascot", "CHB": "COINHUB TOKEN", "CHBR": "CryptoHub", "CHC": "ChainCoin", @@ -2404,8 +2787,11 @@ "CHEEMS": "Cheems", "CHEEPEPE": "CHEEPEPE", "CHEERS": "DICAPRIO CHEERS", - "CHEESE": "CHEESE", + "CHEESE": "Cheese", + "CHEESEBALL": "Cheeseball the Wizard", + "CHEESECOIN": "Cheesecoin", "CHEESUS": "Cheesus", + "CHEF": "Chefdotfun", "CHENG": "Chengshi", "CHEQ": "CHEQD Network", "CHER": "Cherry Network", @@ -2413,35 +2799,47 @@ "CHESS": "Tranchess", "CHESSCOIN": "ChessCoin", "CHET": "ChetGPT", + "CHEW": "CHEWY", "CHEWY": "Chewy", "CHEX": "Chintai", + "CHEYENNE": "Cheyenne", "CHFN": "NOKU CHF", "CHFT": "Crypto Holding", "CHFU": "Upper Swiss Franc", "CHFX": "eToro Swiss Franc", "CHH": "Chihuahua Token", "CHI": "Chi Gastoken", + "CHIB": "Chiba Inu", "CHICA": "CHICA", "CHICKS": "SolChicks", "CHIDO": "Chinese Doge Wow", + "CHIE": "Chief Pepe Officer", "CHIEF": "TheChiefCoin", + "CHIEFD": "Chief D.O.G.E", "CHIHUA": "Chihua Token", "CHII": "Chiiper Chain", "CHILD": "ChildCoin", + "CHILDAI": "Singularity's Child gonzoai", "CHILI": "CHILI", "CHILL": "ChillPill", + "CHILLGUY": "Chill Guy", "CHIM": "Chimera", + "CHINAU": "Chinau", "CHINAZILLA": "ChinaZilla", "CHINGON": "Mexico Chingon", "CHINU": "Chubby Inu", "CHIP": "Chip", + "CHIPI": "chipi", "CHIPPY": "Chippy", "CHIPS": "CHIPS", "CHIRP": "Chirp", + "CHIRPY": "Chirpy Boy", + "CHITAN": "Chitan", "CHITCAT": "ChitCAT", "CHIWAWA": "Chiwawa", "CHK": "Chek", "CHKN": "Chickencoin", + "CHLOE": "Pnut's Sister", "CHLT": "Chellitcoin", "CHMB": "Chumbi Valley", "CHMPZ": "Chimpzee", @@ -2473,7 +2871,10 @@ "CHUC": "CHUCK", "CHUCHU": "CHUCHU", "CHUCK": "Chuck Norris", - "CHUMP": "Chump Change", + "CHUD": "Chudjak", + "CHULO": "Papichulo", + "CHUMP": "Donald J Chump", + "CHUMPC": "Chump Change", "CHURRO": "CHURRO-The Jupiter Dog", "CHVF": "Chives Finance", "CHW": "Chrysalis Coin", @@ -2484,6 +2885,7 @@ "CIC": "Crazy Internet Coin", "CICHAIN": "CIChain", "CIF": "Crypto Improvement Fund", + "CIG": "cig", "CIM": "COINCOME", "CIN": "CinderCoin", "CIND": "Cindrum", @@ -2499,6 +2901,7 @@ "CIRCUS": "Cirque Du Sol", "CIRRUS": "Cirrus", "CIRUS": "Cirus", + "CIRX": "Circular Protocol", "CITI": "CITI Fediverse", "CITY": "Manchester City Fan Token", "CIV": "Civilization", @@ -2520,7 +2923,10 @@ "CL": "CoinLancer", "CLA": "ClaimSwap", "CLAM": "CLAMS", + "CLANKER": "tokenbot", + "CLAP": "Clap Cat", "CLAS": "Classic USDC", + "CLASH": "Clashub", "CLASS": "Class Coin", "CLAY": "Clay Nation", "CLB": "Cloudbric", @@ -2544,6 +2950,7 @@ "CLINT": "Clinton", "CLIPS": "Clips", "CLIQ": "DefiCliq", + "CLISBNB": "clisBNB", "CLIST": "Chainlist", "CLM": "CoinClaim", "CLMRS": "Crolon Mars", @@ -2551,11 +2958,14 @@ "CLNX": "Coloniume Network", "CLNY": "Colony", "CLO": "Callisto Network", + "CLOA": "Cloak", "CLOAK": "CloakCoin", + "CLOKI": "CATLOKI", "CLORE": "Clore.ai", - "CLOUD": "Metacloud", + "CLOUD": "Cloud", "CLOUT": "BitClout", "CLOUTIO": "Clout", + "CLOW": "Clown Pepe", "CLPX": "Chynge.net", "CLR": "CopperLark", "CLRTY": "Clarity", @@ -2576,6 +2986,7 @@ "CMCX": "CORE MultiChain", "CMDX": "Comdex", "CMERGE": "CoinMerge", + "CMETH": "Mantle Restaked Ether", "CMFI": "Compendium", "CMINER": "ChainMiner", "CMIT": "CMITCOIN", @@ -2627,13 +3038,20 @@ "CNYX": "eToro Chinese Yuan", "CO": "Corite", "CO2": "CO2 Token", + "COAI": "CodeMong Ai", "COAL": "BitCoal", "COB": "Cobinhood", "COBE": "Castle of Blackwater", + "COBY": "Coby", "COC": "Coin of the champions", + "COCAINE": "THE GOOD STUFF", "COCK": "Shibacock", - "COCO": "0xCoco", + "COCO": "COCO COIN", + "COCONUT": "Coconut", + "COD": "Chief of Deswamp", + "CODA": "CODA", "CODAI": "CODAI", + "CODE": "Code Token", "CODEG": "CodeGenie", "CODEO": "Codeo Token", "CODEX": "CODEX Finance", @@ -2641,6 +3059,7 @@ "CODY": "Coindy", "COE": "CoEval", "COFEEE": "COFEEE", + "COFFEE": "COFFEE", "COFFEECOIN": "CoffeeCoin", "COFI": "CoinFi", "COFIX": "CoFIX", @@ -2650,15 +3069,19 @@ "COGI": "COGI", "COGS": "Cogmento", "COI": "Coinnec", + "COINB": "Coinbidex", "COINBT": "CoinBot", "COINDEFI": "Coin", "COING": "Coingrid", "COINH": "Coinhound", "COINLION": "CoinLion", + "COINM": "CoinMarketPrime", + "COINONAT": "Coinonat", "COINSCOPE": "Coinscope", "COINSL": "CoinsLoot", "COINVEST": "Coinvest", "COINYE": "Coinye West", + "COJ": "Cojam", "COK": "Cat Own Kimono", "COKE": "Cocaine Cowboy Shards", "COL": "Clash of Lilliput", @@ -2666,8 +3089,10 @@ "COLL": "Collateral Pay", "COLLAR": "PolyPup Finance", "COLLE": "Collective Care", + "COLLEA": "Colle AI", "COLLECT": "CoinCollect", "COLLG": "Collateral Pay Governance", + "COLON": "Colon", "COLR": "colR Coin", "COLT": "Collateral Network", "COLX": "ColossusCoinXT", @@ -2675,6 +3100,8 @@ "COMAI": "Commune AI", "COMB": "Combo", "COMBO": "COMBO", + "COMBOX": "ComBox", + "COMC": "ComCrica Token", "COME": "Community of Meme", "COMEW": "Coin In Meme World", "COMFI": "CompliFi", @@ -2696,15 +3123,20 @@ "CONK": "ShibaPoconk", "CONS": "ConSpiracy Coin", "CONSENTIUM": "Consentium", + "CONTROL": "Control Token", "CONV": "Convergence", "CONX": "Connex", + "COO": "Cool Cats MILK", "COOCHIE": "Cucci", "COOHA": "CoolHash", "COOK": "Cook", + "COOKIE": "Cookie", "COOL": "CoolCoin", "COOP": "Coop Network", + "COPA": "COCO PARK", "COPE": "Cope", "COPI": "Cornucopias", + "COPIO": "Copiosa Coin", "COPIUM": "Copium", "COPS": "Cops Finance", "COPYCAT": "Copycat Finance", @@ -2712,8 +3144,10 @@ "COR": "Coreto", "CORAL": "CoralPay", "CORE": "Core", + "COREC": "CoreConnect", "COREDAO": "coreDAO", "COREG": "Core Group Asset", + "COREK": "Core Keeper", "COREUM": "Coreum", "CORGI": "Corgi Inu", "CORGIAI": "CorgiAI", @@ -2721,12 +3155,14 @@ "CORION": "Corion", "CORN": "CORN", "CORNELLA": "CORNELLA", + "CORSI": "Cane Corso", "CORX": "CorionX", "COS": "Contentos", "COSHI": "CoShi Inu", "COSM": "CosmoChain", "COSMI": "Cosmic FOMO", "COSMIC": "CosmicSwap", + "COSMICN": "Cosmic Network", "COSP": "Cosplay Token", "COSS": "COS", "COST": "Costco Hot Dog", @@ -2780,6 +3216,7 @@ "CPRX": "Crypto Perx", "CPS": "Cryptostone", "CPT": "Cryptaur", + "CPTN": "Captain Max", "CPU": "CPUcoin", "CPX": "Apex Token", "CPY": "COPYTRACK", @@ -2794,12 +3231,16 @@ "CRADLE": "Cradle of Sins", "CRAFT": "TaleCraft", "CRAFTCOIN": "Craftcoin", + "CRAI": "Cryptify AI", "CRAIG": "CraigsCoin", "CRAMER": "Cramer Coin", "CRANEPAY": "Cranepay", "CRASH": "Solana Crash", + "CRASHBOYS": "CRASHBOYS", "CRAVE": "CraveCoin", "CRAYRABBIT": "CrazyRabbit", + "CRAZ": "CRAZY FLOKI", + "CRAZYB": "Crazy Bunny", "CRAZYBONK": "CRAZY BONK", "CRAZYBUNNY": "Crazy Bunny", "CRAZYCAT": "CRAZY CAT", @@ -2807,6 +3248,7 @@ "CRAZYDRAGON": "CRAZY DRAGON", "CRAZYMUSK": "CRAZY MUSK", "CRAZYPEPE": "CrazyPepe", + "CRAZYT": "CRAZY TRUMP", "CRAZYTIGER": "CRAZY TIGER", "CRB": "Creditbit", "CRBN": "Carbon", @@ -2846,10 +3288,14 @@ "CRGPT": "CryptoGPT", "CRH": "Crypto Hunters Coin", "CRHT": "CryptHub", + "CRI": "Criptodólar", "CRI3X": "CRI3X", "CRICKETS": "Kermit", "CRIME": "Crime Gold", "CRIMINGO": "Criminal Flamingo", + "CRIPPL": "Wheelchair Cat", + "CRIS": "CristianoRonaldoSpeedSmurf7Siu", + "CRISPR": "CRISPR", "CRK": "Croking", "CRL": "Cryptelo Coin", "CRM": "Cream", @@ -2878,6 +3324,7 @@ "CRS": "CRYSTALS", "CRSP": "CryptoSpots", "CRT": "Carr.Finance", + "CRTAI": "CRT AI Network", "CRTB": "Coritiba F.C. Fan Token", "CRTM": "Cryptum", "CRTS": "Cratos", @@ -2887,6 +3334,7 @@ "CRUMP": "Crypto Trump", "CRUX": "CryptoMines Reborn", "CRV": "Curve DAO Token", + "CRVE": "Curve DAO Token (Avalanche Bridge)", "CRVUSD": "crvUSD", "CRVY": "Curve Inu", "CRW": "Crown Coin", @@ -2898,12 +3346,26 @@ "CRYO": "CryoDAO", "CRYP": "CrypticCoin", "CRYPT": "CryptCoin", + "CRYPTER": "Crypteriumcoin", + "CRYPTOAI": "CryptoAI", + "CRYPTOB": "Crypto Burger", + "CRYPTOBEAST": "CryptoBeast", + "CRYPTOBL": "CryptoBlades Kingdoms", "CRYPTOBULLION": "CryptoBullion", "CRYPTOE": "Cryptoenter", + "CRYPTOEM": "Crypto Emperor Trump", + "CRYPTOF": "CryptoFarmers", + "CRYPTOH": "CryptoHunterTrading", + "CRYPTOJ": "Crypto Journey", "CRYPTON": "CRYPTON", "CRYPTONITE": "Cryptonite", + "CRYPTOOFFICIAL": "Crypto", + "CRYPTOPAL": "Pal", "CRYPTOPRO": "CryptoProfile", + "CRYPTOR": "CRYPTORG", + "CRYPTOS": "CryptoSoul", "CRYPTOSDG": "Crypto SDG", + "CRYPTOT": "Crypto Trump", "CRYPTOU": "CryptoUnity", "CRYSTAL": "Crystal", "CRYSTALCLEAR": "Crystal Clear Token", @@ -2915,6 +3377,7 @@ "CSC": "CasinoCoin", "CSEN": "Sentient Coin", "CSH": "CashOut", + "CSI": "CSI888", "CSIX": "Carbon Browser", "CSM": "Crust Shadow", "CSMIC": "Cosmic", @@ -2931,12 +3394,14 @@ "CSTL": "Castle", "CSTR": "CoreStarter", "CSUSHI": "cSUSHI", + "CSW": "Crosswalk", "CSWAP": "ChainSwap", "CSX": "Coinstox", "CT": "CryptoTwitter", "CTA": "Cross The Ages", "CTAG": "CTAGtoken", "CTASK": "CryptoTask", + "CTB": "Content Bitcoin", "CTC": "Creditcoin", "CTCN": "Contracoin", "CTE": "Crypto Tron", @@ -2951,12 +3416,13 @@ "CTLS": "Chaintools", "CTLX": "Cash Telex", "CTN": "Continuum Finance", - "CTO": "Crypto", + "CTO": "BaseCTO", "CTOK": "Codyfight", "CTP": "Ctomorrow Platform", "CTPL": "Cultiplan", "CTPT": "Contents Protocol", "CTR": "Creator Platform", + "CTRL": "Ctrl Wallet", "CTRL2XY": "Control2XY", "CTRT": "Cryptrust", "CTS": "Citrus", @@ -2979,7 +3445,9 @@ "CUEX": "Cuex", "CUFF": "Jail Cat", "CULO": "CULO", + "CULOETH": "CULO", "CULT": "Cult DAO", + "CULTUR": "Cultur", "CUM": "Cumbackbears", "CUMINU": "CumInu", "CUMMIES": "CumRocket", @@ -2988,6 +3456,7 @@ "CURE": "Curecoin", "CURI": "Curium", "CURIO": "Curio Governance", + "CURLY": "Curly", "CURR": "Curry", "CURRY": "CurrySwap", "CUSD": "Carbon", @@ -2997,6 +3466,7 @@ "CUST": "Custody Token", "CUT": "CUTcoin", "CUTE": "Blockchain Cuties Universe", + "CUUT": "CUTTLEFISHY", "CUZ": "Cool Cousin", "CV": "CarVertical", "CVA": "Crypto Village Accelerator", @@ -3046,11 +3516,13 @@ "CXO": "CargoX", "CXP": "Caixa Pay", "CXPAD": "CoinxPad", - "CXT": "Coinonat", + "CXT": "Covalent X Token", "CY97": "Cyclops97", "CYB": "CYBERTRUCK", "CYBA": "CYBRIA", + "CYBE": "Cyberlete", "CYBER": "CyberConnect", + "CYBERA": "Cyber Arena", "CYBERC": "CyberCoin", "CYBERD": "Cyber Doge", "CYBERTRUCK": "Cyber Truck", @@ -3065,6 +3537,7 @@ "CYCLUB": "Cyclub", "CYCON": "CONUN", "CYDER": "Cyder Coin", + "CYDX": "CyberDEX", "CYFI": "cYFI", "CYG": "Cygnus", "CYL": "Crystal Token", @@ -3073,13 +3546,16 @@ "CYOP": "CyOp Protocol", "CYP": "CypherPunkCoin", "CYPEPE": "CyPepe", + "CYPHER": "CYPHER•GENESIS (Runes)", "CYRS": "Cyrus Token", "CYRUS": "Cyrus Exchange", "CYS": "BlooCYS", "CYT": "Cryptokenz", + "CZ": "CHANGPENG ZHAO (changpengzhao.club)", "CZC": "Crazy Coin", "CZF": "CZodiac Farming Token", "CZGOAT": "CZ THE GOAT", + "CZKING": "CZKING", "CZOL": "Czolana", "CZR": "CanonChain", "CZRX": "Compound 0x", @@ -3094,6 +3570,7 @@ "D4RK": "DarkPayCoin", "DAAPL": "Apple Tokenized Stock Defichain", "DAB": "DABANKING", + "DABCAT": "Dabcat", "DAC": "Davinci Coin", "DACASH": "DACash", "DACAT": "daCat", @@ -3106,32 +3583,41 @@ "DAD": "DAD", "DADA": "DADA", "DADDY": "Daddy Tate", + "DADDYCHILL": "Daddy Chill", "DADDYDOGE": "Daddy Doge", "DADI": "Edge", + "DAETA": "DÆTA", "DAF": "DaFIN", "DAFI": "Dafi Protocol", "DAFT": "DaftCoin", "DAG": "Constellation", "DAGO": "Dago Mining", + "DAGS": "Dagcoin", "DAGT": "Digital Asset Guarantee Token", "DAI": "Dai", + "DAIE": "Dai (Avalanche Bridge)", "DAILY": "Coindaily", "DAILYS": "DailySwap Token", "DAIMO": "Diamond Token", "DAIN": "Dain Token", "DAIQ": "Daiquilibrium", "DAISY": "Daisy Launch Pad", + "DAK": "dak", "DAL": "DAOLaunch", "DALI": "Dalichain", + "DALMA": "Dalma Inu", "DAM": "Datamine", "DAMEX": "DAMEX", + "DAMN": "Sol Killer", "DAMO": "Coinzen", "DAMOON": "Damoon Coin", "DAN": "Daneel", "DANA": "Ardana", "DANG": "Guangdang", "DANGEL": "dAngel Fund", + "DANJ": "Danjuan Cat", "DANK": "DarkKush", + "DANNY": "Degen Danny", "DAO": "DAO Maker", "DAO1": "DAO1", "DAOACT": "ACT", @@ -3147,6 +3633,7 @@ "DAPS": "DAPS Coin", "DAR": "Mines of Dalarnia", "DARA": "Immutable", + "DARAM": "Daram", "DARB": "Darb Token", "DARC": "Konstellation", "DARCRUS": "Darcrus", @@ -3156,6 +3643,8 @@ "DARIK": "Darik", "DARK": "Dark", "DARKEN": "Dark Energy Crystals", + "DARKMAGACOIN": "DARK MAGA", + "DARKT": "Dark Trump", "DART": "dART Insurance", "DARX": "Bitdaric", "DAS": "DAS", @@ -3163,14 +3652,18 @@ "DASH": "Dash", "DASHD": "Dash Diamond", "DASHG": "Dash Green", + "DASIAv": "DASIA", "DAT": "Datum", "DATA": "Streamr", + "DATAO": "Data Ownership Protocol", "DATAWALLET": "DataWallet", + "DATOM": "Drop Staked ATOM", "DATP": "Decentralized Asset Trading Platform", "DATX": "DATx", "DAUMEN": "Daumenfrosch", "DAV": "DAV", "DAVE": "DAVE", + "DAVID": "David", "DAVINCI": "Davincigraph", "DAVIS": "Davis Cup Fan Token", "DAVP": "Davion", @@ -3196,7 +3689,7 @@ "DBL": "Doubloon", "DBOE": "DBOE", "DBOX": "DefiBox", - "DBR": "Düber", + "DBR": "deBridge", "DBTC": "DebitCoin", "DBTN": "Universa Native token", "DBUND": "DarkBundles", @@ -3213,6 +3706,10 @@ "DCB": "Decubate", "DCC": "Distributed Credit Chain", "DCCT": "DocuChain", + "DCD": "DecideAI", + "DCE": "Decentra Ecosystem", + "DCHEFSOL": "Degen Chef", + "DCHEWY": "Drop Chewy", "DCHF": "DeFi Franc", "DCI": "Decentralized Cloud Infrastructure", "DCIP": "Decentralized Community Investment Protocol", @@ -3234,15 +3731,18 @@ "DD": "DuckDAO", "DDAM": "DDAM", "DDAO": "DDAO Hunters", + "DDBAM": "Didi Bam Bam", "DDD": "Scry.info", "DDDD": "People's Punk", "DDF": "Digital Developers Fund", "DDIM": "DuckDaoDime", "DDK": "DDKoin", "DDL": "Donocle", + "DDMT": "Dongdaemun Token", "DDN": "Den Domains", "DDOS": "disBalancer", "DDR": "Digi Dinar", + "DDRO": "D-Drops", "DDRST": "DigiDinar StableToken", "DDRT": "DigiDinar Token", "DDS": "DDS.Store", @@ -3259,10 +3759,15 @@ "DECI": "Maximus DECI", "DECL": "Decimal token", "DECODE": "Decode Coin", + "DEDA": "DedaCoin", "DEDE": "Dede", + "DEDI": "Dedium", + "DEDPRZ": "DEDPRZ", + "DEEBO": "Deebo the Bear", "DEED": "Deed (Ordinals)", "DEEM": "iShares MSCI Emerging Markets ETF Defichain", - "DEEP": "DeepCloud AI", + "DEEP": "DeepBook Protocol", + "DEEPCLOUD": "DeepCloud AI", "DEEPG": "Deep Gold", "DEER": "ToxicDeer Finance", "DEEX": "DEEX", @@ -3290,6 +3795,7 @@ "DEGEN": "Degen", "DEGENR": "DegenReborn", "DEGO": "Dego Finance", + "DEGOD": "degod", "DEGOV": "Degov", "DEGOV1": "Dego Finance v1", "DEHUB": "DeHub", @@ -3300,6 +3806,7 @@ "DELFI": "DeltaFi", "DELI": "NFTDeli", "DELIGHTPAY": "DelightPay", + "DELON": "Dark Elon", "DELOT": "DELOT.IO", "DELTA": "Delta Financial", "DELTAC": "DeltaChain", @@ -3313,31 +3820,41 @@ "DEOD": "Decentrawood", "DEOR": "Decentralized Oracle", "DEP": "DEAPCOIN", + "DEPA": "Department Of Government Efficiency", + "DEPINU": "Depression Inu", "DEPO": "Depo", "DEPTH": "Depth Token", "DEQ": "Dequant", + "DER": "Deri Trade", "DERC": "DeRace", "DERI": "Deri Protocol", "DERO": "Dero", "DERP": "Derp", "DES": "DeSpace Protocol", + "DESCI": "DeSci Meme", "DESI": "Desico", "DESO": "Decentralized Social", "DESTINY": "Destiny", "DESU": "Dexsport", + "DESY": "Desy Duk", "DETENSOR": "DeTensor", "DETF": "Decentralized ETF", "DETH": "DarkEther", + "DETO": "Delta Exchange", "DEUR": "DigiEuro", "DEUS": "DEUS Finance", + "DEUSD": "Elixir deUSD", "DEV": "Deviant Coin", "DEVCOIN": "DevCoin", + "DEVE": "Develocity Finance", + "DEVI": "DEVITA", "DEVO": "DeVolution", "DEVT": "DeHorizon", "DEVVE": "Devve", "DEVX": "Developeo", "DEX": "DEX", "DEXA": "DEXA COIN", + "DEXC": "DexCoyote Legends", "DEXE": "DeXe", "DEXG": "Dextoken Governance", "DEXIO": "Dexioprotocol", @@ -3395,6 +3912,7 @@ "DGORE": "DogeGoreCoin", "DGP": "DGPayment", "DGPT": "DigiPulse", + "DGTA": "Digitra.com Token", "DGTX": "Digitex Token", "DGVC": "DegenVC", "DGX": "Digix Gold token", @@ -3407,10 +3925,12 @@ "DHV": "DeHive", "DHX": "DataHighway", "DIA": "DIA", + "DIAB": "Diablo IV Solana", "DIABLO": "Diablo IV", "DIAM": "Diamond", "DIAMND": "Projekt Diamond", "DIAMOND": "Diamond Coin", + "DIAMONDINU": "Diamond", "DIBBLE": "Dibbles", "DIBC": "DIBCOIN", "DIC": "Daikicoin", @@ -3420,6 +3940,7 @@ "DICK": "adDICKted", "DICKCOIN": "DickCoin", "DID": "Didcoin", + "DIDDY": "DIDDY", "DIDID": "Didi Duck", "DIE": "Die Protocol", "DIEM": "Facebook Diem", @@ -3434,9 +3955,12 @@ "DIGI": "Digiverse", "DIGIC": "DigiCube", "DIGIF": "DigiFel", + "DIGIT": "Digital Asset Rights Token", "DIGITAL": "Digital Reserve Currency", + "DIGITS": "Digits DAO", "DIGNITY": "Dignity", "DIGS": "Diggits", + "DIK": "DikDok", "DIKO": "Arkadiko", "DILI": "D Community", "DILIGENT": "Diligent Pepe", @@ -3445,15 +3969,18 @@ "DIME": "DimeCoin", "DIMO": "DIMO", "DIN": "Dinero", - "DINERO": "Dinerobet", + "DINERO": "Dinero", + "DINEROBET": "Dinerobet", "DINGER": "Dinger Token", "DINGO": "Dingocoin", "DINO": "DinoSwap", + "DINOS": "Dinosaur Inu", "DINT": "DinarTether", "DINU": "Dogey-Inu", "DINW": "Dinowars", "DIO": "Decimated", "DIONE": "Dione", + "DIONEV1": "Dione v1", "DIP": "Etherisc", "DIPA": "Doge Ipa", "DIRTY": "Dirty Street Cats", @@ -3461,6 +3988,7 @@ "DISCOVERY": "DiscoveryIoT", "DISK": "Dark Lisk", "DISPEPE": "Disabled Pepe", + "DISTR": "Distributed Autonomous Organization", "DIT": "Ditcoin", "DITH": "Dither AI", "DIVA": "DIVA Protocol", @@ -3471,6 +3999,7 @@ "DIW": "DIWtoken", "DIYAR": "Diyarbekirspor Token", "DJED": "Djed", + "DJI": "Doge Jones Industrial Average", "DJT": "Save America", "DK": "Dominant Kong", "DKA": "dKargo", @@ -3486,6 +4015,7 @@ "DLANCE": "DeeLance", "DLB": "DiemLibre", "DLC": "Diamond Launch", + "DLCBTC": "DLC.Link", "DLISK": "Dlisk", "DLLR": "Sovryn Dollar", "DLO": "Delio", @@ -3500,11 +4030,13 @@ "DLY": "Daily Finance", "DLYCOP": "Daily COP", "DMA": "Dragoma", + "DMAGA": "Dark MAGA", "DMAIL": "DMAIL Network", "DMAR": "DMarket", "DMC": "Dream21", "DMCC": "DiscoverFeed", "DMCH": "DARMA Cash", + "DMCK": "Diamond Castle", "DMD": "DMD", "DMG": "DMM: Governance", "DMGBULL": "3X Long DMM Governance Token", @@ -3538,11 +4070,14 @@ "DNXC": "DinoX", "DNY": "Dynasty Coin", "DNZ": "Denizlispor Fan Token", + "DOAI": "DOJO Protocol", "DOBBY": "Dobby", "DOBEN": "dark boden", "DOBO": "DogeBonk", "DOC": "Dochain", + "DOCAINEURON": "Doc.ai Neuron", "DOCC": "Doc Coin", + "DOCCOM": "DOC.COM", "DOCK": "Dock.io", "DOCSWAP": "Dex on Crypto", "DOCT": "DocTailor", @@ -3550,6 +4085,7 @@ "DOD100": "Day of Defeat Mini 100x", "DODI": "DoubleDice", "DODO": "DODO", + "DODOT": "Dodo the Black Swan", "DOE": "Dogs Of Elon", "DOFI": "Doge Floki Coin", "DOG": " DOG•GO•TO•THE•MOON", @@ -3558,15 +4094,19 @@ "DOGAI": "Dogai", "DOGALD": "dogald trump", "DOGB": "DogeBoy", + "DOGBA": "DOGBA INU", "DOGBOSS": "Dog Boss", "DOGC": "Dogeclub", + "DOGCOIN": "Dogcoin", "DOGDEFI": "DogDeFiCoin", "DOGE": "Dogecoin", "DOGE1SAT": "DOGE-1SATELLITE", + "DOGE2": "Dogecoin 2.0", "DOGE20": "Doge 2.0", "DOGEB": "DogeBonk", "DOGEBNB": "DogeBNB", "DOGEC": "DogeCash", + "DOGECAST": "Dogecast", "DOGECEO": "Doge CEO", "DOGECO": "Dogecolony", "DOGECOIN": "Buff Doge Coin", @@ -3575,17 +4115,24 @@ "DOGED": "DogeCoinDark", "DOGEDAO": "DogeDao", "DOGEDASH": "Doge Dash", + "DOGEFA": "DOGEFATHER", + "DOGEFATHER": "Dogefather", "DOGEFORK": "DogeFork", "DOGEGF": "DogeGF", "DOGEGROK": "Doge Grok", "DOGEGROKAI": "Doge Of Grok AI", + "DOGEI": "Dogei", + "DOGEIN": "Doge In Glasses", "DOGEKING": "DogeKing", "DOGELEGION": "DOGE LEGION", + "DOGEM": "Doge Matrix", "DOGEMETA": "Dogemetaverse", "DOGEMOB": "DOGEMOB", "DOGENFT": "The Doge NFT", "DOGEP": "Doge Protocol", "DOGEPAY": "Doge Payment", + "DOGEPEPE": "Doge Pepe", + "DOGEPR": "DOGE PRESIDENT", "DOGER": "Robotic Doge", "DOGERA": "Dogera", "DOGES": "Dogeswap", @@ -3595,46 +4142,62 @@ "DOGEWHALE": "Dogewhale", "DOGEX": "DogeHouse Capital", "DOGEY": "Dogey", + "DOGEYIELD": "DogeYield", "DOGEZILLA": "DogeZilla", + "DOGEZILLAV1": "DogeZilla v1", + "DOGG": "Doggo", "DOGGS": "Doggensnout", "DOGGY": "Doggy", + "DOGGYCOIN": "DOGGY", "DOGH": "a dog in a hoodie", "DOGI": "dogi", "DOGIN": "Doginhood", "DOGINC": "dog in cats world", "DOGINME": "doginme", "DOGIRA": "Dogira", + "DOGK": "Dagknight Dog", + "DOGLAI": "Doglaikacoin", "DOGMI": "DOGMI", "DOGO": "DogemonGo", "DOGPAD": "DogPad Finance", "DOGRMY": "DogeArmy", - "DOGS": "Dogcoin", + "DOGS": "Dogs", "DOGSROCK": "Dogs Rock", + "DOGSS": "DOGS SOL", + "DOGSSO": "DOGS Solana", "DOGSWAG": "DogSwaghat", + "DOGW": "DOGWIFHOOD", "DOGWIFHAT": "dogwifhat", "DOGWIFSEAL": "dogwifseal", - "DOGY": "DogeYield", + "DOGY": "Dogy", "DOGZ": "Dogz", "DOJO": "ProjectDojo", "DOKI": "Doki Doki Finance", "DOKY": "Donkey King", "DOLA": "Dola USD Stablecoin", + "DOLAN": "Dolan Duck", + "DOLLAR": "Dollar", "DOLLARCOIN": "DollarCoin", "DOLLUR": "Dollur Go Brrr", + "DOLPHY": "Dolphy", "DOLZ": "DOLZ", "DOM": "Ancient Kingdom", "DOME": "Everdome", "DOMI": "Domi", + "DOMO": "Dony Montana", "DON": "Donnie Finance", "DONA": "DONASWAP", + "DONAL": "Donald Pump", "DONALD": "DONALD TRUMP", "DONALDT": "Donald The Trump", "DONATION": "DonationCoin", "DONG": "DongCoin", "DONGO": "Dongo AI", + "DONJR": "Don Jr.", "DONK": "Don-key", "DONKE": "DONKE", "DONS": "The Dons", + "DONT": "Donald Trump (dont.cash)", "DONU": "Donu", "DONUT": "Donut", "DONUTS": "The Simpsons", @@ -3643,7 +4206,9 @@ "DOOH": "Bidooh", "DOOMER": "Doomer", "DOOR": "DOOR", + "DOPA": "DopaMeme", "DOPE": "Dopamine App", + "DOPEC": "DOPE Coin", "DOPECOIN": "DopeCoin", "DOPU": "DOPU The Dog with A Purpose", "DOR": "Dorado", @@ -3651,17 +4216,20 @@ "DORAV1": "Dora Factory v1", "DORK": "DORK", "DORKL": "DORK LORD", + "DORKVADER": "DorkVader", "DORKY": "Dork Lord", "DOS": "DOS Network", "DOSE": "DOSE", "DOSHIB": "DogeShiba", "DOT": "Polkadot", "DOTC": "Dotcoin", + "DOTF": "Dot Finance", "DOTR": "Cydotori", "DOUG": "Doug The Duck", "DOUGH": "PieDAO v2 (DOUGH)", "DOV": "DOVU", "DOVI": "Dovi(Ordinals)", + "DOVIS": "Dovish Finance", "DOVU": "DOVU", "DOWS": "Shadows", "DP": "DigitalPrice", @@ -3676,6 +4244,7 @@ "DPLN": "DePlan", "DPLTR": "Palantir Tokenized Stock Defichain", "DPN": "DIPNET", + "DPOOL": "Deadpool Inu", "DPP": "Digital Assets Power Play", "DPR": "Deeper Network", "DPS": "DEEPSPACE", @@ -3694,8 +4263,10 @@ "DRAGONGROK": "DragonGROK", "DRAGONKING": "DragonKing", "DRAGONMA": "Dragon Mainland Shards", + "DRAGONX": "DragonX", "DRAGU": "DRAGU", "DRAGY": "Dragy", + "DRAKO": "Drako", "DRAM": "DRAM", "DRAW": "Drawshop Kingdom Reverse", "DRB": "Digimon Rabbit", @@ -3730,6 +4301,7 @@ "DRXNE": "Droxne", "DRZ": "Droidz", "DS": "DeStorage", + "DSAI": "DeSend Ai", "DSB": "DarkShibe", "DSC": "Dash Cash", "DSCP": "Dreamscape", @@ -3747,6 +4319,8 @@ "DSR": "Desire", "DSRUN": "Derby Stars", "DST": "Double Swap Token", + "DSTAG": "deadstag", + "DSTNY": "Destinys Chicken", "DSTR": "Dynamic Supply Tracker", "DSUN": "DsunDAO", "DSYNC": "Destra Network", @@ -3756,6 +4330,7 @@ "DTB": "Databits", "DTC": "Data Transaction", "DTCT": "DetectorToken", + "DTEC": "Dtec", "DTEM": "Dystem", "DTEP": "DECOIN", "DTG": "Defi Tiger", @@ -3768,6 +4343,7 @@ "DTORO": "DexToro", "DTR": "Dotori", "DTRC": "Datarius", + "DTRUMP": "Degen Trump", "DTSLA": "Tesla Tokenized Stock Defichain", "DTX": "DataBroker DAO", "DUA": "Brillion", @@ -3775,15 +4351,18 @@ "DUB": "DubCoin", "DUBAICAT": "Dubai Cat", "DUBBZ": "Dubbz", + "DUBER": "Düber", "DUBI": "Decentralized Universal Basic Income", "DUBX": "DUBXCOIN", "DUC": "DucatusCoin", "DUCATO": "Ducato Protocol Token", "DUCK": "Unit Protocol New", + "DUCKC": "DuckCoin", "DUCKD": "DuckDuckCoin", "DUCKER": "Ducker", "DUCKIES": "Yellow Duckies", "DUCKO": "Duck Off Coin", + "DUCKY": "Ducky Duck", "DUCX": "DucatusX", "DUDE": "DuDe", "DUEL": "GameGPT", @@ -3802,6 +4381,7 @@ "DUO": "ParallelCoin", "DUOT": "DUO Network", "DUREV": "Povel Durev", + "DUROV": "FREE DUROV", "DURTH": "iShares MSCI World ETF Tokenized Stock Defichain", "DUSD": "Decentralized USD", "DUSK": "Dusk Network", @@ -3816,6 +4396,7 @@ "DVI": "Dvision Network", "DVINCI": "Davinci Jeremie", "DVK": "Devikins", + "DVL": "Develad", "DVNQ": "Vanguard Real Estate Tokenized Stock Defichain ()", "DVOO": "Vanguard S&P 500 ETF Tokenized Stock Defichain", "DVP": "Decentralized Vulnerability Platform", @@ -3825,9 +4406,12 @@ "DVT": "DeVault", "DVTC": "DivotyCoin", "DVX": "Derivex", + "DWARFY": "Dwarfy", "DWARS": "Dynasty Wars", "DWC": "Digital Wallet", "DWEB": "DecentraWeb", + "DWOG": "DWOG THE DOG", + "DWOLF": "Dark Wolf", "DWT": "DiveWallet Token", "DWZ": "DeFi Wizard", "DX": "DxChain Token", @@ -3846,16 +4430,20 @@ "DXR": "DEXTER", "DXS": "Dx Spot", "DXT": "Dexit Finance", + "DXY": "US Degen Index 6900", + "DYAD": "Dyad Stable", "DYC": "Dycoin", "DYDX": "dYdX", "DYM": "Dymension", "DYN": "Dynamic", "DYNA": "Dynamix", + "DYNAM": "Dynamic Crypto Index", "DYNAMICTRADING": "Dynamic Trading Rights", "DYNCOIN": "Dyncoin", "DYNEX": "Dynex GPU", "DYNMT": "Dynamite", "DYNO": "DYNO", + "DYNOC": "DynoChain", "DYOR": "DYOR Token", "DYP": "Dypius", "DYPV1": "Dypius v1", @@ -3869,26 +4457,32 @@ "DZI": "DeFinition", "DZOO": "Degen Zoo", "Dow": "DowCoin", + "E1INCH": "1inch (Energi Bridge)", "E21": "E21 Coin", "E2C": "Electronic Energy Coin", "E8": "Energy8", "EA": "EagleCoin", "EAC": "Education Assessment Cult", + "EADX": "EADX Token", "EAG": "Emerging Assets Group", "EAGLE": "Eagle Token", "EAGS": "EagsCoin", - "EAI": "Edain", + "EAI": "Eagle AI", + "EARLY": "Early Risers", + "EARLYF": "EarlyFans", "EARN": "EarnGuild", "EARTH": "Earth Token", "EARTHCOIN": "EarthCoin", "EASYF": "EasyFeedback", "EAT": "EDGE Activity Token", + "EATH": "Eartherium", "EAURIC": "Eauric", "EAVE": "EaveAI", "EB3": "EB3coin", "EBA": "Elpis Battle", "EBASE": "EURBASE", "EBC": "EBCoin", + "EBCH": "Bitcoin Cash (Energiswap)", "EBEN": "Green Ben", "EBET": "EthBet", "EBIT": "eBit", @@ -3896,10 +4490,12 @@ "EBOX": "Ethbox Token", "EBS": "EbolaShare", "EBSC": "EarlyBSC", + "EBSHIB": "Wrapped Energy Shiba Inu (Energi Bridge)", "EBSO": "eBlockStock", "EBST": "eBoost", "EBT": "ELON BUYS TWITTER", "EBTC": "eBitcoin", + "EBULL": "ETHEREUM IS GOOD", "EBYT": "EarthByt", "EBZ": "Ebitz", "EC": "Echoin", @@ -3911,7 +4507,7 @@ "ECET": "Evercraft Ecotechnologies", "ECG": "EcoSmart", "ECH": "EthereCash", - "ECHO": "ECHO BOT", + "ECHOBOT": "ECHO BOT", "ECHOD": "EchoDEX", "ECHT": "e-Chat", "ECI": "Euro Cup Inu", @@ -3934,6 +4530,8 @@ "ECT": "SuperEdge", "ECTE": "EurocoinToken", "ECU": "ECOSC", + "ECXX": "ECXX", + "EDAIN": "Edain", "EDAT": "EnviDa", "EDC": "EDC Blockchain", "EDDA": "EDDASwap", @@ -3952,6 +4550,7 @@ "EDLC": "Edelcoin", "EDN": "EdenChain", "EDNS": "EDNS Token", + "EDOG": "EDOG", "EDOGE": "ElonDoge", "EDR": "Endor Protocol Token", "EDRC": "EDRCoin", @@ -3973,6 +4572,7 @@ "EFIL": "Ethereum Wrapped Filecoin", "EFK": "ReFork", "EFL": "E-Gulden", + "EFR": "End Federal Reserve", "EFT": "ETH Fan Token Ecosystem", "EFX": "The Effect.ai", "EG": "EG Token", @@ -3990,6 +4590,7 @@ "EGGP": "Eggplant Finance", "EGGY": "EGGY", "EGI": "eGame", + "EGL": "The Eagle Of Truth", "EGLD": "eGold", "EGO": "EGOcoin", "EGOD": "EgodCoin", @@ -4000,19 +4601,27 @@ "EGS": "EdgeSwap", "EGT": "Egretia", "EGX": "Enegra", + "EGY": "Egypt Cat", "EHASH": "EHash", "EHIVE": "eHive", "EHRT": "Eight Hours Token", "EIFI": "EIFI FINANCE", + "EIGEN": "EigenLayer", "EIM": "Expert Infra", + "EIQT": "IQ Prediction", "EJAC": "EJA Coin", "EJS": "Enjinstarter", "EKG": "Ekon Gold", "EKN": "Elektron", "EKO": "EchoLink", + "EKOC": "Coke", "EKS": "Elumia Krystal Shards", + "EKSM": "Synthetic Kusama (Energiswap)", "EKT": "EDUCare", "EKTA": "Ekta", + "EKTAV1": "Ekta v1", + "EKTAV2": "Ekta v2", + "EKUBO": "Ekubo Protocol", "EL": "ELYSIA", "ELA": "Elastos", "ELAC": "ELA Coin", @@ -4042,11 +4651,14 @@ "ELITE": "EthereumLite", "ELIX": "Elixir", "ELIXIR": "Starchi", + "ELIZ": "Eliza (ai16zeliza)", + "ELIZA": "Eliza (elizawakesup.ai)", "ELK": "Elk Finance", "ELLA": "Ellaism", "ELLI": "ElliotCoin", "ELM": "Elements Play", "ELMO": "ELMOERC", + "ELMOCOIN": "Elmo", "ELMON": "Elemon", "ELMT": "Element", "ELO": "ElonPark", @@ -4054,15 +4666,21 @@ "ELON2024": "ELON 2024(BSC)", "ELON404": "Elon404", "ELONCAT": "ELON CAT COIN", + "ELOND": "ELON DOGE", "ELONDOGE": "ELON DOGE", "ELONDRAGON": "ELON DRAGON", + "ELONGATE": "ElonGate", "ELONGD": "Elongate Deluxe", "ELONGT": "Elon GOAT", + "ELONIA": "Elonia Trump", "ELONIUM": "Elonium", "ELONM": "ELON MEME", + "ELONMA": "ELON MARS", "ELONMARS": "ELON MARS", + "ELONMU": "Elon Musk", "ELONONE": "AstroElon", "ELONPEPE": "Elon Pepe Robot", + "ELONTRUMP": "ELON TRUMP", "ELP": "Ellerium", "ELS": "Ethlas", "ELT": "Element Black", @@ -4080,6 +4698,7 @@ "EMAID": "MaidSafeCoin", "EMANATE": "EMANATE", "EMAR": "EmaratCoin", + "EMATIC": "Wrapped Polygon (Energi Bridge)", "EMAX": "EthereumMax", "EMB": "Overline Emblem", "EMBER": "EmberCoin", @@ -4120,15 +4739,18 @@ "ENDCEX": "Endpoint CeX Fan Token", "ENDLESS": "Endless Board Game", "ENE": "EneCoin", + "ENEAR": "Near (Energiswap)", "ENEDEX": "Enedex", "ENERGYX": "Safe Energy", "ENG": "Enigma", "ENGT": "Engagement Token", "ENIGMA": "ENIGMA", "ENJ": "Enjin Coin", + "ENJV1": "Enjin Coin v1", "ENK": "Enkidu", "ENNO": "ENNO Cash", "ENO": "Enotoken", + "ENOKIFIN": "Enoki Finance", "ENQ": "Enecuum", "ENQAI": "enqAI", "ENRG": "EnergyCoin", @@ -4182,7 +4804,8 @@ "EQT": "EquiTrader", "EQU": "Equation", "EQUAD": "Quadrant Protocol", - "EQUAL": "EqualCoin", + "EQUAL": "Equalizer DEX", + "EQUALCOIN": "EqualCoin", "EQUI": "EQUI", "EQUIL": "Equilibrium", "EQUITOKEN": "EQUI Token", @@ -4230,11 +4853,13 @@ "ESN": "Ethersocial", "ESNC": "Galaxy Arena Metaverse", "ESP": "Espers", + "ESPL": "ESPL ARENA", "ESPR": "Espresso Bot", "ESRC": "ESR Coin", "ESS": "Essentia", "EST": "ESports Chain", "ESTATE": "AgentMile", + "ESTEE": "Kaga No Fuuka Go Sapporo Kagasou", "ESW": "eSwitch®", "ESZ": "EtherSportz", "ET": "ENDO", @@ -4257,11 +4882,17 @@ "ETH2X-FLI": "ETH 2x Flexible Leverage Index", "ETHA": "ETHA Lend", "ETHAX": "ETHAX", - "ETHB": "EtherBTC", + "ETHB": "ETHEREUM ON BASE", "ETHBN": "EtherBone", "ETHD": "Ethereum Dark", + "ETHDOG": "Ethereumdog", "ETHER": "Etherparty", + "ETHERBTC": "EtherBTC", "ETHERDELTA": "EtherDelta", + "ETHERE": "Ethereal", + "ETHEREM": "Etherempires", + "ETHEREUM": "Solana Ethereum Meme", + "ETHEREUMP": "ETHEREUMPLUS", "ETHERINC": "EtherInc", "ETHERKING": "Ether Kingdoms Token", "ETHERNITY": "Ethernity Chain", @@ -4310,21 +4941,32 @@ "EUC": "Eurocoin", "EUCOIN": "EU Coin", "EUCX": "EUCX", + "EUD": "Eurodom", "EUL": "Euler", "EULER": "Euler Tools", "EUM": "Elitium", "EUNO": "EUNO", "EURC": "Euro Coin", + "EURCV": "EUR CoinVertible", + "EURCVV1": "EUR CoinVertible v1", "EURE": "Monerium EUR emoney", + "EURI": "Eurite", "EURN": "NOKU EUR", + "EUROCUP": "EURO CUP INU", "EUROE": "EUROe Stablecoin", + "EUROP": "Europa Coin", + "EURQ": "Quantoz EURQ", + "EURR": "StablR Euro", "EURS": "STASIS EURS", "EURT": "Euro Tether", + "EURTV1": "Euro Tether v1", "EURU": "Upper Euro", "EURX": "eToro Euro", "EUSD": "Egoras Dollar", + "EUTBL": "Spiko EU T-Bills Money Market Fund", "EV": "EVAI", "EVA": "Evadore", + "EVAI": "EVA Intelligence", "EVAN": "Evanesco Network", "EVAULT": "EthereumVault", "EVC": "Eventchain", @@ -4342,9 +4984,11 @@ "EVERGREEN": "EverGreenCoin", "EVERLIFE": "EverLife.AI", "EVERMOON": "EverMoon", + "EVERV": "EverValue Coin", "EVERY": "Everyworld", "EVIL": "EvilCoin", "EVILPEPE": "Evil Pepe", + "EVIN": "Evin Token", "EVMOS": "Evmos", "EVN": "Evn Token", "EVO": "EvoVerses", @@ -4388,6 +5032,7 @@ "EXO": "Exosis", "EXOS": "Exobots", "EXP": "Expanse", + "EXPAND": "Gems", "EXPO": "Exponential Capital", "EXRD": "Radix", "EXRN": "EXRNchain", @@ -4402,9 +5047,12 @@ "EYETOKEN": "EYE Token", "EZ": "EasyFi V2", "EZC": "EZCoin", + "EZEIGEN": "Restaked EIGEN", "EZETH": "Renzo Restaked ETH", "EZI": "Ezillion", "EZM": "EZMarket", + "EZPZ": "Eazy Peazy", + "EZSOL": "Renzo Restaked SOL", "EZT": "EZToken", "EZY": "EzyStayz", "ElvishMagic": "EMAGIC", @@ -4423,9 +5071,11 @@ "FACETER": "Faceter", "FACT": "Orcfax", "FACTOM": "Factom", + "FACTORY": "ChainFactory", "FACTR": "Defactor", "FADO": "FADO Go", "FAG": "PoorFag", + "FAH": "Falcons", "FAI": "Fairum", "FAIR": "FairCoin", "FAIRC": "Faireum Token", @@ -4435,9 +5085,11 @@ "FAKT": "Medifakt", "FALCONS": "Falcon Swaps", "FALX": "FalconX", + "FAM": "Family", "FAME": "Fame MMA", "FAMEC": "FameCoin", "FAMILY": "The Bitcoin Family", + "FAML": "FAML", "FAMOUSF": "Famous Fox Federation", "FAN": "Fanadise", "FAN360": "Fan360", @@ -4447,19 +5099,25 @@ "FANV": "FanVerse", "FANX": "FrontFanz", "FANZ": "FanChain", + "FAPTAX": "Faptax", "FAR": "Farmland Protocol", "FARA": "FaraLand", "FARCA": "Farcana", "FARM": "Harvest Finance", "FARMA": "FarmaTrust", "FARMC": "FARM Coin", + "FARME": "Farmers Only", "FARMING": "Farming Bad", "FARMS": "Farmsent", + "FARTCOIN": "Fartcoin", + "FAS": "fast construction coin", "FAST": "Fastswap", + "FASTAI": "Fast And Ai", "FASTMOON": "FastMoon", "FASTV1": "Fastswap v1", "FAT": "Fatcoin", "FATCAKE": "FatCake", + "FATH": "Father Of Meme: Origin", "FATHER": "DogeFather", "FATHOM": "Fathom", "FATMICHI": "FATMICHI", @@ -4474,6 +5132,8 @@ "FBG": "Fort Block Games", "FBN": "Five balance", "FBNB": "ForeverBNB", + "FBOMB": "fBomb", + "FBOMBV1": "fBomb v1", "FBURN": "Forever Burn", "FBX": "Finance Blocks", "FC": "Facecoin", @@ -4503,7 +5163,9 @@ "FDX": "fidentiaX", "FDZ": "Friendz", "FEAR": "Fear", + "FEARNOT": "FEAR NOT", "FECES": "FECES", + "FEE": "FEED EVERY GORILLA", "FEED": "Feeder Finance", "FEENIXV2": "ProjectFeenixv2", "FEES": "UNIFEES", @@ -4522,8 +5184,9 @@ "FERT": "Chikn Fert", "FERZAN": "Ferzan", "FESS": "Fesschain", - "FET": "Fetch.AI", + "FET": "Artificial Superintelligence Alliance", "FETCH": "Fetch", + "FETS": "FE TECH", "FEVR": "RealFevr", "FEX": "FEX Token", "FEY": "Feyorra", @@ -4534,6 +5197,7 @@ "FFCT": "FortFC", "FFM": "Files.fm Library", "FFN": "Fairy Forest", + "FFTP": "FIGHT FOR THE PEOPLE", "FFUEL": "getFIFO", "FFYI": "Fiscus FYI", "FGC": "FantasyGold", @@ -4558,7 +5222,11 @@ "FIF": "flokiwifhat", "FIFTY": "FIFTYONEFIFTY", "FIG": "FlowCom", + "FIGH": "FIGHT FIGHT FIGHT", "FIGHT": "Crypto Fight Club", + "FIGHTMAGA": "FIGHT MAGA", + "FIGHTPEPE": "FIGHT PEPE", + "FIGHTRUMP": "FIGHT TRUMP", "FIH": "Fidelity House", "FIII": "Fiii", "FIL": "FileCoin", @@ -4570,9 +5238,11 @@ "FIN": "DeFiner", "FINA": "Defina Finance", "FINALE": "Ben's Finale", + "FINAN": "FINANCIAL TRANSACTION SYSTEM", "FINB": "Finblox", "FINC": "Finceptor", "FIND": "FindCoin", + "FINDER": "Finder AI", "FINE": "Refinable", "FINGER": "Finger Blast", "FINK": "FINK", @@ -4582,15 +5252,20 @@ "FINT": "FintraDao", "FINU": "Formula Inu", "FIO": "FIO Protocol", + "FIONA": "Fiona", + "FIONABSC": "Fiona", "FIRA": "Defira", "FIRE": "Matr1x Fire", "FIRECOIN": "FireCoin", + "FIREW": "Fire Wolf", "FIRO": "Firo", "FIRSTHARE": "FirstHare", "FIRU": "Firulais Finance", "FIS": "Stafi", "FISH": "Polycat Finance", - "FIST": "FistBump", + "FISHK": "Fishkoin", + "FIST": "Fistbump", + "FISTBUMP": "FistBump", "FIT": "Financial Investment Token", "FITC": "Fitcoin", "FITFI": "Step App", @@ -4610,17 +5285,23 @@ "FKSK": "Fatih Karagümrük SK", "FKX": "FortKnoxster", "FL": "Freeliquid", + "FLA": "Flappy", "FLAG": "Flag Network", + "FLAKY": "FLAKY", "FLAME": "FireStarter", "FLAP": "Flappy Coin", "FLAPPY": "Flappy", + "FLAREF": "FlareFoxInu", "FLAS": "Flas Exchange Token", "FLASH": "Flashstake", "FLASHC": "FLASH coin", + "FLAVIA": "Flavia Is Online", + "FLAY": "Flayer", "FLC": "FlowChainCoin", "FLD": "FluidAI", "FLDC": "Folding Coin", "FLDT": "FairyLand", + "FLEA": "FLEABONE", "FLEPE": "Floki VS Pepe", "FLETA": "FLETA", "FLEX": "FLEX Coin", @@ -4665,6 +5346,7 @@ "FLOVI": "Flovi inu", "FLOVM": "FLOV MARKET", "FLOW": "Flow", + "FLOWER": "FlowerAI", "FLOWP": "Flow Protocol", "FLOYX": "Floyx", "FLP": "Gameflip", @@ -4673,7 +5355,10 @@ "FLRS": "Flourish Coin", "FLS": "Flits", "FLT": "Fluence", + "FLUFFI": "Fluffington", + "FLUFFY": "FLUFFY", "FLUFFYS": "Fluffys", + "FLUI": "Fluidity", "FLUID": "Fluid", "FLURRY": "Flurry Finance", "FLUT": "Flute", @@ -4709,9 +5394,11 @@ "FNLX": "Fignal X", "FNO": "Fonero", "FNP": "FlipNpik", + "FNS": "FAUNUS", "FNSA": "FINSCHIA", "FNTB": "FinTab", "FNX": "FinNexus", + "FNXAI": "Finanx AI", "FNZ": "Fanzee", "FO": "FIBOS", "FOA": "Fragments of arker", @@ -4720,14 +5407,18 @@ "FOCV": "FOCV", "FODL": "Fodl Finance", "FOF": "Future Of Fintech", - "FOFAR": "Fofar", + "FOFAR": "FoFar", + "FOFARBASE": "FOFAR", + "FOFARIO": "Fofar", "FOFO": "FOFO Token", "FOGE": "Fat Doge", "FOIN": "Foin", "FOL": "Folder Protocol", "FOLD": "Manifold Finance", "FOLO": "Alpha Impact", - "FOMO": "Aavegotchi FOMO", + "FOMO": "FOMO BULL CLUB", + "FOMON": "FOMO Network", + "FOMOSOL": "FOMOSolana", "FON": "INOFI", "FONE": "Fone", "FONS": "FONSmartChain", @@ -4743,6 +5434,7 @@ "FORCE": "TriForce Tokens", "FORCEC": "Force Coin", "FORE": "FORE Protocol", + "FOREST": "FOREST", "FORESTPLUS": "The Forbidden Forest", "FOREVER": "Forever Coin", "FOREVERFOMO": "ForeverFOMO", @@ -4771,9 +5463,11 @@ "FOXE": "Foxe", "FOXF": "Fox Finance", "FOXGIRL": "FoxGirl", + "FOXI": "Foxify", "FOXSY": "Foxsy AI", "FOXT": "Fox Trading", "FOXV2": "FoxFinanceV2", + "FOXXY": "FOXXY", "FOXY": "Foxy", "FP": "Fren Pet", "FPAD": "FantomPAD", @@ -4786,6 +5480,7 @@ "FR": "Freedom Reserve", "FRA": "Findora", "FRAC": "FractalCoin", + "FRATT": "Frogg and Ratt", "FRAX": "Frax", "FRAZ": "FrazCoin", "FRBK": " FreeBnk", @@ -4793,6 +5488,7 @@ "FRD": "Farad", "FRDX": "Frodo Tech", "FRE": "FreeCoin", + "FREAK": "Freakoff", "FREC": "Freyrchain", "FRECNX": "FreldoCoinX", "FRED": "FREDEnergy", @@ -4800,8 +5496,11 @@ "FREE": "FREE coin", "FREED": "FreedomCoin", "FREEDO": "Freedom", + "FREEDOM": "Freedom Protocol Token", "FREELA": "DecentralFree", + "FREEPAVEL": "Free Pavel", "FREEROSS": "FreeRossDAO", + "FREET": "FreeTrump", "FREL": "Freela", "FREN": "FREN", "FRENCH": "French On Base", @@ -4828,8 +5527,12 @@ "FROGGY": "Froggy", "FROGLIC": "Pink Hood Froglicker", "FROGO": "Frogo", + "FROK": "Frok.ai", "FRONK": "Fronk", "FRONT": "Frontier", + "FROP": "Popo The Frog", + "FROSTY": "Frosty the Polar Bear", + "FROX": "Frox", "FROYO": "Froyo Games", "FROZE": "FrozenAi", "FRP": "Fame Reward Plus", @@ -4852,6 +5555,7 @@ "FSHN": "Fashion Coin", "FSM": "Floki SafeMoon", "FSN": "Fusion", + "FSNV1": "Fusion v1", "FSO": "FSociety", "FST": "Futureswap", "FSTC": "FastCoin", @@ -4859,6 +5563,7 @@ "FT": "Fracton Protocol", "FTB": "Fit&Beat", "FTC": "FeatherCoin", + "FTD": "42DAO", "FTG": "fantomGO", "FTH": "Fintyhub Token", "FTHM": "Fathom Protocol", @@ -4868,6 +5573,7 @@ "FTMO": "Fantom Oasis", "FTN": "Fasttoken", "FTO": "FuturoCoin", + "FTON": "Fanton", "FTP": "FuturePoints", "FTR": "FactR", "FTRB": "Faith Tribe", @@ -4875,18 +5581,22 @@ "FTS": "Fortress Lending", "FTT": "FTX Token", "FTTOKEN": "Finance Token", + "FTTT": "FTT Token", "FTUM": "Fatum", "FTVT": "FashionTV Token", "FTW": "FutureWorks", "FTX": "FintruX", "FTXT": "FUTURAX", + "FU": "FU Money", "FUBAO": "FUBAO", "FUCK": "Fuck Token", "FUD": "FUD.finance", "FUEL": "Jetfuel Finance", + "FUELX": "Fuel", "FUFU": "Fufu Token", + "FUG": "FUG", "FUJIN": "Fujinto", - "FUKU": "Furukuru", + "FUKU": "FUKU-KUN", "FUL": "Fulcrom Finance", "FUMO": "Alien Milady Fumo", "FUN": "FUN Token", @@ -4906,6 +5616,7 @@ "FUR": "Furio", "FURIE": "Matt Furie", "FURU": "Furucombo", + "FURUKURU": "Furukuru", "FURY": "Engines of Fury", "FURYX": "Metafury", "FUS": "Fus", @@ -4914,7 +5625,9 @@ "FUSE": "Fuse Network Token", "FUSION": "FusionBot", "FUSO": "Fusotao", + "FUT": "FuturesAI", "FUTC": "FutCoin", + "FUTUR": "Future Token", "FUTURE": "FutureCoin", "FUTUREAI": "Future AI", "FUZE": "FUZE Token", @@ -4925,6 +5638,7 @@ "FWB": "Friends With Benefits Pro", "FWC": "Qatar 2022", "FWH": "FigureWifHat", + "FWOG": "Fwog", "FWT": "Freeway Token", "FWW": "Farmers World Wood", "FX": "Function X", @@ -4938,13 +5652,15 @@ "FXS": "Frax Share", "FXST": "FX Stock Token", "FXT": "FuzeX", + "FXUSD": "f(x) Protocol fxUSD", "FXY": "Floxypay", "FYD": "FYDcoin", + "FYDO": "Fly Doge", "FYN": "Affyn", "FYP": "FlypMe", "FYZ": "Fyooz", "FYZNFT": "Fyooz NFT", - "G": "GRN Grid", + "G": "Gravity", "G1X": "GoldFinX", "G3": "GAM3S.GG", "G50": "G50", @@ -4976,21 +5692,29 @@ "GALT": "Galtcoin", "GAM": "Gambit coin", "GAMB": "GAMB", + "GAMBI": "Gambi Fi", "GAMBIT": "Gambit", "GAMBL": "Metagamble", "GAME": "GameBuild", "GAMEBUD": "GAMEBUD", "GAMEC": "Game", + "GAMECO": "Game.com", "GAMECRED": "GameCredits", + "GAMEF": "Game Fantasy Token", "GAMEFI": "GameFi Token", "GAMEFORK": "GameFork", "GAMEIN": "Game Infinity", "GAMER": "GameStation", "GAMERFI": "GamerFI", "GAMES": "Gamestarter", + "GAMEST": "GameStop Coin", "GAMESTARS": "Game Stars", + "GAMESTO": "GameStop", + "GAMESTUMP": "GAMESTUMP", + "GAMET": "GAME Token", "GAMEX": "GameX", "GAMI": "GAMI World", + "GAMIN": "Gaming Stars", "GAMINGDOGE": "GAMINGDOGE", "GAMINGSHIBA": "GamingShiba", "GAMMA": "Gamma Strategies", @@ -5020,6 +5744,7 @@ "GATSBY": "Gatsby Inu", "GAU": "Gamer Arena", "GAUSS": "Gauss0x", + "GAY": "GAY", "GAYPEPE": "Gay Pepe", "GAYSLER": "Gaysler", "GAZE": "GazeTV", @@ -5052,6 +5777,7 @@ "GCAT": "Giga Cat on Base", "GCB": "Global Commercial Business", "GCC": "GuccioneCoin", + "GCCO": "GCCOIN", "GCME": "GoCryptoMe", "GCN": "gCn Coin", "GCOIN": "Galaxy Fight Club", @@ -5066,6 +5792,7 @@ "GDE": "Golden Eagle", "GDL": "GodlyCoin", "GDO": "GroupDao", + "GDOG": "GDOG", "GDOGE": "Golden Doge", "GDR": "Guider.Travel", "GDRT": "Good Driver Reward Token", @@ -5078,7 +5805,10 @@ "GEAR": "Gearbox Protocol", "GEC": "Geco.one", "GECKO": "Gecko Coin", + "GECKY": "Gecky", + "GEEK": "De:Lithe Last Memories", "GEEQ": "Geeq", + "GEF": "GemFlow", "GEGE": "Gege", "GEIST": "Geist Finance", "GEKKO": "Gekko HQ", @@ -5086,15 +5816,17 @@ "GELO": "Grok Elo", "GEM": "Gemie", "GEMA": "Gemera", - "GEME": "GAMESTUMP", + "GEME": "GEME", "GEMG": "GemGuardian", + "GEMI": "Gemini Inu", "GEMINI": "Gemini Ai", "GEMINIT": "Gemini", - "GEMS": "Gems", + "GEMS": "Gems VIP", "GEMSTON": "GEMSTON", "GEMZ": "Gemz Social", "GEN": "DAOstack", "GENE": "Genopets", + "GENECTO": "Gene", "GENESIS": "Genesis Worlds", "GENI": "Genius", "GENIE": "The Genie", @@ -5105,6 +5837,7 @@ "GENS": "Genshiro", "GENSLR": "Good Gensler", "GENSTAKE": "Genstake", + "GENT": "Gentleman", "GENX": "Genx Token", "GENXNET": "Genesis Network", "GENZ": "GENZ Token", @@ -5124,6 +5857,7 @@ "GET": "Guaranteed Entrance Token", "GETA": "Getaverse", "GETH": "Guarded Ether", + "GETLIT": "LIT", "GETX": "Guaranteed Ethurance Token Extra", "GEX": "Gexan", "GEZY": "EZZY GAME GEZY", @@ -5142,6 +5876,7 @@ "GFY": "go fu*k yourself", "GG": "Reboot", "GGAVAX": "GoGoPool AVAX", + "GGB": "GGEBI", "GGC": "Global Game Coin", "GGCM": "Gold Guaranteed Coin", "GGG": "Good Games Guild", @@ -5149,7 +5884,6 @@ "GGM": "Monster Galaxy", "GGMT": "GG MetaGame", "GGOLD": "GramGold Coin", - "GGP": "GGPro", "GGPT": "Generative GPT", "GGR": "GGRocket", "GGS": "Gilgam", @@ -5158,10 +5892,15 @@ "GGTKN": "GG Token", "GHA": "Ghast", "GHC": "Galaxy Heroes Coin", - "GHCOLD": "Galaxy Heroes Coin", + "GHCV1": "Galaxy Heroes Coin v1", + "GHCV2": "Galaxy Heroes Coin v2", + "GHCV3": "Galaxy Heroes Coin v3", "GHD": "Giftedhands", + "GHDV1": "Giftedhands v1", + "GHE": "GHETTO PEPE", "GHNY": "Grizzly Honey", "GHO": "GHO", + "GHOAD": "GhoadCoin", "GHOST": "GhostbyMcAfee", "GHOSTCOIN": "GhostCoin", "GHOSTM": "GhostMarket", @@ -5179,14 +5918,21 @@ "GIF": "Gift Token", "GIFT": "GiftNet", "GIG": "GigaCoin", - "GIGA": "GigaSwap", + "GIGA": "Gigachad", + "GIGACAT": "GIGACAT", "GIGACHAD": "GigaChad", + "GIGASWAP": "GigaSwap", + "GIGGLE": "Giggle Academy", + "GIGS": "Climate101", "GIGX": "GigXCoin", "GIKO": "Giko Cat", + "GILOEX": "Gilo", "GIM": "Gimli", "GIMMER": "Gimmer", + "GIMMERV1": "Gimmer v1", "GIN": "GINcoin", "GINGER": "GINGER", + "GINNAN": "Ginnan The Cat", "GINOA": "Ginoa", "GINUX": "Green Shiba Inu", "GINZA": "GINZA NETWORK", @@ -5194,15 +5940,20 @@ "GIOT": "Giotto Coin", "GIOVE": "GIOVE", "GIR": "Girlfriend", + "GIRLS": "Girls Club", + "GITH": "GitHub's Mascot Octocat", "GIV": "Giveth", "GIVE": "GiveCoin", "GIZ": "GIZMOcoin", + "GIZMO": "GIZMO•IMAGINARY• KITTEN (Runes)", "GJC": "Global Jobcoin", + "GKAPPA": "Golden Kappa", "GKF": "Galatic Kitty Fighters", "GKI": "GKi", "GL": "Lemmings", "GLA": "Gladius", "GLAX": "BLOCK GALAXY NETWORK", + "GLAZE": "Glaze", "GLB": "Golden Ball", "GLC": "GoldCoin", "GLCH": "Glitch", @@ -5218,13 +5969,17 @@ "GLFT": "Global Fan Token", "GLI": "GLI TOKEN", "GLIDE": "Glide Finance", + "GLIESE": "GlieseCoin", "GLINK": "Gemlink", "GLINT": "BeamSwap", "GLM": "Golem Network Token", "GLMR": "Moonbeam", + "GLMV1": "Golem Network Token v1", "GLN": "Galion Token", + "GLO": "Global Innovation Platform", "GLOBAL": "GlobalCoin", "GLOBE": "Global", + "GLORP": "Glorp", "GLORY": "SEKAI GLORY", "GLOS": "GLOS", "GLOWSHA": "GlowShares", @@ -5247,6 +6002,7 @@ "GME": "GameStop", "GMEE": "GAMEE", "GMEPEPE": "GAMESTOP PEPE", + "GMETHERFRENS": "GM", "GMETRUMP": "GME TRUMP", "GMEX": "Game Coin", "GMFAM": "GMFAM", @@ -5254,11 +6010,13 @@ "GMI": "GamiFi", "GML": "GameLeagueCoin", "GMM": "Gamium", - "GMMT": "Green Mining Movement Token", + "GMMT": "Giant Mammoth", "GMNG": "Global Gaming", "GMNT": "Gmining", "GMPD": "GamesPad", "GMR": "GAMER", + "GMRV1": "GAMER v1", + "GMRV2": "GAMER v2", "GMRX": "Gaimin", "GMS": "Gemstra", "GMT": "STEPN", @@ -5276,6 +6034,8 @@ "GNNX": "Gennix", "GNO": "Gnosis", "GNOME": "GNOME", + "GNOMY": "Gnomy", + "GNON": "Numogram", "GNR": "Gainer", "GNS": "Gains Network", "GNT": "GreenTrust", @@ -5288,11 +6048,17 @@ "GOAL": "GOAL token", "GOALBON": "Goal Bonanza", "GOALS": "UnitedFans", - "GOAT": "Goat", + "GOAT": "Goatseus Maximus", + "GOATAI": "GOAT AI", + "GOATCOIN": "Goat", + "GOATSE": "GOATSE", "GOB": "Goons of Balatroon", "GOC": "GoCrypto", + "GOCHU": "Gochujangcoin", "GOD": "Bitcoin God", + "GODCAT": "GodcatExplodingKittens", "GODE": "Gode Chain", + "GODEX": "GUARD OF DECENT", "GODL": "GODL", "GODS": "Gods Unchained", "GODZ": "Cryptogodz", @@ -5301,6 +6067,7 @@ "GOFF": "Gift Off Token", "GOFX": "GooseFX", "GOG": "Guild of Guardians", + "GOGLZ": "GOGGLES", "GOGO": "GOGO Finance", "GOGU": "GOGU Coin", "GOIN": "GOinfluencer", @@ -5310,43 +6077,63 @@ "GOLC": "GOLCOIN", "GOLD": "CyberDragon Gold", "GOLDCAT": "GOLD CAT", + "GOLDCOINETH": "Gold", + "GOLDE": "GOLDEN AGE", "GOLDEN": "Golden Inu", "GOLDENG": "Golden Goose", "GOLDF": "Gold Fever", "GOLDMIN": "GoldMiner", + "GOLDN": "GoLondon", "GOLDPIECES": "GoldPieces", + "GOLDS": "Gold Standard", "GOLDX": "eToro Gold", "GOLDY": "DeFi Land Gold", "GOLF": "GolfCoin", + "GOLFI": "Golf is Boring", "GOLOS": "Golos", "GOLOSBLOCKCHAIN": "Golos Blockchain", "GOM": "Gomics", "GOM2": "GoMoney2", "GOMA": "GOMA Finance", + "GOMAV1": "GOMA Finance v1", + "GOMAV2": "GOMA Finance v2", "GOMD": "GOMDori", "GOME": "Game of Memes", "GOMT": "GoMeat", + "GOMV1": "GoMoney", + "GONDOLA": "Gondola", "GONE": "GONE", + "GONG": "GONG", "GOO": "Gooeys", "GOOCH": "Gooch", "GOOD": "Goodomy", + "GOODM": "Good Morning!", + "GOODMO": "Good Morning", + "GOOG": "Googly Cat", "GOOGLE": "Deepmind Ai", "GOOGLY": "Googly Cat", + "GOOMPY": "Goompy by Matt Furie", "GOON": "Goonies", + "GOP": "The Republican Party", "GOPX": "GOPX Token", "GORA": "Gora", "GOREC": "GoRecruit", "GORGONZOLA": "Heroes 3 Foundation", + "GORGONZOLAV1": "Heroes 3 Foundation v1", "GORILLA": "Gorilla", "GORILLAD": "Gorilla Diamond", "GORILLAINU": "Gorilla Inu", + "GORPLE": "GorplesCoin", "GOS": "Gosama", "GOSS": "GOSSIP-Coin", "GOST": "SoulCoin", "GOT": "ParkinGo", "GOTEM": "gotEM", "GOTG": "Got Guaranteed", + "GOTTI": "Gotti Token", "GOTX": "GothicCoin", + "GOU": "Gou", + "GOUT": "GOUT", "GOV": "SubDAO", "GOVI": "Govi", "GOVT": "The Government Network", @@ -5379,8 +6166,11 @@ "GRAI": "Gravita Protocol", "GRAIL": "Camelot Token", "GRAIN": "Granary", + "GRAM": "Gram", "GRANDCOIN": "GrandCoin", + "GRANDMA": "Grandma", "GRAPE": "GrapeCoin", + "GRASS": "Grass", "GRAV": "Graviton", "GRAVITAS": "Gravitas", "GRAVITYF": "Gravity Finance", @@ -5390,10 +6180,15 @@ "GRC": "GreenCoin.AI", "GRE": "GreenCoin", "GREARN": "GrEarn", + "GREE": "Green God Candle", "GREEN": "GreenX", + "GREENH": "Greenheart CBD", + "GREENMMT": "Green Mining Movement Token", + "GREENPOWER": "GreenPower", "GREENT": "Greentoken", "GREG": "greg", "GRELF": "GRELF", + "GREMLY": "Gremly", "GREXIT": "GrexitCoin", "GREY": "Grey Token", "GRFT": "Graft Blockchain", @@ -5410,9 +6205,11 @@ "GRLC": "Garlicoin", "GRM": "GridMaster", "GRMD": "GreenMed", - "GRN": "GreenPower", + "GRN": "GRN Grid", "GRND": "SuperWalk", + "GRNV1": "GRN Grid v1", "GRO": "Gro DAO Token", + "GROGGO": "Groggo By Matt Furie", "GROK": "Grok", "GROK2": "GROK 2.0", "GROKBANK": "Grok Bank", @@ -5480,6 +6277,7 @@ "GTAVI": "GTAVI", "GTBOT": "Gaming-T-Bot", "GTC": "Gitcoin", + "GTCC": "GTC COIN", "GTCOIN": "Game Tree", "GTE": "GreenTek", "GTF": "GLOBALTRUSTFUND TOKEN", @@ -5494,6 +6292,7 @@ "GTSE": "Global Tourism Sharing Ecology", "GTTM": "Going To The Moon", "GTX": "GALLACTIC", + "GUA": "GUA", "GUAC": "Guacamole", "GUAP": "Guapcoin", "GUAR": "Guarium", @@ -5503,6 +6302,7 @@ "GUCCI": "GUCCI", "GUE": "GuerillaCoin", "GUESS": "Peerguess", + "GUGU": "gugu", "GUI": "Gui Inu", "GUILD": "BlockchainSpace", "GUISE": "GUISE", @@ -5515,14 +6315,17 @@ "GUNS": "GeoFunders", "GUP": "Guppy", "GURL": "Gently Used Girl", + "GURU": "Guru Network", "GUSD": "Gemini Dollar", "GUSDT": "Global Utility Smart Digital Token", "GUT": "Genesis Universe", "GUUFY": "Guufy", + "GUZUTA": "CLYDE", "GVC": "Global Virtual Coin", "GVE": "Globalvillage Ecosystem", "GVL": "Greever", "GVR": "Grove [OLD]", + "GVRV1": "Grove v1", "GVT": "Genesis Vision", "GW": "Gyrowin", "GWD": "GreenWorld", @@ -5556,8 +6359,13 @@ "HABIBI": "The Habibiz", "HAC": "Hackspace Capital", "HACD": "Hacash Diamond", + "HACH": "Hachiko", "HACHI": "Hachi", + "HACHIK": "Hachiko", "HACHIKO": "Hachiko Inu Token", + "HACHIONB": "Hachi On Base", + "HACK": "HACK", + "HAGGIS": "New Born Haggis Pygmy Hippo", "HAHA": "Hasaki", "HAI": "Hacken Token", "HAIR": " HairDAO", @@ -5575,9 +6383,12 @@ "HAMI": "Hamachi Finance", "HAMMY": "SAD HAMSTER", "HAMS": "HamsterCoin", + "HAMSTER": "Space Hamster", + "HAMSTERB": "HamsterBase", "HAMSTR": "Hamster Coin", "HAN": "HanChain", "HANA": "Hanacoin", + "HANAETHCTO": "HANA", "HAND": "ShowHand", "HANDY": "Handy", "HANK": "Hank", @@ -5585,12 +6396,18 @@ "HAO": "HistoryDAO", "HAP": "Happy Train", "HAPI": "HAPI", + "HAPPY": "Happy Cat", + "HAR": "Harambe Coin", "HARAM": "HARAM", "HARAMBE": "Harambe on Solana", "HARD": "Kava Lend", "HARE": "Hare Token", "HAREPLUS": "Hare Plus", "HAROLD": "Harold", + "HARPER": "Harper", + "HARR": "HARRIS DOGS", + "HARRIS": "KAMALA HARRIS", + "HARRISV": "Harris V Trump", "HARRYP": "HarryPotterObamaSonic10Inu (ERC20)", "HART": "HARA", "HASBIK": "Hasbulla", @@ -5605,17 +6422,22 @@ "HAUS": "DAOhaus", "HAVOC": "Havoc", "HAVY": "Havy", + "HAW": "Hawk Tuah", "HAWK": "Hawksight", + "HAWKCITY": "Hawk", + "HAWKPTAH": "Hawk Ptah", "HAWKTUAH": "Hawk Tuah", - "HAY": "Destablecoin HAY", + "HAXS": "Axie Infinity Shards (Harmony One Bridge)", "HAYYA": "GO HAYYA", "HAZ": "Hazza", "HAZE": "HazeCoin", "HB": "HeartBout", "HBAR": "Hedera Hashgraph", + "HBARBARIAN": "HBARbarian", "HBARX": "HBARX", "HBB": "Hubble", "HBC": "HBTC Captain Token", + "HBCH": "Huobi BCH", "HBD": "Hive Dollar", "HBDC": "Happy Birthday Coin", "HBE": "healthbank", @@ -5624,9 +6446,11 @@ "HBO": "Hash Bridge Oracle", "HBOT": "Hummingbot", "HBRS": "HubrisOne", + "HBSV": "Huobi BSV", "HBT": "Habitat", "HBTC": "Huobi BTC", "HBX": "Hyperbridge", + "HBZ": "HBZ Coin", "HC": "HyperCash", "HCC": "HappyCreatorCoin", "HCT": "HurricaneSwap Token", @@ -5641,7 +6465,9 @@ "HDV": "Hydraverse", "HDX": "HydraDX", "HE": "Heroes & Empires", + "HEA": "Healium", "HEAL": "Etheal", + "HEALT": "Healthmedi", "HEART": "Humans", "HEARTBOUT": "HeartBout Pay", "HEARTR": "Heart Rate", @@ -5657,11 +6483,17 @@ "HEGE": "Hege", "HEGG": "Hummingbird Egg", "HEGIC": "Hegic", + "HEHE": "hehe", + "HEL": "Hello Puppy", + "HELA": "Science Cult Mascot", + "HELI": "Helion", + "HELINK": "Chainlink (Huobi Exchange)", "HELIOS": "Mission Helios", "HELL": "HELL COIN", "HELLO": "HELLO", "HELMET": "Helmet Insure", "HELPS": "HelpSeed", + "HEM": "Hemera", "HEMAN": "HE-MAN", "HEMULE": "Hemule", "HEP": "Health Potion", @@ -5669,13 +6501,17 @@ "HERA": "Hero Arena", "HERB": "HerbCoin", "HERBE": "Herbee", + "HERME": "Hermes DAO", "HERMES": "Hermes Protocol", "HERO": "Metahero", + "HEROC": "HEROcoin", "HEROES": "Dehero Community Token", "HEROESC": "HeroesChained", + "HEROI": "Heroic Saga Shiba", "HET": "HavEther", "HETA": "HetaChain", "HETH": "Huobi Ethereum", + "HEWE": "Health & Wealth", "HEX": "HEX", "HEXC": "HexCoin", "HEZ": "Hermez Network Token", @@ -5683,6 +6519,7 @@ "HFI": "Holder Finance", "HFIL": "Huobi Fil", "HFT": "Hashflow", + "HFUN": "Hold.fun", "HGEN": "HGEN DAO", "HGET": "Hedget", "HGHG": "HUGHUG Coin", @@ -5718,6 +6555,7 @@ "HIH": "HiHealth", "HIKARI": "Hikari Protocol", "HILL": "President Clinton", + "HILO": "HILO", "HIM": "Human Intelligence Machine", "HIMAYC": "hiMAYC", "HIME": "Phantom of the Kill", @@ -5733,12 +6571,14 @@ "HIP": "HIPPOP", "HIPENGUINS": "hiPENGUINS", "HIPP": "El Hippo", + "HIPPO": "sudeng", "HIPUNKS": "hiPUNKS", "HIRE": "HireMatch", "HIRENGA": "hiRENGA", "HISAND33": "hiSAND33", "HISEALS": "hiSEALS", "HISQUIGGLE": "hiSQUIGGLE", + "HISS": "Snake of Solana", "HIT": "HitChain", "HITBTC": "HitBTC Token", "HITOP": "Hitop", @@ -5757,6 +6597,7 @@ "HLD": "HyperLending", "HLDY": "HOLIDAY", "HLG": "Holograph", + "HLINK": "Chainlink (Harmony One Bridge)", "HLM": "Helium", "HLN": "Holonus", "HLP": "Purpose Coin", @@ -5764,6 +6605,7 @@ "HLPT": "HLP Token", "HLS": "Halis", "HLT": "HyperLoot", + "HLTC": "Huobi LTC", "HLX": "Helex", "HMC": "Hi Mutual Society", "HMD": "Homelend", @@ -5777,12 +6619,15 @@ "HMR": "Homeros", "HMRN": "Homerun", "HMST": "Hamster Marketplace Token", + "HMSTR": "Hamster Kombat", "HMT": "HUMAN Token", "HMTT": "Hype Meme Token", + "HMU": "hit meeee upp", "HMX": "HMX", "HNB": "HashNet BitEco", "HNC": "Hellenic Coin", "HNCN": "Huncoin", + "HND": "Hundred Finance", "HNS": "Handshake", "HNST": "Honest", "HNT": "Helium", @@ -5812,21 +6657,29 @@ "HOM": "Homeety", "HOME": "OtterHome", "HOMER": "Homer Simpson", + "HOMERB": "Homer BSC", + "HOMERO": "Homer Of Meme", "HOMI": "HOMIHELP", "HOMIECOIN": "Homie Wars", "HOMMIES": "HOMMIES", + "HOMS": "Heroes of memes", "HON": "SoulSociety", "HONEY": "Hivemapper", "HONEYCOIN": "Honey", "HONG": "HongKongDAO", "HONK": "Honk", + "HONKLER": "Honkler", "HONOR": "HonorLand", "HOOF": "Metaderby Hoof", "HOOK": "Hooked Protocol", "HOOP": "Chibi Dinos", + "HOOPS": "Hoops", + "HOOT": "HOOT", "HOP": "Hop Protocol", "HOPPY": "Hoppy", + "HOPPYTOKEN": "Hoppy", "HOPR": "HOPR", + "HOR": "HorizonDEX", "HORD": "Hord", "HORSE": "Ethorse", "HORUS": "HorusPay", @@ -5865,6 +6718,7 @@ "HRDG": "HRDGCOIN", "HRM": "Honorarium", "HRO": "HEROIC.com", + "HRSE": "The Winners Circle", "HRT": "HIRO", "HRTS": "YellowHeart Protocol", "HRX": "HorusLayer", @@ -5877,6 +6731,7 @@ "HST": "Decision Token", "HSUI": "Suicune", "HSUITE": "HbarSuite", + "HSUSDC": "Holdstation USDC", "HT": "Huobi Token", "HTA": "Historia", "HTB": "Hotbit", @@ -5885,6 +6740,7 @@ "HTDF": "Orient Walt", "HTE": "Hepton", "HTER": "Biogen", + "HTK": "Hard To Kill", "HTM": "Hatom", "HTML": "HTML Coin", "HTMOON": "HTMOON", @@ -5897,9 +6753,11 @@ "HUAHUA": "Chihuahua Chain", "HUB": "Hub Token", "HUBII": "Hubii Network", + "HUBSOL": "SolanaHub staked SOL", "HUC": "HunterCoin", "HUDI": "Hudi", - "HUGE": "BigCoin", + "HUE": "Huebel Bolt", + "HUGE": "HugeWin", "HUGO": "Hugo Inu", "HUH": "HUH Token", "HUHCAT": "huhcat", @@ -5912,6 +6770,7 @@ "HUNT": "HUNT", "HUR": "Hurify", "HUS": "HUSSY", + "HUSBY": "HUSBY", "HUSD": "HUSD", "HUSH": "Hush", "HUSKY": "Husky", @@ -5940,6 +6799,7 @@ "HYBRID": "Hybrid Bank Cash", "HYC": "HYCON", "HYCO": "HYPERCOMIC", + "HYD": "HYDRA", "HYDRA": "Hydra", "HYDRO": "Hydro", "HYDROMINER": "Hydrominer", @@ -5965,6 +6825,7 @@ "HZN": "Horizon Protocol", "HZT": "HazMatCoin", "I0C": "I0coin", + "I3D": "i3D Protocol", "I7": "ImpulseVen", "I9C": "i9 Coin", "IAG": "IAGON", @@ -5989,8 +6850,11 @@ "ICAP": "ICAP Token", "ICASH": "ICASH", "ICB": "IceBergCoin", + "ICBX": "ICB Network", "ICC": "Insta Cash Coin", "ICE": "Ice Open Network", + "ICEC": "IceCream", + "ICECR": "Ice Cream Sandwich", "ICELAND": "ICE LAND", "ICETH": "Interest Compounding ETH Index", "ICG": "Invest Club Global", @@ -5998,6 +6862,7 @@ "ICHI": "ICHI", "ICHN": "i-chain", "ICHX": "IceChain", + "ICL": "ICLighthouse DAO", "ICLICK": "Iclick inu", "ICN": "Iconomi", "ICNX": "Icon.X World", @@ -6046,9 +6911,11 @@ "IEC": "IvugeoEvolutionCoin", "IETH": "iEthereum", "IF": "Impossible Finance", + "IFBTC": "Ignition FBTC", "IFC": "Infinite Coin", "IFIT": "CALO INDOOR", "IFLT": "InflationCoin", + "IFOR": "iFortune", "IFT": "InvestFeed", "IFUM": "Infleum", "IFUND": "Unifund", @@ -6058,6 +6925,7 @@ "IGG": "IG Gold", "IGI": "Igi", "IGNIS": "Ignis", + "IGT": "Infinitar", "IGTT": "IGT", "IGU": "IguVerse", "IGUP": "IguVerse", @@ -6067,7 +6935,9 @@ "IIC": "Intelligent Investment Chain", "IJC": "IjasCoin", "IJZ": "iinjaz", + "IJZV1": "iinjaz v1", "IKI": "ikipay", + "IKIGAI": "Ikigai", "ILA": "Infinite Launch", "ILC": "ILCOIN", "ILCT": "ILCoin Token", @@ -6103,10 +6973,12 @@ "IMVR": "ImmVRse", "IMX": "Immutable X", "IN": "InCoin", + "INA": "pepeinatux", "INARI": "Inari", "INB": "Insight Chain", "INC": "Incrementum", "INCAKE": "InfinityCAKE", + "INCEPT": "Incept", "INCNT": "Incent", "INCORGNITO": "Incorgnito", "INCP": "InceptionCoin", @@ -6116,6 +6988,7 @@ "INDEX": "Index Cooperative", "INDI": "IndiGG", "INDIA": "Indiacoin", + "INDIAN": "Indian Call Center", "INDICOIN": "IndiCoin", "INDU": "INDU4.0", "INDY": "Indigo Protocol", @@ -6124,10 +6997,11 @@ "INERY": "Inery", "INES": "Inescoin", "INET": "Insure Network", + "INETH": "Inception Restaked ETH", "INEX": "Inex Project", "INF": "Infinium", "INFC": "Influence Chain", - "INFI": "Insured Finance", + "INFI": "Infinite", "INFINI": "Infinity Economics", "INFLR": "Inflr", "INFO": "Infomatix", @@ -6145,18 +7019,24 @@ "INOVAI": "INOVAI", "INP": "Ionic Pocket Token", "INRT": "INRToken", + "INRX": "INRx", + "INRXV1": "INRx v1", "INS": "Insolar (Old Chain)", "INSANE": "InsaneCoin", "INSANITY": "Insanity Coin", "INSC": "INSC (Ordinals)", + "INSE": "INSECT", "INSN": "Insane Coin", "INSP": "Inspect", + "INSPI": "InspireAI", "INSR": "Insurabler", "INST": "Instadapp", "INSTAMINE": "Instamine Nuggets", "INSTAR": "Insights Network", "INSUR": "InsurAce", + "INSURANCE": "insurance", "INSURC": "InsurChain Coin", + "INSUREDFIN": "Insured Finance", "INT": "Internet Node token", "INTD": "INTDESTCOIN", "INTE": "InteractWith", @@ -6179,6 +7059,7 @@ "INVESTEL": "Investelly token", "INVI": "INVI Token", "INVIC": "Invictus", + "INVITE": "INVITE Token", "INVOX": "Invox Finance", "INVX": "Investx", "INX": "Insight Protocol", @@ -6215,6 +7096,7 @@ "IPOR": "IPOR", "IPSX": "IP Exchange", "IPT": "Crypt-ON", + "IPU": "iPulse", "IPUX": "IPUX", "IPV": "IPVERSE", "IPVOLD": "IPVERSE (Klaytn)", @@ -6232,12 +7114,14 @@ "IRIS": "IRIS Network", "IRISTOKEN": "Iris Ecosystem", "IRL": "IrishCoin", + "IRO": "Iro-Chan", "IRON": "Iron Fish", "IRONBSC": "Iron BSC", "IRT": "Infinity Rocket", "IRYDE": "iRYDE COIN", "ISA": "Islander", "ISDT": "ISTARDUST", + "ISEC": "IntelliSecure Systems", "ISG": "ISG", "ISH": "Interstellar Holdings", "ISHI": "Ishi", @@ -6268,6 +7152,7 @@ "ITL": "Italian Lira", "ITLR": "MiTellor", "ITM": "intimate.io", + "ITO": "Ito-chan", "ITOC": "ITOChain", "ITR": "INTRO", "ITSB": "ITSBLOC", @@ -6282,6 +7167,7 @@ "IVAR": "Ivar Coin", "IVC": "Investy Coin", "IVEX": "IVEX Financial", + "IVFUN": "Invest Zone", "IVI": "IVIRSE", "IVIP": "iVipCoin", "IVN": "IVN Security", @@ -6293,6 +7179,7 @@ "IWT": "IwToken", "IX": "X-Block", "IXC": "IXcoin", + "IXIR": "IXIR", "IXP": "IMPACTXPRIME", "IXS": "IX Swap", "IXT": "iXledger", @@ -6313,17 +7200,23 @@ "JACY": "JACY", "JADE": "Jade Protocol", "JADEC": "Jade Currency", + "JAGO": "Jagotrack", "JAIHO": "Jaiho Crypto", "JAKE": "Jake The Dog", "JAM": "Tune.Fm", "JAN": "Storm Warfare", "JANE": "JaneCoin", + "JANET": "Janet", + "JANI": "JANI", "JAR": "Jarvis+", "JARED": "Jared From Subway", "JARY": "JeromeAndGary", "JASMY": "JasmyCoin", + "JASON": "Jason Derulo", + "JAV": "Javsphere", "JAWS": "AutoShark", "JAY": "Jaypeggers", + "JBO": "JBOX", "JBOT": "JACKBOT", "JBS": "JumBucks Coin", "JBX": "Juicebox", @@ -6334,13 +7227,16 @@ "JCO": "JennyCo", "JCR": "JustCarbon Removal", "JCT": "Japan Content Token", + "JDAI": "Dai (TON Bridge)", "JDC": "JustDatingSite", + "JDO": "JINDO", "JED": "JEDSTAR", "JEDALS": "Yoda Coin Swap", "JEET": "Jeet", "JEETOLAX": "Jeetolax", "JEFE": "JEFE TOKEN", "JEFF": "Jeff in Space", + "JEFFRY": "jeffry", "JEJUDOGE": "Jejudoge", "JELLI": "JELLI", "JELLY": "Jelly eSports", @@ -6351,8 +7247,10 @@ "JERRY": "Jerry Inu", "JERRYINU": "JERRYINU", "JES": "Jesus", + "JEST": "Jester", "JESUS": "Jesus Coin", "JET": "Jet Protocol", + "JETCAT": "Jetcat", "JETCOIN": "Jetcoin", "JETTON": "JetTon Game", "JEUR": "Jarvis Synthetic Euro", @@ -6365,11 +7263,13 @@ "JFIVE": "Jonny Five", "JGLP": "Jones GLP", "JGN": "Juggernaut", + "JHH": "Jen-Hsun Huang", "JIAOZI": "Jiaozi", "JIB": "Jibbit", "JIF": "JiffyCoin", "JIG": "Jigen", "JIM": "Jim", + "JIN": "JinPeng", "JIND": "JINDO INU", "JINDOGE": "Jindoge", "JIO": "JIO Token", @@ -6382,6 +7282,7 @@ "JKC": "JunkCoin", "JKL": "Jackal Protocol", "JLP": "Jupiter Perps LP", + "JLY": "Jellyverse", "JM": "JustMoney", "JMC": "Junson Ming Chan Coin", "JMPT": "JumpToken", @@ -6397,6 +7298,7 @@ "JOBS": "JobsCoin", "JOC": "Speed Star JOC", "JOE": "JOE", + "JOEB": "Joe Biden", "JOEBIDEN2024 ": "JOEBIDEN2024", "JOEY": "Joey Inu", "JOGECO": "Jogecodog", @@ -6407,13 +7309,20 @@ "JOK": "JokInTheBox", "JOKER": "JOKER", "JOKERCOIN": "JokerCoin", + "JOKERERC": "Joker", "JOL": "Jolofcoin", "JOLT": "Joltify", + "JOMA": "Joma", "JONES": "Jones DAO", + "JONESUSDC": "Jones USDC", "JOOPS": "JOOPS", + "JOPER": "Joker Pepe", + "JOSE": "Jose", "JOTCHUA": "Perro Dinero", + "JOULE": "Joule", "JOWNES": "Alux Jownes", "JOY": "Joystream", + "JOYCAT": "JoyCat Coin", "JOYS": "JOYS", "JOYT": "JoyToken", "JOYTOKEN": "Joycoin", @@ -6427,6 +7336,7 @@ "JRIT": "JERITEX", "JRT": "Jarvis Reward Token", "JSE": "JSEcoin", + "JSET": "Jsetcoin", "JSM": "Joseon Mun", "JSOL": "JPool Staked SOL", "JST": "JUST", @@ -6439,44 +7349,61 @@ "JUDGE": "JudgeCoin", "JUGNI": "JUGNI", "JUI": "Juiice", + "JUIC": "Juice", "JUICE": "Juice Finance", + "JUICEB": "Juice", "JUL": "Joule", "JULB": "JustLiquidity Binance", "JULD": "JulSwap", + "JUM": "Jumoney", "JUMBO": "Jumbo Exchange", "JUMP": "Jumpcoin", "JUN": "Jun \"M\" Coin", "JUNGLE": "JUNGLEDOGE", + "JUNGLEKING": "JungleKing TigerCoin", + "JUNIOR": "Junior", "JUNKIE": "Junkie Cats", "JUNO": "JUNO", "JUP": "Jupiter", "JUPI": "Jupiter", "JUPSOL": "Jupiter Staked SOL", "JUR": "Jur", + "JUS": "Just The Tip", "JUSD": "JUSD Stable Token", - "JUSDC": "Jones USDC", + "JUSDC": "USD Coin (TON Bridge)", "JUSDT": "TON Bridged USDT", + "JUST": "just a cat", + "JUSTI": "Justin MEME", "JUSTICE": "AssangeDAO", "JUV": "Juventus Fan Token", "JVL": "Javelin", + "JVT": "JVault", "JVY": "Javvy", "JW": "Jasan Wellness", + "JWBTC": "Wrapped Bitcoin (TON Bridge)", "JWIF": "Jerrywifhat", "JWL": "Jewels", "JYC": "Joe-Yo Coin", "K21": "K21", "K2G": "Kasko2go", + "KAAI": "KanzzAI", "KAAS": "KAASY.AI", + "KAB": "KABOSU", "KABOSU": "Kabosu Family", "KABY": "Kaby Arena", "KAC": "KACO Finance", "KACY": "Kassandra", + "KADYROV": "Ramzan", "KAF": "KAIF Platform", "KAG": "Silver", + "KAGE": "Kage Network", "KAI": "KardiaChain", + "KAIA": "Kaia", "KAID": "KAIDEX", "KAIJU": "KAIJUNO8", + "KAIK": "KAI KEN", "KAIKEN": "Kaiken Shiba", + "KAILY": "Kailith", "KAINET": "KAINET", "KAKA": "KAKA NFT World", "KAKAXA": "KAKAXA", @@ -6491,13 +7418,22 @@ "KALM": "KALM", "KALYCOIN": "KalyCoin", "KAM": "BitKAM", + "KAMA": "Kamala Horris", + "KAMAL": "Kamala Harris", + "KAMALA": "Kamala Harris", + "KAMALAHARRIS": "KAMALA HARRIS", + "KAMLA": "KAMALAMA (kamalama.org)", "KAMPAY": "KamPay", "KAN": "Bitkan", + "KANG": "Kangamoon", "KANG3N": "Kang3n", "KANGAL": "Kangal", + "KANGO": "KANGO", "KAP": "KAP Games", "KAPU": "Kapu", "KAR": "Karura", + "KARA": "KarateCat", + "KARAT": "KARAT Galaxy", "KARATE": "Karate Combat", "KAREN": "KarenCoin", "KARMA": "Karma", @@ -6505,6 +7441,10 @@ "KARRAT": "KARRAT", "KART": "Dragon Kart", "KAS": "Kaspa", + "KASBOT": "KASBOT THE GUARDIAN OF 𐤊ASPA", + "KASHIN": "KASHIN", + "KASPER": "Kasper the ghost of Kaspa", + "KASPY": "KASPY", "KASSIAHOME": "Kassia Home", "KASTA": "Kasta", "KAT": "Kambria", @@ -6533,6 +7473,7 @@ "KCAL": "Phantasma Energy", "KCASH": "Kcash", "KCAT": "KING OF CATS", + "KCATS": "KASPA CATS", "KCCM": "KCC MemePad", "KCCPAD": "KCCPad", "KCH": "Keep Calm and Hodl", @@ -6560,15 +7501,20 @@ "KELP": "KELP", "KELPE": "Kelp Earned Points", "KELPIE": "Kelpie Inu", + "KEM": "Kem Jeng Un", "KEMA": "Kemacoin", - "KEN": "Kencoin", + "KEN": "Ken", + "KENCOIN": "Kencoin", "KENDU": "Kendu Inu", "KENKA": "KENKA METAVERSE", "KENNEL": "Kennel Locker", + "KENOBI": "Obi PNut Kenobi", "KENSHI": "Kenshi", "KEP": "Kepler", "KEPT": "KeptChain", "KERMIT": "KermitTheCoin", + "KERN": "Kernel", + "KET": "KET", "KETAMINE": "Ketamine", "KETAN": "Ketan", "KEX": "Kira Network", @@ -6577,6 +7523,7 @@ "KEYC": "KeyCoin", "KEYCAT": "Keyboard Cat", "KEYFI": "KeyFi", + "KEYS": "KEYS", "KEYT": "REBIT", "KFC": "Chicken", "KFI": "Klever Finance", @@ -6588,6 +7535,7 @@ "KGO": "Kiwigo", "KGT": "Kaby Gaming Token", "KHAI": "khai", + "KHEOWZOO": "khaokheowzoo", "KHM": "Kohima", "KI": "Genopets KI", "KIAN": "Porta", @@ -6595,6 +7543,7 @@ "KIBSHI": "KiboShib", "KICK": "Kick", "KICKS": "GetKicks", + "KIDEN": "RoboKiden", "KIF": "KittenFinance", "KIKO": "KIKO", "KILLA": "The Bitcoin Killa", @@ -6607,15 +7556,20 @@ "KIN": "Kin", "KIND": "Kind Ads", "KINE": "Kine Protocol", + "KINET": "KinetixFi", "KING": "KING", "KING93": "King93", "KINGB": "King Bean", "KINGBONK": "King Bonk", "KINGCAT": "King Cat", + "KINGD": "Kingdom of Ants", "KINGDOG": "King Dog Inu", "KINGDOMQUEST": "Kingdom Quest", "KINGF": "King Finance", "KINGGROK": "King Grok", + "KINGNEIRO": "King Neiro", + "KINGO": "King of memes", + "KINGOF": "King Of Memes", "KINGPEPE": "KING PEPE", "KINGSHIB": "King Shiba", "KINGSLERF": "King Slerf", @@ -6626,6 +7580,7 @@ "KINGWIF": "King WIF", "KINGY": "KINGYTON", "KINIC": "Kinic", + "KINK": "Kinka", "KINT": "Kintsugi", "KINU": "Kragger Inu", "KIRA": "Kira the Injective Cat", @@ -6639,17 +7594,24 @@ "KISHU": "Kishu Inu", "KIT": "Kitsune", "KITA": "KITA INU", + "KITE": "Kite", + "KITEAI": "KITEAI", "KITSU": "Kitsune Inu", + "KITTE": "Kittekoin", "KITTENS": "Kitten Coin", "KITTENWIF": "KittenWifHat", "KITTI": "KITTI TOKEN", - "KITTY": "Kitty Inu", + "KITTY": "Roaring Kitt", + "KITTYINU": "Kitty Inu", + "KITTYINUV1": "Kitty Inu v1", + "KITTYS": "KITTY Sol", + "KITTYSOL": "Kitty Solana", "KIWI": "kiwi", "KIZUNA": "KIZUNA", "KKO": "Kineko", "KKT": "Kingdom Karnage", "KLAP": "Klap Finance", - "KLAY": "Klaytn", + "KLAUS": "Klaus", "KLC": "KiloCoin", "KLD": "Koduck", "KLEE": "KleeKai", @@ -6664,6 +7626,7 @@ "KLT": "Kamaleont", "KLUB": "KlubCoin", "KLV": "Klever", + "KLY": "Klayr", "KMA": "Calamari Network", "KMC": "Kitsumon", "KMD": "Komodo", @@ -6680,6 +7643,7 @@ "KNFT": "KStarNFT", "KNG": "BetKings", "KNGN": "KingN Coin", + "KNI": "Knights of Cathena", "KNIGHT": "Forest Knight", "KNINE": "K9 Finance", "KNJ": "Kunji Finance", @@ -6690,7 +7654,9 @@ "KNS": "Kenshi", "KNT": "Knekted", "KNTO": "Kento", + "KNU": "Keanu", "KNW": "Knowledge", + "KOAI": "KOI", "KOBE": "Shabu Shabu", "KOBO": "KoboCoin", "KODA": "Koda Cryptocurrency", @@ -6706,19 +7672,26 @@ "KOK": "KOK Coin", "KOKO": "KokoSwap", "KOL": "Kollect", + "KOLANA": "KOLANA", "KOLION": "Kolion", + "KOLT": "Kolt", "KOM": "Kommunitas", + "KOMA": "Koma Inu", "KOMO": "Komoverse", "KOMP": "Kompass", "KOMPETE": "KOMPETE", "KON": "KonPay", + "KONAN": "Konan of Kaspa", + "KONET": "KONET", "KONG": "KONG", "KONO": "Konomi Network", "KORA": "Kortana", + "KORC": "King of Referral Coin", "KORE": "KORE Vault", "KOREC": "Kore", "KORRA": "KORRA", "KOSS": "Koss", + "KOTARO": "KOTARO", "KOTO": "Koto", "KOY": "Koyo", "KOZ": "Kozjin", @@ -6726,13 +7699,19 @@ "KP4R": "Keep4r", "KPAD": "KickPad", "KPAPA": "KPAPA", + "KPAW": "KasPaw", "KPC": "KEEPs Coin", "KPHI": "Kephi Gallery", + "KPK": "ParkCoin", "KPL": "Kepple", "KPN": "KonnektVPN", "KPOP": "KPOP Coin", + "KPOPFUN": "KPOP (kpop.fun)", "KRAK": "Kraken", "KRATOS": "KRATOS", + "KRAV": "Krav", + "KRAZY": "krazy n.d.", + "KRAZYKAMALA": "KRAZY KAMALA", "KRB": "Karbo", "KRC": "KRCoin", "KRD": "Krypton DAO", @@ -6755,6 +7734,8 @@ "KRUGERCOIN": "KrugerCoin", "KRX": "RAVN Korrax", "KRY": "Krypdraw", + "KRYP": "Krypto Trump", + "KS": "kittyspin", "KS2": "Kingdomswap", "KSC": "KStarCoin", "KSH": "Kahsh", @@ -6774,6 +7755,7 @@ "KTN": "Kattana", "KTO": "Kounotori", "KTON": "Darwinia Commitment Token", + "KTR": "Kitty Run", "KTS": "Klimatas", "KTT": "K-Tune", "KTX": "KwikTrust", @@ -6788,6 +7770,7 @@ "KUMU": "Kumu Finance", "KUNAI": "KunaiKash", "KUNCI": "Kunci Coin", + "KUNDALINI": "Kundalini is a real girl", "KUR": "Kuro", "KURO": "Kurobi", "KURT": "Kurrent", @@ -6815,6 +7798,7 @@ "KYCC": "KYCCOIN", "KYL": "Kylin Network", "KYOKO": "Kyoko", + "KYRA": "KYRA", "KYTE": "Kambria Yield Tuning Engine", "KYUB": "Kyuubi", "KYVE": "KYVE Network", @@ -6823,13 +7807,16 @@ "L": "L inu", "L2": "Leverj Gluon", "L2DAO": "Layer2DAO", + "L3": "Layer3", "L3P": "Lepricon", "L3USD": "L3USD", "L7": "L7", "LA": "LATOKEN", "LAB": "Labrys", + "LABORCRYPTO": "LaborCrypto", "LABRA": "LabraCoin", "LABS": "LABS Group", + "LABUBU": "Labubu", "LABX": "Stakinglab", "LABZ": "Insane Labz", "LACCOIN": "LocalAgro", @@ -6840,6 +7827,7 @@ "LADYS": "Milady Meme Coin", "LAEEB": "LaEeb", "LAELAPS": "Laelaps", + "LAFFIN": "Laffin Kamala", "LAI": "LayerAI", "LAIKA": "Laika Protocol", "LAINESOL": "Laine Staked SOL", @@ -6852,20 +7840,25 @@ "LANC": "Lanceria", "LAND": "Landshare", "LANDB": "LandBox", + "LANDLORD": "LANDLORD RONALD", "LANDS": "Two Lands", "LANDV1": "Landshare v1", "LANDWOLF": "LANDWOLF", + "LANDWOLFETH": "Landwolf", "LANDWU": "LandWu", "LANE": "LaneAxis", "LAO": "LC Token", + "LAOS": "LAOS Network", "LAPI": "Lapis Inu", "LAPTOP": "Hunter Biden's Laptop", + "LAPUPU": "Lapupu", "LAR": "LinkArt", "LARIX": "Larix", "LARO": "Anito Legends", "LARR": "larrywifhat", "LARRY": "LarryCoin", "LAS": "LNAsolution Coin", + "LASOL": "LamaSol", "LAT": "PlatON Network", "LATOM": "Liquid ATOM", "LATTE": "LatteSwap", @@ -6877,10 +7870,13 @@ "LAVE": "Lavandos", "LAVITA": "Lavita AI", "LAW": "Law Token", + "LAWO": "Law Of Attraction", "LAX": "LAPO", + "LAY3R": "AutoLayer", "LAYER": "UniLayer", "LAZ": "Lazarus", "LAZIO": "Lazio Fan Token", + "LAZYCAT": "LAZYCAT", "LB": "LoveBit", "LBA": "Cred", "LBC": "LBRY Credits", @@ -6888,9 +7884,10 @@ "LBL": "LABEL Foundation", "LBLOCK": "Lucky Block", "LBM": "Libertum", - "LBR": "LaborCrypto", + "LBR": "Lybra Finance", + "LBRV1": "Lybra Finance v1", "LBT": "Law Blocks", - "LBTC": "LiteBitcoin", + "LBTC": "Lombard Staked BTC", "LBXC": "LUX BIO EXCHANGE COIN", "LC": "Lotus Capital", "LC4": "LEOcoin", @@ -6898,11 +7895,12 @@ "LCC": "LitecoinCash", "LCD": "Lucidao", "LCG": "LCG", + "LCI": "LOVECHAIN", "LCK": "Luckbox", "LCMG": "ElysiumG", "LCMS": "LCMS", "LCP": "Litecoin Plus", - "LCR": "Lucre", + "LCR": "Lucro", "LCRO": "Liquid CRO", "LCS": "LocalCoinSwap", "LCSN": "Lacostoken", @@ -6930,6 +7928,7 @@ "LEE": "Love Earn Enjoy", "LEET": "LeetSwap", "LEG": "Legia Warsaw Fan Token", + "LEGION": "LEGION", "LEGO": "Lego Coin", "LEIA": "Leia", "LELE": "Lelecoin", @@ -6938,6 +7937,7 @@ "LEMN": "LEMON", "LEMO": "LemoChain", "LEMON": "LemonCoin", + "LEMX": "LEMON", "LEN": "Liqnet", "LENARD": "Lenard", "LEND": "Aave", @@ -6945,17 +7945,22 @@ "LENDS": "Lends", "LENFI": "Lenfi", "LENIN": "LeninCoin", + "LENS": "Len Sassaman (len-sassaman.vip)", "LEO": "LEO Token", + "LEOCOIN": "LEO", "LEOPARD": "Leopard", "LEOS": "Leonicorn Swap", "LEOX": "Galileo", "LEPA": "Lepasa", "LEPEN": "LePenCoin", + "LEPER": "Leper", "LESBIAN": "Lesbian Inu", "LESS": "Less Network", "LESSF": "LessFnGas", + "LESTER": "Litecoin Mascot", "LET": "LinkEye", "LETIT": "Letit", + "LETS": "Let's WIN This", "LETSGO": "Lets Go Brandon", "LEU": "CryptoLEU", "LEV": "Levante U.D. Fan Token", @@ -6974,6 +7979,7 @@ "LFG": "Gamerse", "LFGO": "Lets Fuckin Go", "LFI": "LunaFi", + "LFIT": "LFIT", "LFNTY": "Lifinity", "LFT": "Lend Flare Dao", "LFW": "Linked Finance World", @@ -6982,6 +7988,7 @@ "LGC": "LiveGreen Coin", "LGCY": "LGCY Network", "LGD": "Legends Cryptocurrency", + "LGNDX": "LegendX", "LGO": "Legolas Exchange", "LGOLD": "LYFE GOLD", "LGOT": "LGO Token", @@ -7002,14 +8009,17 @@ "LIBRE": "Libre", "LIC": "Ligercoin", "LICK": "PetLFG", + "LICKER": "LICKER", "LICO": "Liquid Collectibles", "LID": "Liquidity Dividends Protocol", "LIDER": "Lider Token", + "LIE": "it’s all a lie", "LIEN": "Lien", "LIF": "Winding Tree", "LIF3": "LIF3", "LIFE": "Life Crypto", "LIFEBIRD": "LIFEBIRD", + "LIFET": "LifeTime", "LIFETOKEN": "LIFE", "LIFT": "Uplift", "LIGER": "Ligercoin", @@ -7019,10 +8029,13 @@ "LIKE": "Only1", "LIKEC": "LikeCoin", "LILA": "LiquidLayer", + "LILB": "Lil Brett", "LILFLOKI": "Lil Floki", "LILPUMP": "lilpump", + "LILY": "LILY-The Gold Digger", "LIME": "iMe Lab", "LIMEX": "Limestone Network", + "LIMITEDCOIN": "Limited Coin", "LIMO": "Limoverse", "LIMX": "LimeCoinX", "LINA": "Linear", @@ -7039,6 +8052,7 @@ "LINSPIRIT": "linSpirit", "LINU": "Luna Inu", "LINX": "Linx", + "LIO": "Lio", "LION": "Lion Token", "LIPC": "LIpcoin", "LIPS": "LipChain", @@ -7046,13 +8060,16 @@ "LIQD": "Liquid Finance", "LIQR": "Topshelf Finance", "LIQUI": "Liquidus", + "LIQUIDIUM": "LIQUIDIUM•TOKEN", "LIR": "Let it Ride", "LIS": "Realis Network", "LISA": "Lisa Simpson", "LIST": "KList Protocol", "LISTA": "Lista DAO", + "LISUSD": "lisUSD", "LIT": "Litentry", "LITE": "Lite USD", + "LITEBTC": "LiteBitcoin", "LITENETT": "Litenett", "LITH": "Lithium Finance", "LITHIUM": "Lithium", @@ -7061,6 +8078,7 @@ "LITT": "LitLab Games", "LIV": "LiviaCoin", "LIVE": "TRONbetLive", + "LIVESEY": "Dr. Livesey", "LIVESTARS": "Live Stars", "LIXX": "Libra Incentix", "LIZ": "Lizus Payment", @@ -7088,6 +8106,8 @@ "LMCH": "Latamcash", "LMCSWAP": "LimoCoin SWAP", "LMEOW": "lmeow", + "LMF": "Lamas Finance", + "LMQ": "Lightning McQueen", "LMR": "Lumerin", "LMT": "Lympo Market Token", "LMTOKEN": "LM Token", @@ -7109,6 +8129,7 @@ "LNX": "Lunox Token", "LOA": "League of Ancients", "LOAF": "LOAF CAT", + "LOAFCAT": "LOAFCAT", "LOAN": "Lendoit", "LOBO": "LOBO•THE•WOLF•PUP", "LOBS": "Lobstex", @@ -7118,6 +8139,7 @@ "LOCG": "LOCGame", "LOCI": "LociCoin", "LOCK": "Contracto", + "LOCKIN": "LOCK IN", "LOCO": "Loco", "LOCOM": "Locomotir", "LOCUS": "Locus Chain", @@ -7127,15 +8149,20 @@ "LOFI": "LOFI", "LOG": "Wood Coin", "LOGO": "LOGOS", + "LOGX": "LogX Network", "LOIS": "Lois Token", "LOKA": "League of Kingdoms", "LOKR": "Polkalokr", "LOL": "EMOGI Network", "LOLA": "Lola", + "LOLATHECAT": "Lola", "LOLC": "LOL Coin", + "LOLLY": "Lollipop", + "LOLO": "Lolo", "LON": "Tokenlon", "LONG": "Longdrink Finance", "LONGFU": "LONGFU", + "LONGM": "Long Mao", "LONGSHINE": "LongShine", "LOOK": "LookCoin", "LOOKS": "LooksRare", @@ -7144,6 +8171,7 @@ "LOON": "Loon Network", "LOONG": "PlumpyDragons", "LOOP": "LOOP", + "LOOPIN": "LooPIN Network", "LOOPY": "Loopy", "LOOT": "LootBot", "LOOTEX": "Lootex", @@ -7163,6 +8191,7 @@ "LOTTY": "Lotty", "LOTUS": "The White Lotus", "LOUD": "Loud Market", + "LOULOU": "LOULOU", "LOV": "LoveChain", "LOVE": "Deesse", "LOVELY": "Lovely finance", @@ -7177,6 +8206,7 @@ "LPI": "LPI DAO", "LPK": "Kripton", "LPL": "LinkPool", + "LPM": "Love Power Market", "LPNT": "Luxurious Pro Network Token", "LPOOL": "Launchpool", "LPT": "Livepeer", @@ -7190,10 +8220,14 @@ "LQDR": "LiquidDriver", "LQDX": "Liquid Crypto", "LQR": "Laqira Protocol", + "LQT": "Lifty", "LQTY": "Liquity", "LRC": "Loopring", + "LRDS": "BLOCKLORDS", "LRG": "Largo Coin", "LRN": "Loopring [NEO]", + "LRT": "LandRocker", + "LRT2": "LRT Squared", "LSC": "LS Coin", "LSD": "LightSpeedCoin", "LSDOGE": "LSDoge", @@ -7224,7 +8258,7 @@ "LTCR": "LiteCreed", "LTCU": "LiteCoin Ultra", "LTCX": "LitecoinX", - "LTD": "Limited Coin", + "LTD": "Living the Dream", "LTE": "Local Token Exchange", "LTEX": "Ltradex", "LTG": "LiteCoin Gold", @@ -7238,6 +8272,7 @@ "LTPC": "Lightpaycoin", "LTR": "LogiTron", "LTRBT": "Little Rabbit", + "LTRBTV1": "Little Rabbit v1", "LTS": "Litestar Coin", "LTT": "LocalTrade", "LTX": "Lattice Token", @@ -7247,12 +8282,15 @@ "LUBE": "Joe Lube Coin", "LUC": "Play 2 Live", "LUCA": "LUCA", + "LUCE": "Luce", "LUCHOW": "LunaChow", + "LUCI": "LUCI", "LUCK": "Lucky Cat", "LUCKY": "Lucky Lion", "LUCKYB": "LuckyBlocks", "LUCKYS": "LuckyStar", "LUCKYSLP": "LuckysLeprecoin", + "LUCRE": "Lucre", "LUCY": "Lucy", "LUDO": "Ludo", "LUFC": "Leeds United Fan Token", @@ -7265,9 +8303,14 @@ "LUM": "Illuminates", "LUMA": "LUMA Token", "LUMI": "LUMI Credits", + "LUMIA": "Lumia", + "LUMIO": "Solana Mascot", + "LUMOS": "Lumos", "LUN": "Lunyr", "LUNA": "Terra", + "LUNAB": "Luna by Virtuals", "LUNAR": "Lunar", + "LUNARLENS": "Lunarlens", "LUNAT": "Lunatics", "LUNC": "Terra Classic", "LUNCARMY": "LUNCARMY", @@ -7299,8 +8342,10 @@ "LXF": "LuxFi", "LXT": "LITEX", "LXTO": "LuxTTO", + "LYA": "Huralya", "LYB": "LyraBar", "LYC": "LycanCoin", + "LYDI": "Lydia Finance", "LYF": "Lillian Token", "LYFE": "Lyfe", "LYK": "Loyakk Vega", @@ -7321,6 +8366,7 @@ "LYZI": "Lyzi", "LZ": "LaunchZone", "LZM": "LoungeM", + "LZUSDC": "LayerZero Bridged USDC (Fantom)", "M": "MetaVerse-M", "M1": "SupplyShock", "M2O": "M2O Token", @@ -7330,22 +8376,30 @@ "MAC": "MachineCoin", "MACHO": "macho", "MADA": "MilkADA", + "MADAGASCARTOKEN": "Madagascar Token", "MADANA": "MADANA", "MADC": "MadCoin", + "MADH": "Madhouse", "MADOG": "MarvelDoge", + "MADP": "Mad Penguin", "MADPEPE": "Mad Pepe", "MAEP": "Maester Protocol", "MAF": "MetaMAFIA", - "MAG": "Magnet", + "MAG": "Magnify Cash", "MAGA": "MAGA Hat", "MAGA2024": "MAGA2024", "MAGAA": "MAGA AGAIN", + "MAGAC": "MAGA CAT", + "MAGACA": "MAGA CAT", "MAGACAT": "MAGACAT", "MAGADOGE": "MAGA DOGE", "MAGAIBA": "Magaiba", + "MAGAN": "Maganomics On Solana", "MAGANOMICS": "Maganomics", + "MAGAP": "MAGA PEPE", "MAGAPEPE": "MAGA PEPE", "MAGASHIB": "MAGA SHIB", + "MAGASOL": "MAGA", "MAGATRUMP": "MAGA Trump", "MAGE": "MetaBrands", "MAGIC": "Magic", @@ -7353,7 +8407,13 @@ "MAGICK": "Cosmic Universe Magick", "MAGICV": "Magicverse", "MAGIK": "Magik Finance", + "MAGN": "Magnate Finance", "MAGNET": "Yield Magnet", + "MAGNET6900": "MAGNET6900", + "MAGNETWORK": "Magnet", + "MAGOA": "Make America Great Once Again", + "MAGPAC": "MAGA Meme PAC", + "MAH": "Mahabibi Bin Solman", "MAHA": "MahaDAO", "MAI": "Mindsync", "MAIA": "Maia", @@ -7361,7 +8421,11 @@ "MAIL": "CHAINMAIL", "MAINSTON": "Ston", "MAJO": "Majo", + "MAJOR": "Major Frog", + "MAK": "MetaCene", "MAKE": "MAKE", + "MAKEA": "Make America Healthy Again", + "MAKEE": "Make Ethereum Great Again", "MAKI": "MakiSwap", "MALGO": "milkALGO", "MALL": "Metamall", @@ -7371,12 +8435,14 @@ "MAN": "Matrix AI Network", "MANA": "Decentraland", "MANC": "Mancium", + "MAND": "Mandala Exchange Token", "MANDALA": "Mandala Exchange Token", "MANDOX": "MandoX", "MANE": "MANE", "MANEKI": "MANEKI", "MANGA": "Manga Token", "MANIA": "ScapesMania", + "MANIFEST": "Manifest", "MANNA": "Manna", "MANORUKA": "ManoRuka", "MANT": "Mantle USD", @@ -7384,6 +8450,7 @@ "MANTLE": "Mantle", "MANYU": "Little Manyu", "MAO": "Mao", + "MAOW": "MAOW", "MAP": "MAP Protocol", "MAPC": "MapCoin", "MAPE": "Mecha Morphing", @@ -7391,6 +8458,7 @@ "MAPS": "MAPS", "MAR3": "Mar3 AI", "MARCO": "MELEGA", + "MARCUS": "Marcus Cesar Inu", "MARE": "Mare Finance", "MARGA": "Margaritis", "MARGINLESS": "Marginless", @@ -7406,6 +8474,7 @@ "MARS4": "MARS4", "MARSC": "MarsCoin", "MARSH": "Unmarshal", + "MARSO": "Marso.Tech", "MARSRISE": "MarsRise", "MARSUPILAMI": "MARSUPILAMI INU", "MARSW": "Marswap", @@ -7430,6 +8499,7 @@ "MASTER": "Mastercoin", "MASTERCOIN": "MasterCoin", "MASTERMINT": "MasterMint", + "MASTERTRADER": "MasterTraderCoin", "MASYA": "MASYA", "MAT": "MiniApps", "MATA": "Ninneko", @@ -7441,18 +8511,26 @@ "MATICX": "Stader MaticX", "MATPAD": "MaticPad", "MATRIX": "Matrix Labs", + "MATT": "Matt Furie", + "MATTER": "AntiMatter", "MAU": "MAU", "MAUW": "MAUW", "MAV": "Maverick Protocol", + "MAVAX": "Avalanche (Multichain)", "MAVIA": "Heroes of Mavia", "MAW": "Mountain Sea World", - "MAX": "MaxCoin", + "MAWA": "Kumala Herris", + "MAWC": "Magawincat", + "MAX": "Matr1x", + "MAXCOIN": "MaxCoin", + "MAXETH": "Max on ETH", "MAXI": "Maximus", "MAXL": "Maxi protocol", "MAXR": "Max Revive", "MAXX": "MAXX Finance", "MAY": "Theresa May Coin", "MAYACOIN": "MayaCoin", + "MAYO": "Mr Mayonnaise the Cat", "MAYP": "Maya Preferred", "MAZC": "MyMazzu", "MAZI": "MaziMatic", @@ -7460,6 +8538,8 @@ "MB": "MineBee", "MB4": "Matthew Box 404", "MB8": "MB8 Coin", + "MBAG": "MoonBag", + "MBANK": "MetaBank", "MBAPEPE": "MBAPEPE", "MBASE": "Minebase", "MBC": "MicroBitcoin", @@ -7470,12 +8550,16 @@ "MBET": "MoonBet", "MBF": "MoonBear.Finance", "MBI": "Monster Byte Inc", + "MBID": "myBID", + "MBILLY": "MAMA BILLY", "MBIT": "Mbitbooks", "MBL": "MovieBloc", "MBLC": "Mont Blanc", "MBLK": "Magical Blocks", + "MBLV1": "MovieBloc v1", "MBM": "MobileBridge Momentum", "MBN": "Mobilian Coin", + "MBNB": "Binance Coin (Multichain)", "MBONK": "megaBonk", "MBOT": "MoonBot", "MBOX": "MOBOX", @@ -7487,7 +8571,9 @@ "MBTX": "MinedBlock", "MBX": "Marblex", "MC": "Merit Circle", + "MCA": "Mcashchain", "MCADE": "Metacade", + "MCAKE": "EasyCake", "MCAP": "MCAP", "MCAR": "MasterCar", "MCASH": "Monsoon Finance", @@ -7496,7 +8582,10 @@ "MCB": "MCDEX", "MCC": "Magic Cube Coin", "MCD": "CDbio", + "MCDAI": "Dai (Multichain)", + "MCDULL": "McDull", "MCELO": "Moola Celo", + "MCEN": "Main Character Energy", "MCEUR": "Moola Celo EUR", "MCF": "MCFinance", "MCG": "MicroChains Gov Token", @@ -7509,6 +8598,7 @@ "MCN": "mCoin", "MCO": "Crypto.com", "MCO2": "Moss Carbon Credit", + "MCOI": "MCOIN", "MCOIN": "MCOIN", "MCONTENT": "MContent", "MCP": "My Crypto Play", @@ -7518,10 +8608,12 @@ "MCRT": "MagicCraft", "MCS": "MCS Token", "MCT": "MyConstant", + "MCTO": "McToken", "MCTP": "Metacraft", "MCU": "MediChain", "MCUSD": "Moola Celo USD", "MCV": "MCV Token", + "MD": "MetaDeck", "MDA": "Moeda", "MDAI": "MindAI", "MDAO": "MarsDAO", @@ -7535,6 +8627,7 @@ "MDICE": "Multidice", "MDM": "Medium", "MDN": "Modicoin", + "MDOGE": "First Dog In Mars", "MDR": "Mudra MDR", "MDS": "MediShares", "MDT": "Measurable Data Token", @@ -7557,6 +8650,7 @@ "MEDIC": "MedicCoin", "MEDICO": "Mediconnect", "MEDIT": "MediterraneanCoin", + "MEDUSA": "MEDUSA", "MEE": "Medieval Empires", "MEED": "Meeds DAO", "MEER": "Qitmeer Network", @@ -7566,17 +8660,22 @@ "MEFA": "Metaverse Face", "MEGA": "MegaFlash", "MEGABOT": "Megabot", + "MEGAD": "Mega Dice Casino", "MEGAHERO": "MEGAHERO", "MEGALAND": "Metagalaxy Land", "MEGALANDV1": "Metagalaxy Land v1", + "MEGAX": "Megahex", "MEGE": "MEGE", "MEH": "meh", + "MEI": "Mei Solutions", + "MEIZHU": "GUANGZHOU ZOO NEW BABY PANDA", "MEL": "MELX", "MELANIA": "Melania Trump", "MELB": "Minelab", "MELD": "MELD", "MELI": "Meli Games", "MELLO": "Mello Token", + "MELLOW": "Mellow Man", "MELLSTROY": "MELLSTROY", "MELO": "Melo Token", "MELODITY": "Melodity", @@ -7592,18 +8691,24 @@ "MEMEETF": "Meme ETF", "MEMEFI": "MemeFi", "MEMEINU": "Meme Inu", + "MEMEM": "Meme Man", "MEMEME": "MEMEME", "MEMEMINT": "MEME MINT", "MEMEMUSK": "MEME MUSK", "MEMERUNE": "MEME•ECONOMICS", "MEMES": "MemeCoinDAO", + "MEMESAI": "Memes AI", + "MEMESQUAD": "Meme Squad", "MEMET": "MEMETOON", "MEMETIC": "Memetic", "MEMORYCOIN": "MemoryCoin", + "MEN": "METAHUB FINANCE", "MENDI": "Mendi Finance", "MENGO": "Flamengo Fan Token", "MENLO": "Menlo One", + "MEO": "Meow Of Meme", "MEOW": "Zero Tech", + "MEOWETH": "Meow", "MEOWG": "MeowGangs", "MEOWIF": "Meowifhat", "MEOWM": "Meow Meow Coin", @@ -7619,6 +8724,7 @@ "MERIDIAN": "Meridian Network LOCK", "MERKLE": "Merkle Network", "MERL": "Merlin Chain", + "MERLIN": "Oldest Raccoon", "MERY": "Mistery On Cro", "MESA": "MetaVisa", "MESG": "MESG", @@ -7626,11 +8732,16 @@ "MESSI": "MESSI COIN", "MESSU": "Loinel Messu", "MET": "Metronome", - "META": "Metadium", + "META": "MetaDAO", + "METAA": "META ARENA", "METABOT": "Robot Warriors", "METAC": "Metacoin", + "METACA": "MetaCash", "METACAT": "MetaCat", + "METACLOUD": "Metacloud", "METACR": "Metacraft", + "METAD": "MetaDoge", + "METADIUM": "Metadium", "METADOGE": "MetaDoge", "METADOGEV2": "MetaDoge V2", "METAF": "MetaFastest", @@ -7646,13 +8757,15 @@ "METAQ": "MetaQ", "METAS": "Metaseer", "METAT": "MetaTrace", + "METATI": "Metatime Coin", + "METATR": "MetaTrace Utility Token", "METAUFO": "MetaUFO", "METAV": "MetaVPad", + "METAVE": "Metaverse Convergence", "METAVIE": "Metavie", "METAW": "MetaWorth", "METAX": "MetaverseX", "METEOR": "Meteorite Network", - "METER": "Meter Stable", "METFI": "MetFi", "METH": "Mantle Staked Ether", "METI": "Metis", @@ -7663,6 +8776,7 @@ "METRO": "Metropoly", "MEU": "MetaUnit", "MEV": "MEVerse", + "MEVETH": "mevETH", "MEVR": "Metaverse VR", "MEW": "cat in a dogs world", "MEWC": "Meowcoin", @@ -7686,10 +8800,12 @@ "MFPS": "Meta FPS", "MFS": "Moonbase File System", "MFT": "Hifi Finance (Old)", + "MFTM": "Fantom (Multichain)", "MFTU": "Mainstream For The Underground", "MFUND": "Memefund", "MFX": "MFChain", "MG": "MinerGate Token", + "MG8": "Megalink", "MGAMES": "Meme Games", "MGAR": "Metagame Arena", "MGC": "Meta Games Coin", @@ -7721,8 +8837,10 @@ "MIC": "Mithril Cash", "MICE": "Mice", "MICHI": "michi", + "MICK": "Mickey Meme", "MICKEY": "Steamboat Willie", "MICRO": "Micromines", + "MICRODOGE": "MicroDoge", "MIDAI": "Midway AI", "MIDAS": "Midas", "MIDASDOLLAR": "Midas Dollar Share", @@ -7730,15 +8848,21 @@ "MIE": "MIE Network", "MIF": "monkeywifhat", "MIG": "Migranet", + "MIGGLEI": "Migglei", + "MIGGLES": "Mr Miggles", "MIGMIG": "MigMig Swap", + "MIHARU": "Smiling Dolphin", "MIIDAS": "Miidas NFT", "MIININGNFT": "MiningNFT", + "MIKE": "Mike", "MIKS": "MIKS COIN", "MIL": "Milllionaire Coin", + "MILA": "MILADY MEME TOKEN", "MILE": "milestoneBased", "MILEI": "MILEI", "MILK": "Milkshake Swap", "MILK2": "Spaceswap MILK2", + "MILKBAG": "MILKBAG", "MILKYWAY": "MilkyWayZone", "MILLI": "Million", "MILLY": "milly", @@ -7746,6 +8870,7 @@ "MILOCEO": "Milo CEO", "MILOCOIN": "MiloCoin", "MILODOG": "MILO DOG", + "MILOP": "MILO Project", "MIM": "Magic Internet Money", "MIMATIC": "MAI", "MIMI": "MIMI Money", @@ -7755,28 +8880,38 @@ "MINA": "Mina Protocol", "MINC": "MinCoin", "MIND": "Morpheus Labs", + "MINDC": "MindCoin", "MINDCOIN": "MindCoin", "MINDEX": "Mindexcoin", "MINDGENE": "Mind Gene", "MINDS": "Minds", "MINE": "SpaceMine", + "MINEA": "Mine AI", "MINER": "MINER", "MINERALS": "Minerals Coin", "MINES": "MINESHIELD", "MINETTE": "Vibe Cat", "MINEX": "Minex", - "MINI": "Mini", + "MINGO": "Mingo", + "MINI": "mini", "MINIBNBTIGER": "MiniBNBTiger", + "MINID": "Mini Donald", "MINIDOGE": "MiniDOGE", "MINIFOOTBALL": "Minifootball", "MINIMYRO": "Mini Myro", + "MININEIRO": "Mini Neiro", + "MININGWATCHDOG": "Miningwatchdog Smartchain", "MINION": "Minions INU", + "MINIP": "MiniPepe Coin", "MINIPEPE": "MiniPepe", + "MINIS": "Mini", "MINISHIB": "miniSHIB ETH", "MINO": "MINO INU", + "MINOCOINCTO": "MINO", "MINS": "Minswap", "MINT": "Mint Club", "MINTCOIN": "MintCoin", + "MINTE": "Minter HUB", "MINTME": "MintMe.com Coin", "MINTYS": "MintySwap", "MINU": "Minu", @@ -7788,13 +8923,17 @@ "MIR": "Mirror Protocol", "MIRA": "Chains of War", "MIRACLE": "MIRACLE", + "MIRAI": "MIRAI", "MIRC": "MIR COIN", + "MIRT": "MIR Token", "MIS": "Mithril Share", "MISA": "Sangkara", "MISCOIN": "MIScoin", + "MISHA": "Vitalik's Dog", "MISHKA": "Mishka Token", "MISS": "MISS", "MIST": "Mist", + "MISTE": "Mister Miggles", "MISTRAL": "Mistral AI", "MIT": "Galaxy Blitz", "MITC": "MusicLife", @@ -7802,6 +8941,7 @@ "MITHRIL": "CLIMBERS", "MITTENS": "Mittens", "MITX": "Morpheus Infrastructure Token", + "MIU": "Miu", "MIV": "MakeItViral", "MIVA": "Minerva Wallet", "MIVRS": "Minionverse", @@ -7810,26 +8950,32 @@ "MIXCOIN": "Mixaverse", "MIXER": "TON Mixer", "MIY": "Icel Idman Yurdu Token", + "MIZ": "Mizar", "MJT": "MojitoSwap", "MK": "Meme Kombat", "MKC": "Meta Kongz", "MKEY": "MEDIKEY", + "MKL": "Merkle Trade", "MKONG": "MEME KONG", "MKR": "Maker", "MKT": "MikeToken", "MKUSD": "Prisma mkUSD", "ML": "Mintlayer", "MLA": "Moola", + "MLC": "My Lovely Planet", "MLD": "MonoLend", + "MLEO": "LEO Token (Multichain)", "MLGC": "Marshal Lion Group Coin", + "MLINK": "Chainlink (Multichain)", "MLITE": "MeLite", "MLK": "MiL.k", "MLN": "Enzyme", "MLNK": "Malinka", "MLOKY": "MLOKY", + "MLP": "Matrix Layer Protocol", "MLS": "CPROP", "MLT": "MIcro Licensing Coin", - "MLTC": "MultiWallet Coin", + "MLTC": "Litecoin (Multichain)", "MLTPX": "MoonLift Capital", "MLXC": "Marvellex Classic", "MM": "Millimeter", @@ -7837,6 +8983,7 @@ "MMAI": "MetamonkeyAi", "MMAON": "MMAON", "MMAPS": "MapMetrics", + "MMATIC": "Wrapped Polygon (Multichain)", "MMC": "Monopoly Millionaire Control", "MMETA": "Duckie Land Multi Metaverse", "MMF": "MMFinance", @@ -7852,6 +8999,7 @@ "MMT": "Master MIX Token", "MMTM": "Momentum", "MMUI": "MetaMUI", + "MMULTI": "Multichain (via Multichain Cross-Chain Router)", "MMVG": "MEMEVENGERS", "MMX": "MMX", "MMXIV": "MaieutiCoin", @@ -7859,11 +9007,13 @@ "MMY": "Mummy Finance", "MN": "Cryptsy Mining Contract", "MNB": "MoneyBag", + "MNBR": "MN Bridge", "MNC": "MainCoin", "MND": "Mound Token", "MNDCC": "Mondo Community Coin", "MNDE": "Marinade", "MNE": "Minereum", + "MNEE": "MNEE USD Stablecoin ", "MNET": "MINE Network", "MNFT": "Mongol NFT", "MNFTS": "Marvelous NFTs", @@ -7891,6 +9041,7 @@ "MNZ": "Menzy", "MO": "Morality", "MOAC": "MOAC", + "MOAI": "MOAI", "MOAR": "Moar Finance", "MOAT": "Mother Of All Tokens", "MOB": "MobileCoin", @@ -7898,12 +9049,17 @@ "MOBIC": "Mobility Coin", "MOBIE": "MobieCoin", "MOBILE": "Helium Mobile", + "MOBIU": "Mobius Money", "MOBU": "MOBU", "MOBX": "MOBIX", "MOBY": "Moby", + "MOBYONBASE": "Moby", + "MOBYONBASEV1": "Moby v1", "MOC": "Mossland", + "MOCA": "Moca Coin", "MOCHI": "Mochiswap", "MOCHICAT": "MochiCat", + "MOCK": "Mock Capital", "MOCO": "MoCo", "MOD": "Modefi", "MODA": "MODA DAO", @@ -7922,18 +9078,25 @@ "MOFI": "MobiFi", "MOFOLD": "Molecular Future (ERC20)", "MOG": "Mog Coin", + "MOGC": "MOG CAT", + "MOGCO": "Mog Coin (mogcoinspl.com)", "MOGE": "Moge", "MOGGO": "MOGGO", + "MOGP": "MOG PEPE", + "MOGT": "MOG TRUMP", "MOGU": "Mogu", "MOGUL": "Mogul Productions", + "MOGUT": "Mogutou", "MOGX": "Mogu", "MOH": "Medal of Honour", "MOI": "MyOwnItem", "MOIN": "MoinCoin", + "MOJI": "Moji", "MOJO": "Mojocoin", "MOK": "MocktailSwap", "MOL": "Molecule", "MOLA": "MoonLana", + "MOLI": "Mobile Liquidity", "MOLK": "Mobilink Token", "MOLLARS": "MollarsToken", "MOLLY": "Molly", @@ -7947,6 +9110,7 @@ "MONARCH": "TRUEMONARCH", "MONAV": "Monavale", "MONB": "MonbaseCoin", + "MONDO": "mondo", "MONETA": "Moneta", "MONEY": "MoneyCoin", "MONEYBEE": "MONEYBEE", @@ -7957,6 +9121,7 @@ "MONG20": "Mongoose 2.0", "MONGBNB": "MongBNB", "MONGOOSE": "Mongoose", + "MONGY": "Mongy", "MONI": "Monsta Infinite", "MONIE": "Infiblue World", "MONK": "Monkey Project", @@ -7966,25 +9131,37 @@ "MONKEYS": "Monkeys Token", "MONKU": "Monku", "MONO": "MonoX", + "MONOLITH": "Monolith", "MONONOKEINU": "Mononoke Inu", + "MONOPOLY": "Meta Monopoly", "MONS": "Monsters Clan", "MONST": "Monstock", "MONSTA": "Cake Monster", + "MONSTE": "Monster", "MONT": "Monarch Token", "MONTE": "Monte", "MOO": "MooMonster", + "MOOBIFI": "Staked BIFI", "MOOCAT": "MooCat", + "MOODENG": "Moo Deng (moodengsol.com)", + "MOODENGSPACE": "MOO DENG", + "MOODENGWIF": "MOODENGWIF", "MOOI": "Moonai", "MOOLA": "Degen Forest", "MOOLYA": "moolyacoin", "MOON": "r/CryptoCurrency Moons", "MOONARCH": "Moonarch", + "MOONB": "Moon Base", + "MOONBI": "Moonbix", + "MOONBIX": "MOONBIX MEME", "MOONC": "MoonCoin", "MOOND": "Dark Moon", "MOONDAY": "Moonday Finance", + "MOONDO": "MOON DOGE", "MOONED": "MoonEdge", "MOONER": "CoinMooner", "MOONEY": "Moon DAO", + "MOONI": "MOON INU", "MOONION": "Moonions", "MOONKIZE": "MoonKize", "MOONLIGHT": "Moonlight Token", @@ -7992,6 +9169,7 @@ "MOONS": "Sailor Moons", "MOONSHOT": "Moonshot", "MOONSTAR": "MoonStar", + "MOONW": "moonwolf.io", "MOOO": "Hashtagger", "MOOV": "dotmoovs", "MOOX": "Moox Protocol", @@ -7999,9 +9177,11 @@ "MOR": "Morpheus", "MORA": "Meliora", "MORE": "More Coin", + "MOREGEN": "MoreGen FreeMoon", "MORFEY": "Morfey", "MOROS": "MOROS NET", "MORPH": "Morpheus Token", + "MORPHO": "Morpho", "MORRA": "Morra", "MORSE": "Morse", "MOS": "MOS Coin", @@ -8009,6 +9189,7 @@ "MOT": "Olympus Labs", "MOTA": "MotaCoin", "MOTG": "MetaOctagon", + "MOTH": "MOTH", "MOTHER": "Mother Iggy", "MOTI": "Motion", "MOTO": "Motocoin", @@ -8017,15 +9198,19 @@ "MOVD": "MOVE Network", "MOVE": "MarketMove", "MOVER": "Mover", + "MOVEUSD": "MoveMoney USD", "MOVEY": "Movey", "MOVEZ": "MoveZ", "MOVON": "MovingOn Finance", "MOVR": "Moonriver", "MOW": "mouse in a cats world", "MOWA": "Moniwar", + "MOXIE": "Moxie", + "MOYA": "MOYA", "MOZ": "Mozik", "MP": "Membership Placeholders", "MP3": "MP3", + "MPAA": "MPAA", "MPAD": "MultiPad", "MPAY": "Menapay", "MPC": "Metaplace", @@ -8056,12 +9241,14 @@ "MRHB": "MarhabaDeFi", "MRI": "Marshall Inu", "MRK": "MARK.SPACE", + "MRM": "Mr Mint", "MRN": "Mercoin", "MRNA": "Moderna", "MRP": "MorpheusCoin", "MRPEPE": "Pepe Potato", "MRS": "Metars Genesis", "MRSA": "MrsaCoin", + "MRSMIGGLES": "Mrs Miggles", "MRT": "MinersReward", "MRUN": "Metarun", "MRV": "Macroverse", @@ -8071,10 +9258,11 @@ "MRY": "MurrayCoin", "MSA": "My Shiba Academia", "MSB": "Misbloc", - "MSC": "Miningwatchdog Smartchain", + "MSC": "Matrix SmartChain", "MSCP": "Moonscape", "MSCT": "MUSE ENT NFT", "MSD": "MSD", + "MSFT": "Microsoft 6900", "MSG": "MsgSender", "MSGO": "MetaSetGO", "MSHD": "MASHIDA", @@ -8085,6 +9273,7 @@ "MSOL": "Marinade Staked SOL", "MSOT": "BTour Chain", "MSP": "Mothership", + "MSPC": "MeowSpace", "MSQ": "MSquare Global", "MSR": "Masari", "MST": "Idle Mystic", @@ -8092,12 +9281,13 @@ "MSTETH": "Eigenpie mstETH", "MSTO": "Millennium Sapphire", "MSU": "MetaSoccer", + "MSUSHI": "Sushi (Multichain)", "MSWAP": "MoneySwap", "MT": "MyToken", "MTA": "Meta", "MTB": "MetaBridge", "MTBC": "Metabolic", - "MTC": "MEDICAL TOKEN CURRENCY", + "MTC": "Matrix Chain", "MTCMN": "MTC Mesh", "MTCN": "Multiven", "MTD": "Minted", @@ -8113,11 +9303,13 @@ "MTK": "Moya Token", "MTL": "Metal", "MTLM3": "Metal Music v3", + "MTLS": "eMetals", "MTLX": "Mettalex", + "MTMS": "MTMS Network", "MTN": "TrackNetToken", "MTO": "Merchant Token", "MTP": "Macro Protocol", - "MTR": "MasterTraderCoin", + "MTR": "Meter Stable", "MTRA": "MetaRare", "MTRC": "ModulTrade", "MTRG": "Meter", @@ -8137,25 +9329,31 @@ "MTY": "Viddli", "MTZ": "Monetizr", "MU": "Miracle Universe", + "MUA": "MUA DAO", "MUBI": "Multibit", "MUC": "Multi Universe Central", "MUDOL2": "Hero Blaze: Three Kingdoms", "MUDRA": "MudraCoin", "MUE": "MonetaryUnit", + "MUES": "MuesliSwap MILK", "MULTI": "Multichain", "MULTIBOT": "Multibot", "MULTIGAMES": "MultiGames", "MULTIV": "Multiverse", + "MULTIWALLET": "MultiWallet Coin", "MUMU": "Mumu", "MUN": "MUNcoin", "MUNCH": "Munch Token", "MUNCHY": "Boys Club Munchy", + "MUNI": "Uniswap Protocol Token (Multichain)", "MUNITY": "Metahorse Unity", "MUNK": "Dramatic Chipmunk", + "MUNSUN": "MUNSUN", "MURA": "Murasaki", "MURATIAI": "MuratiAI", "MUSCAT": "MusCat", "MUSD": "mStable USD", + "MUSDC": "USD Coin (Multichain)", "MUSDCOIN": "MUSDcoin", "MUSE": "Muse DAO", "MUSIC": "Gala Music", @@ -8192,10 +9390,13 @@ "MWAVE": "MeshWave", "MWC": "MimbleWimbleCoin", "MWCC": "Metaworld", + "MWD": "MEW WOOF DAO", "MX": "MX Token", "MXC": "Machine Xchange Coin", + "MXD": "Denarius", "MXGP": "MXGP Fan Token", "MXM": "Maximine", + "MXNB": "MXNB", "MXNT": "Tether MXNt", "MXRP": "Monsta XRP", "MXT": "MixTrust", @@ -8215,6 +9416,7 @@ "MYO": "Mycro", "MYOBU": "Myōbu", "MYRA": "Mytheria", + "MYRE": "Myre", "MYRIA": "Myria", "MYRO": "Myro", "MYRODRAGON": "MYRO DRAGON", @@ -8232,18 +9434,23 @@ "MZM": "MetaZooMee", "MZR": "Mazuri GameFi", "MZX": "Mosaic Network", + "Medu": "Medusa", "N0031": "nYFI", "N1": "NFTify", "N3DR": "NeorderDAO ", + "N64": "N64", "N7": "Number7", "N8V": "NativeCoin", "NABOX": "Nabox", "NAC": "Nirvana Chain", + "NACHO": "Nacho the 𐤊at", "NADA": "NADA Protocol Token", "NAFT": "Nafter", "NAH": "Strayacoin", "NAI": "Nuklai", + "NAILONG": "Nailong", "NAKA": "Nakamoto Games", + "NAKAV1": "Nakamoto Games v1", "NALA": "Not a lion, a...", "NALS": "NALS (Ordinals)", "NAM": "Namacoin", @@ -8264,15 +9471,19 @@ "NAS": "Nebulas", "NAS2": "Nas2Coin", "NASADOGE": "Nasa Doge", + "NASDAQ420": "Nasdaq420", "NASH": "NeoWorld Cash", "NASSR": "Alnassr FC Fan Token", "NASTR": "Liquid ASTR", "NAT": "Natmin", + "NATI": "IlluminatiCoin", "NATION": "Nation3", "NATIX": "NATIX Network", + "NATOR": "Pepenator", "NAUSICAA": "Nausicaa-Inu", "NAUT": "Nautilus Coin", "NAV": "NavCoin", + "NAVAL": "NAVAL AI", "NAVC": "NavC token", "NAVI": "Atlas Navi", "NAVIA": "NaviAddress", @@ -8280,7 +9491,9 @@ "NAVX": "NAVI Protocol", "NAVY": "BoatPilot Token", "NAWA": "Narwhale.finance", + "NAWS": "NAWS.AI", "NAX": "NextDAO", + "NAYM": "NAYM", "NAZ": "NAZDAQ", "NAZA": "NAZA", "NAZAR": "NAZAR PROTOCOL", @@ -8306,7 +9519,9 @@ "NCAT": "Neuracat", "NCC": "NeuroChain", "NCDT": "Nuco.Cloud", + "NCN": "NeurochainAI", "NCO": "Nexacore", + "NCOIN": "NatronZ", "NCOP": "NCOP", "NCOR": "NovaCore", "NCORAI": "NeoCortexAI", @@ -8314,6 +9529,7 @@ "NCP": "Newton Coin", "NCR": "Neos Credits", "NCT": "PolySwarm", + "NCTR": "Nectar", "ND": "Nemesis Downfall", "NDAU": "ndau", "NDB": "NDB", @@ -8327,9 +9543,11 @@ "NEADRAM": "The Ennead", "NEAL": "Coineal Token", "NEAR": "Near", + "NEARK": "NearKat", "NEARX": "Stader NearX", "NEAT": "NEAT", "NEBL": "Neblio", + "NEBNB": "Neuro BNB", "NEBU": "Nebuchadnezzar", "NEC": "Nectar", "NEER": "Metaverse.Network Pioneer", @@ -8340,6 +9558,17 @@ "NEFTY": "NeftyBlocks", "NEGED": "Neged", "NEI": "Neurashi", + "NEILUO": "CHINESE NEIRO", + "NEINEI": "Chinese Neiro", + "NEIREI": "NeiRei", + "NEIRO": "Neiro", + "NEIROC": "Neirocoin (neirocoin.club)", + "NEIROCOIN": "Neiro Ethereum", + "NEIROH": "NeiroWifHat", + "NEIROINU": "Neiro Inu", + "NEIROLIVE": "Neiro", + "NEIROLOL": "Neiro", + "NEIROONB": "Neiro on Base", "NEKI": "Neki Token", "NEKO": "The Neko", "NEKOIN": "Nekoin", @@ -8368,6 +9597,8 @@ "NETA": "Negative Tax", "NETC": "NetworkCoin", "NETCOIN": "Netcoincapital", + "NETCOINV1": "Netcoincapital v1", + "NETK": "Netkoin", "NETKO": "Netko", "NETRUM": "Netrum", "NETT": "Netswap", @@ -8384,15 +9615,22 @@ "NEUTR": "Neutrinos", "NEUTRO": "Neutro Protocol", "NEUTRON": "Neutron", + "NEV": "NEVER SURRENDER", "NEVA": "NevaCoin", + "NEVANETWORK": "Neva", + "NEVE": "NEVER SURRENDER", "NEVER": "neversol", "NEW": "Newton", "NEWB": "Newbium", + "NEWBV1": "Newbium v1", + "NEWC": "New Cat", "NEWG": "NewGold", "NEWM": "NEWM", "NEWO": "New Order", "NEWOS": "NewsToken", + "NEWP": "New Peon", "NEWS": "PUBLISH", + "NEWSL": "Newsly", "NEWSTOKENS": "NewsTokens", "NEWTON": "Newtonium", "NEX": "Nash Exchange", @@ -8400,12 +9638,15 @@ "NEXAI": "NexAI", "NEXBOX": "NexBox", "NEXBT": "Native XBTPro Exchange Token", + "NEXG": "NexGami", "NEXM": "Nexum", + "NEXMI": "NexMillionaires", "NEXMS": "NexMillionaires", "NEXO": "NEXO", "NEXT": "Connext Network", "NEXTEX": "Next.exchange Token", "NEXTEXV1": "Next.exchange Token v1", + "NEXTV1": "Connext Network", "NEXUSAI": "NexusAI", "NEXXO": "Nexxo", "NEZHA": "NezhaToken", @@ -8413,7 +9654,9 @@ "NFCR": "NFCore", "NFD": "Feisty Doge NFT", "NFE": "Edu3Labs", + "NFM": "NFMart", "NFN": "Nafen", + "NFNT": "NFINITY AI", "NFP": "NFPrompt", "NFT": "APENFT", "NFT11": "NFT11", @@ -8422,6 +9665,7 @@ "NFTBS": "NFTBooks", "NFTD": "NFTrade", "NFTE": "NFTEarthOFT", + "NFTFI": "NFTfi", "NFTI": "NFT Index", "NFTL": "NFTLaunch", "NFTLOOT": "NFTLootBox", @@ -8429,6 +9673,7 @@ "NFTN": "NFTNetwork", "NFTP": "NFT", "NFTS": "NFT STARS", + "NFTSTYLE": "NFTStyle", "NFTT": "NFT", "NFTX": "NFTX", "NFTXHI": "NFTX Hashmasks Index", @@ -8443,6 +9688,7 @@ "NGL": "Entangle", "NGM": "e-Money", "NGMI": "NGMI Coin", + "NGTG": "NUGGET TRAP", "NHCT": "Nano Healthcare Token", "NHI": "Non Human Intelligence", "NHT": "Neighbourhoods", @@ -8454,17 +9700,24 @@ "NIF": "Unifty", "NIFT": "Niftify", "NIFTSY": "Envelop", + "NIFTY": "Nifty Wizards Dust", + "NIFTYL": "Nifty League", "NIGELLA": "Nigella coin", "NIGHT": "Midnight", "NIGI": "Nigi", + "NIH": "Nihao coin", "NIHAO": "NiHao", "NII": "nahmii", "NIIFI": "NiiFi", "NIK": "NIKPLACE", + "NIKO": "NikolAI", + "NILE": "Nile", "NIM": "Nimiq", "NIMFA": "Nimfamoney", "NIN": "Next Innovation", + "NINJ": "Ninja Protocol", "NINJA": "Dog Wif Nunchucks", + "NINJACAT": "NinjaCat", "NINJAZ": "Danketsu", "NINKY": "Ninky", "NINO": "Ninneko", @@ -8472,7 +9725,10 @@ "NIOB": "Niob Finance", "NIOCTIB": "nioctiB", "NIOX": "Autonio", + "NIOXV1": "Autonio v1", + "NIOXV2": "Autonio v2", "NIPPY": "Cat On Catnip", + "NIQAB": "NIQAB WORLD ORDER", "NIRV": "Nirvana NIRV", "NIT": "Nesten", "NITEFEEDER": "Nitefeeder", @@ -8502,6 +9758,7 @@ "NMH": "Namahe", "NMK": "Namek", "NMKR": "NMKR", + "NML": "No Mans Land", "NMR": "Numeraire", "NMS": "Numus", "NMSP": "Nemesis PRO", @@ -8518,6 +9775,7 @@ "NOBS": "No BS Crypto", "NOCHILL": "AVAX HAS NO CHILL", "NODE": "Whole Network", + "NODIDDY": "NODIDDY", "NODIS": "Nodis", "NODL": "Nodle Network", "NOGS": "Noggles", @@ -8529,8 +9787,13 @@ "NOKU": "NOKU Master token", "NOLA": "Nola", "NOM": "Finom NOM Token", + "NOMNOM": "nomnom", + "NOMOX": "NOMOEX Token", "NONE": "None Trading", "NOO": "Noocoin", + "NOOB": "Blast Royale", + "NOODS": "Noods", + "NOOOO": "NOOOO", "NOOT": "NOOT (Ordinals)", "NOR": "Noir", "NORA": "SnowCrash Token", @@ -8541,7 +9804,11 @@ "NOSN": "nOS", "NOSO": "Noso", "NOT": "Notcoin", + "NOTAI": "NOTAI", + "NOTC": "NOT", + "NOTDOG": "NOTDOG", "NOTE": "Notional Finance", + "NOTECANTO": "Note", "NOTHING": "NOTHING", "NOTINU": "NOTCOIN INU", "NOV": "Novara Calcio Fan Token", @@ -8550,7 +9817,9 @@ "NOX": "NITRO", "NOXB": "Noxbox", "NPAS": "New Paradigm Assets Solution", - "NPC": "NPCcoin", + "NPC": "Non-Playable Coin", + "NPCC": "NPCcoin", + "NPCS": "Non-Playable Coin Solana", "NPER": "NPER", "NPICK": "NPICK BLOCK", "NPLC": "Plus Coin", @@ -8569,7 +9838,7 @@ "NRGY": "NRGY Defi", "NRK": "Nordek", "NRM": "Neuromachine", - "NRN": "Doc.ai Neuron", + "NRN": "Neuron", "NRO": "Neuro", "NRP": "Neural Protocol", "NRS": "NoirShares", @@ -8590,7 +9859,10 @@ "NSP": "NOMAD.space", "NSR": "NuShares", "NSS": "NSS Coin", + "NST": "Ninja Squad Token", "NSTE": "NewSolution 2.0", + "NSTK": "Unstake", + "NSTR": "Nostra", "NSUR": "NSUR Coin", "NSURE": "Nsure Network", "NT": "NEXTYPE Finance", @@ -8602,6 +9874,7 @@ "NTG": "NEWTOWNGAMING", "NTK": "Neurotoken", "NTM": "NetM", + "NTMPI": "Neutaro", "NTO": "Neton", "NTR": "Nether", "NTRN": "Neutron", @@ -8617,6 +9890,7 @@ "NUC": "NuCoin", "NUDE": "0xNude", "NUDES": "NUDES", + "NUGGET": "Gegagedigedagedago", "NUKE": "NukeCoin", "NULS": "Nuls", "NUM": "Numbers Protocol", @@ -8626,8 +9900,10 @@ "NUSA": "Nusa", "NUSD": "Nomin USD", "NUT": "Native Utility Token", + "NUTC": "Nutcash", "NUTGV2": "NUTGAIN", - "NUTS": "Squirrel Finance", + "NUTS": "Thetanuts Finance", + "NUTZ": "NUTZ", "NUUM": "MNet", "NUX": "Peanut", "NVA": "Neeva Defi", @@ -8642,9 +9918,10 @@ "NVT": "NerveNetwork", "NVX": "Novax Coin", "NVZN": "INVIZION", - "NWC": "Newscrypto Coin", + "NWC": "Numerico", "NWCN": "NowCoin", "NWG": "NotWifGary", + "NWIF": "neirowifhat", "NWP": "NWPSolution", "NWS": "Nodewaves", "NXC": "Nexium", @@ -8661,6 +9938,7 @@ "NXTI": "NXTI", "NXTT": "Next Earth", "NXTTY": "NXTTY", + "NYA": "Nya", "NYAN": "NyanCoin", "NYANDOGE": "NyanDOGE International", "NYANTE": "Nyantereum International", @@ -8680,6 +9958,7 @@ "NZL": "Zealium", "NZO": "NonZero", "O": "Childhoods End", + "O1INCH": "1inch (Optimism Bridge)", "O3": "O3 Swap", "O4DX": "O4DX", "OAK": "Acorn Collective", @@ -8689,6 +9968,7 @@ "OAT": "OAT Network", "OATH": "OATH Protocol", "OAX": "Oax", + "OB1INCH": "1inch (OmniBridge)", "OBEMA": "burek obema", "OBI": "Orbofi AI", "OBICOIN": "OBI Real Estate", @@ -8697,11 +9977,14 @@ "OBROK": "OBRok", "OBS": "One Basis Cash", "OBSCURE": "Obscurebay", + "OBSI": "Obsidium", "OBSR": "OBSERVER Coin", + "OBSUSHI": "Sushi (OmniBridge)", "OBT": "Oobit", "OBTC": "Obitan Chain", "OBX": "OpenBlox", "OC": "OrangeCoin", + "OCADA": "OCADA.AI", "OCAI": "Onchain AI", "OCAVU": "Ocavu Network Token", "OCB": "BLOCKMAX", @@ -8714,7 +9997,10 @@ "OCICAT": "OciCat", "OCL": "Oceanlab", "OCN": "Odyssey", + "OCO": "Owners Casino Online", "OCP": "Omni Consumer Protocols", + "OCPR": "OC Protocol", + "OCRV": "Curve DAO Token (OmniBridge)", "OCT": "Octopus Network", "OCTA": "OctaSpace", "OCTAGON": "POLYDeFI", @@ -8726,6 +10012,7 @@ "OCTOIN": "Octoin Coin", "OCW": "Online Cold Wallet", "OCX": "Original Crypto Coin", + "ODAI": "Dai (Optimism Bridge)", "ODC": "Overseas Direct Certification", "ODDZ": "Oddz", "ODE": "ODEM", @@ -8747,7 +10034,10 @@ "OG": "OG Fan Token", "OGCINU": "The OG Cheems Inu", "OGD": "OLYMPIC GAMES DOGE", + "OGGIE": "Oggie", "OGGY": "Oggy Inu", + "OGLG": "OGLONG", + "OGM": "OG Mickey", "OGN": "Origin Protocol", "OGO": "Origo", "OGOD": "GOTOGOD", @@ -8762,15 +10052,19 @@ "OHANDY": "Orbit Bridge Klaytn Handy", "OHM": "Olympus", "OHMV2": "Olympus v2", + "OHNO": "Oh no", + "OHNOGG": "OHNHO (ohno.gg)", "OHO": "OHO", "OICOIN": "Osmium Investment Coin", "OIL": "Oiler", "OILD": "OilWellCoin", + "OILX": "OilX Token", "OIN": "OIN Finance", "OIO": "Online", "OJA": "Ojamu", "OJX": "Ojooo", "OK": "OKCash", + "OKANE": "OKANE", "OKAYEG": "Okayeg", "OKB": "OKB", "OKG": "Ookeenga", @@ -8780,8 +10074,11 @@ "OKS": "Oikos", "OKSE": "Okse", "OKT": "OKT Chain", + "OL": "Open Loot", + "OLAF": "Olaf Token", "OLAND": "Oceanland", "OLAS": "Autonolas", + "OLD": "Old Trump", "OLDSF": "OldSafeCoin", "OLE": "OpenLeverage", "OLEA": "Olea Token", @@ -8793,6 +10090,7 @@ "OLXA": "OLXA", "OLY": "Olyseum", "OLYMP": "OlympCoin", + "OLYMPE": "OLYMPÉ", "OM": "MANTRA", "OMA": "OmegaCoin", "OMAX": "Omax", @@ -8806,12 +10104,15 @@ "OMI": "ECOMI", "OMIC": "Omicron", "OMIKAMI": "Amaterasu Omikami", + "OMIX": "Omix", "OMMI": "Ommniverse", - "OMNI": "Omni", - "OMNIA": "OmniaVerse", + "OMNI": "Omni Network", + "OMNIA": "OMNIA Protocol", + "OMNIAV1": "OmniaVerse v1", + "OMNIAV2": "OmniaVerse", "OMNIC": "OmniCat", "OMNICRON": "OmniCron", - "OMNINET": "Omni Network", + "OMNILAYER": "Omni", "OMNIR": "Omni Real Estate Token", "OMNIX": "OmniBotX", "OMNOM": "Doge Eat Doge", @@ -8819,9 +10120,11 @@ "OMT": "Mars Token", "OMV1": "OM Token (v1)", "OMX": "Project Shivom", + "OMZ": "Open Meta City", "ON": "OFIN Token", "ONAM": "ONAM", "ONC": "One Cash", + "ONCH": "OnchainPoints.xyz", "ONDO": "Ondo", "ONE": "Harmony", "ONES": "OneSwap DAO", @@ -8830,6 +10133,8 @@ "ONG": "SoMee.Social", "ONGAS": "Ontology Gas", "ONI": "ONINO", + "ONIG": "Onigiri", + "ONIGIRI": "Onigiri The Cat", "ONION": "DeepOnion", "ONIT": "ONBUFF", "ONL": "On.Live", @@ -8844,9 +10149,11 @@ "ONUS": "ONUS", "ONX": "Onix", "OOE": "OpenOcean", + "OOFP": "OOFP", "OOGI": "OOGI", "OOKI": "Ooki", "OOKS": "Onooks", + "OOM": "OomerBot", "OORC": "Orbit Bridge Klaytn Orbit Chain", "OORT": "OORT", "OOT": "Utrum", @@ -8855,6 +10162,7 @@ "OPA": "Option Panda Platform", "OPAIG": "OvalPixel", "OPC": "OP Coin", + "OPCA": "OP_CAT(BIP-420)", "OPCAT": "OPCAT", "OPCT": "Opacity", "OPEN": "Open Custody Protocol", @@ -8865,6 +10173,7 @@ "OPENP": "Open Platform", "OPENRI": "Open Rights Exchange", "OPENSOURCE": "Open Source Network", + "OPENW": "OpenWorld", "OPENX": "OpenSwap Optimism Token", "OPEPE": "Optimism PEPE", "OPES": "Opes", @@ -8880,23 +10189,28 @@ "OPS": "Octopus Protocol", "OPSC": "OpenSourceCoin", "OPSEC": "OpSec", + "OPSV1": "Octopus Protocol v1", + "OPSV2": "Octopus Protocol v2", "OPT": "Opus", "OPTA": "Opta Global", "OPTC": "Open Predict Token", "OPTCM": "Optimus", "OPTI": "Optimus AI", "OPTIG": "Catgirl Optimus", + "OPTIM": "Optimus X", "OPTIMOUSE": "Optimouse", "OPTION": "OptionCoin", "OPU": "Opu Coin", "OPUL": "Opulous", "OPV": "OpenLive NFT", "OPXVEVELO": "OpenX Locked Velo", + "ORA": "Oracolxor", "ORACLE": "Oracle AI", "ORACLECHAIN": "OracleChain", "ORACUL": "Oracul Ai", "ORAI": "Oraichain Token", "ORAIX": "OraiDEX", + "ORANGE": "Annoying Orange", "ORAO": "ORAO Network", "ORARE": "OneRare", "ORB": "KlayCity ORB", @@ -8910,9 +10224,11 @@ "ORC": "Orbit Chain", "ORCA": "Orca", "ORD": "ordinex", + "ORDER": "Orderly Network", "ORDI": "Ordinals ", "ORDI2": "ORDI 2.0", "ORDIFI": "OrdinalsFi", + "ORDIN": "ORDINAL HODL MEME", "ORDS": "Ordiswap", "ORE": "Galactrum", "OREO": "OreoFi", @@ -8923,9 +10239,11 @@ "ORI": "Origami", "ORIGIN": "Origin Foundation", "ORION": "Orion Money", + "ORKL": "Orakler", "ORLY": "OrlyCoin", "ORM": "ORIUM", "ORME": "Ormeus Coin", + "ORMO": "Ormolus", "ORN": "Orion Protocol", "ORNJ": "Orange", "ORO": "Operon Origins", @@ -8942,6 +10260,7 @@ "OSA": "OSA Token", "OSAK": "Osaka Protocol", "OSC": "iOscar", + "OSCAR": "OSCAR", "OSEA": "Omnisea", "OSEAN": "OSEAN", "OSETH": "StakeWise Staked ETH", @@ -8952,10 +10271,12 @@ "OSK": "OSK", "OSKDAO": "OSK DAO", "OSL": "OSL AI", + "OSMI": "OSMI", "OSMO": "Osmosis", "OSQTH": "Opyn Squeeth", "OSS": "OSSChain", "OST": "OST", + "OSUSHI": "Sushi (Optimism Bridge)", "OSWAP": "OpenSwap", "OT": "Onchain Trade", "OTB": "OTCBTC Token", @@ -8973,6 +10294,7 @@ "OUSD": "Origin Dollar", "OUSDC": "Orbit Bridge Klaytn USDC", "OUSE": "OUSE Token", + "OUSG": "OUSG", "OUT": "Netscouters", "OVC": "OVCODE", "OVERLORD": "Overlord", @@ -8984,6 +10306,7 @@ "OWL": "OWL Token", "OWN": "Ownly", "OWNDATA": "OWNDATA", + "OWO": "SoMon", "OX": "Open Exchange Token", "OXAI": "OxAI.com", "OXB": "Oxbull Tech", @@ -9004,7 +10327,9 @@ "OZMPC": "Ozempic", "OZO": "Ozone Chain", "OZONE": "Ozone metaverse", + "OZONEC": "Ozonechain", "OZP": "OZAPHYRE", + "P": "PUPS•WORLD•PEACE", "P202": "Project 202", "P2PS": "P2P Solutions Foundation", "P3D": "3DPass", @@ -9014,8 +10339,10 @@ "PABLO": "PABLO DEFI", "PAC": "PacMoon", "PACE": "3space Art", + "PACK": "HashPack", "PACM": "Pacman Blastoff", "PACMAN": "Pac Man", + "PACO": "Paco", "PACOCA": "Pacoca", "PACP": "PAC Protocol", "PACT": "impactMarket", @@ -9031,6 +10358,7 @@ "PAK": "Pakcoin", "PAL": "PolicyPal Network", "PALAI": "PaladinAI", + "PALE": "Palette", "PALET": "Palette", "PALG": "PalGold", "PALLA": "Pallapay", @@ -9041,26 +10369,34 @@ "PAM": "PAM", "PAMBI": "Pambicoin", "PAMP": "PAMP Network", - "PAN": "Pantos", + "PAN": "Pankito", "PAND": "Panda Finance", "PANDA": "PandaDAO", "PANDAI": "PandAI", + "PANDAS": "Panda Swap", + "PANDE": "Pande", "PANDO": "Pando", "PANDOP": "PandoProject", "PANDORA": "Pandora", "PANGEA": "PANGEA", "PANIC": "PanicSwap", "PANO": "PanoVerse", + "PANTOS": "Pantos", + "PAO": "South Pao", "PAPA": "Papa Bear", "PAPADOGE": "Papa Doge", + "PAPAT": "PAPA Trump", "PAPER": "Dope Wars Paper", + "PAPERBASE": "Paper", "PAPI": "Papi", + "PAPO": "PAPO NINJA", "PAPPAY": "PAPPAY", "PAPU": "Papu Token", "PAPUSHA": "Papusha", "PAR": "Parachute", "PARA": "Paralink Network", "PARAB": "Parabolic", + "PARAD": "Paradox", "PARADOX": "The Paradox Metaverse", "PARAG": "Paragon Network", "PARAL": "Parallel", @@ -9075,6 +10411,7 @@ "PARLAY": "Parlay", "PARMA": "PARMA Fan Token", "PARQ": "PARQ", + "PARRY": "Parry Parrot", "PART": "Particl", "PAS": "Passive Coin", "PASC": "Pascal Coin", @@ -9085,13 +10422,17 @@ "PATEK": "Silly Patek", "PATEX": "Patex", "PATH": "PathDAO", + "PATRIOT": "Patriot", "PATTON": "Patton", + "PAUL": "Elephant Penguin", "PAVIA": "Pavia", "PAVO": "Pavocoin", "PAW": "PAWSWAP", + "PAWPAW": "PawPaw", "PAWS": "PawStars", "PAWSTA": "dogeatingpasta", "PAWTH": "Pawthereum", + "PAXE": "Paxe", "PAXEX": "PAXEX", "PAXG": "PAX Gold", "PAXU": "Pax Unitas", @@ -9099,6 +10440,7 @@ "PAY": "TenX", "PAYB": "Paybswap", "PAYCON": "Paycon", + "PAYD": "PAYD", "PAYN": "PayNet Coin", "PAYP": "PayPeer", "PAYS": "Payslink", @@ -9108,6 +10450,7 @@ "PAZZI": "Paparazzi", "PBAR": "Pangolin Hedera", "PBASE": "Polkabase", + "PBB": "PEPE BUT BLUE", "PBC": "PabyosiCoin", "PBET": "PBET", "PBIRB": "Parrotly", @@ -9139,41 +10482,55 @@ "PCR": "Paycer Protocol", "PCS": "Pabyosi Coin", "PCSP": "GenomicDao G-Stroke", + "PCW": "Power Crypto World", "PCX": "ChainX", "PD": "PUDEL", "PDA": "PlayDapp", + "PDAI": "Dai (Polygon Portal)", "PDATA": "PDATA", "PDC": "Project Decorum", "PDD": "PDDOLLAR", "PDEX": "Polkadex", "PDF": "Port of DeFi Network", + "PDJT": "President Donald J. Trump", "PDOG": "Polkadog", "PDOGE": "PolkaDoge", "PDRAGON": "Phoenix Dragon", "PDRIP": "Pulse Drip", "PDT": "ParagonsDAO", "PDX": "PDX Coin", + "PE": "Pe", "PEA": "Pea Farm", "PEACH": "Based Peaches", "PEACHY": "Peachy", "PEAK": "PEAKDEFI", + "PEAN": "Peanut the Squirrel (peanut-token.xyz)", "PEANIE": "Peanie", + "PEANU": "PEANUT INU", + "PEANUT": "#1 Tiktok Squirrel", + "PEAQ": "peaq", "PEAR": "Pear Swap", "PEARL": "Pearl Finance", "PEAS": "Peapods Finance", + "PEBIRD": "PEPE BIRD", "PEC": "PeaceCoin", "PECL": "PECland", "PED": "PEDRO", "PEDRO": "Pedro The Raccoon", "PEEL": "Meta Apes", + "PEENO": "Peeno", "PEEP": "Peepo", "PEEPA": "Peepa", "PEEPEE": "Peepee", "PEEPO": "PEEPO", + "PEEPOBASE": "Peepo (peepobase.org)", "PEEPS": "The People’s Coin", "PEEZY": "Young Peezy AKA Pepe", "PEFI": "Penguin Finance", "PEG": "PegNet", + "PEGA": "PEGA", + "PEGAMAGA": "Pepe Maga", + "PEGG": "PokPok Golden Egg", "PEGS": "PegShares", "PEIPEI": "PEIPEI", "PEKA": "PEKA", @@ -9183,22 +10540,29 @@ "PEL": "Propel Token", "PELF": "PELFORT", "PEM": "Pembrock", + "PEME": "PEME", "PENC": "PenCoin", "PENDLE": "Pendle", + "PENDY": "Pendy", "PENG": "Peng", "PENGCOIN": "PENG", + "PENGU": "Penguiana", "PENGYX": "PengyX", "PENIS": "PenisGrow", + "PENJ": "Penjamin Blinkerton", "PENP": "Penpie", "PENR": "Penrose Finance", "PENTA": "Penta", + "PEON": "Peon", "PEOPLE": "ConstitutionDAO", "PEOSONE": "pEOS", "PEP": "Pepechain", "PEPA": "Pepa Inu", + "PEPAY": "PEPAY", "PEPC": "Pepe Classic", "PEPE": "Pepe", "PEPE2": "Pepe 2.0", + "PEPE2024": "Olympic Pepe 2024", "PEPE20V1": "Pepe 2.0 v1", "PEPEA": "Pepeandybrettlandwolf", "PEPEAI": "Pepe Analytics", @@ -9206,12 +10570,14 @@ "PEPEB": "PEPEBOMB", "PEPEBNB": "Pepe The Frog", "PEPEBRC": "PEPE (Ordinals)", + "PEPEBSC": "Pepe Coin", "PEPEBURN": "Pepeburn", "PEPEC": "Pepe Chain", "PEPECASH": "Pepe Cash", "PEPECAT": "PEPE CAT", "PEPECEO": "REAL PEPE CEO", "PEPECHAIN": "PEPE Chain", + "PEPECO": "PEPE COIN BSC", "PEPECOIN": "PepeCoin", "PEPED": "PepeDAO Coin", "PEPEDAO": "PEPE DAO", @@ -9227,17 +10593,21 @@ "PEPEGRINCH": "Pepe Grinch", "PEPEINU": "PEPE inu", "PEPEKING": "PEPEKING", + "PEPEKRC20": "PEPE KRC20", "PEPELON": "Pepelon", "PEPEMAGA": "Trump Pepe", "PEPEMO": "PepeMo", "PEPEMOON": "PEPEMOON", + "PEPEOFSOL": "Pepe of Solana", "PEPEPI": "PEPEPi", "PEPER": "Baby Pepe", "PEPERA": "PEPERA", "PEPESOL": "PEPE SOL", + "PEPESOLCTO": "Pepe (pepesolcto.vip)", "PEPESORA": "Pepe Sora AI", "PEPESWAP": "PEPE Swap", "PEPET": "PepeTrump", + "PEPETR": "PEPE TREMP", "PEPEW": "PEPEPOW", "PEPEWIFHAT": "Pepewifhat", "PEPEWO": "PEPE World", @@ -9268,7 +10638,10 @@ "PESA": "Credible", "PESHI": "PESHI", "PESOBIT": "PesoBit", + "PESTO": "Pesto the Baby King Penguin", "PET": "Hello Pets", + "PETE": "PETE", + "PETERTODD": "Peter Todd", "PETF": "PEPE ETF", "PETG": "Pet Games", "PETH": "pETH", @@ -9293,7 +10666,7 @@ "PGEN": "Polygen", "PGF7T": "PGF500", "PGL": "Prospectors", - "PGN": "Pigeoncoin", + "PGN": "Paragon", "PGOLD": " Polkagold", "PGPT": "PrivateAI", "PGROK": "Papa Grok", @@ -9310,37 +10683,48 @@ "PHBD": "Polygon HBD", "PHC": "Profit Hunters Coin", "PHCR": "PhotoChromic", + "PHEN": "Phenx", + "PHEX": "HEX (Polygon Portal)", "PHI": "PHI Token", "PHIBA": "Papa Shiba", "PHIGOLD": "PhiGold Coin", + "PHIL": "Philtoken", "PHL": "Philcoin", "PHM": "Phomeum", + "PHMN": "POSTHUMAN", "PHN": "Phayny", "PHNX": "PhoenixDAO", "PHO": "Photon", + "PHOENIX": "Phoenix Finance", "PHONON": "Phonon DAO ", "PHOON": "Typhoon Cash", "PHORE": "Phore", "PHR": "Phreak", + "PHRYG": "PHRYGES", "PHRYGE": "PHRYGES", + "PHRYGES": "The Phryges", "PHS": "PhilosophersStone", "PHT": "Photon Token", "PHTC": "Photochain", "PHTR": "Phuture", + "PHUN": "PHUNWARE", "PHV": "PATHHIVE", - "PHX": "Phoenix Finance", "PI": "Plian", "PIA": "Olympia AI", "PIAS": "PIAS", "PIB": "Pibble", "PICA": "PicaArtMoney", + "PICKL": "PICKLE", "PICKLE": "Pickle Finance", "PICO": "PicoGo", + "PICOLO": "PICOLO", "PIE": "Persistent Information Exchange", + "PIERRE": "sacré bleu", "PIF": "Pepe Wif Hat", "PIG": "Pig Finance", "PIGE": "Pige", "PIGEON": "Pigeon In Yellow Boots", + "PIGEONC": "Pigeoncoin", "PIGGY": "Piggy", "PIGGYCOIN": "Piggy Coin", "PIGONK": "PIGONK", @@ -9348,18 +10732,24 @@ "PIIN": "piin (Ordinals)", "PIKA": "Pikaboss", "PIKACHU": "Pikachu Inu", + "PIKACRYPTO": "Pika", + "PIKAM": "Pikamoon", + "PIKE": "Pike Token", "PIKO": "Pinnako", "PILOT": "Unipilot", + "PIM": "PIM", "PIN": "Pin", "PINCHI": "Da Pinchi", "PINE": "Pine", "PINETWORKDEFI": "Pi Network DeFi", "PING": "CryptoPing", - "PINK": "PinkCoin", + "PINK": "PINK - The Panther", + "PINKCOIN": "PinkCoin", "PINKSALE": "PinkSale", "PINKX": "PantherCoin", "PINMO": "Pinmo", "PINO": "Pinocchu", + "PINS": "PINs Network Token", "PINU": "Piccolo Inu", "PINU100X": "Pi INU 100x", "PIO": "Pioneershares", @@ -9367,9 +10757,13 @@ "PIPA": "Pipa Coin", "PIPI": "Pippi Finance", "PIPL": "PiplCoin", + "PIPO": "Pipo", + "PIPPIN": "pippin", "PIPT": "Power Index Pool Token", "PIRATE": "Pirate Nation", "PIRATECASH": "PirateCash", + "PIRATECASHV1": "PirateCash v1", + "PIRATECASHV2": "PirateCash v2 (PirateCash Telegram bot)", "PIRATECOIN": "Pirate Coin Games", "PIRB": "PIRB", "PIRI": "Pirichain", @@ -9383,6 +10777,8 @@ "PIX": "Lampix", "PIXEL": "Pixels", "PIXELV": "PixelVerse", + "PIXFI": "Pixelverse", + "PIXL": "PIXL", "PIZA": "Half Pizza", "PIZPEPE": "Pepe Pizzeria", "PIZZA": "PizzaSwap", @@ -9411,7 +10807,7 @@ "PLATC": "PlatinCoin", "PLATINUM": "Platinum", "PLATO": "Plato Game", - "PLAY": "HEROcoin", + "PLAY": "Play Token", "PLAYC": "PlayChip", "PLAYCOIN": "PlayCoin", "PLAYKEY": "Playkey", @@ -9422,7 +10818,9 @@ "PLCUC": "PLC Ultima Classic", "PLD": "Plutonian DAO", "PLE": "Plethori", + "PLEA": "Plearn", "PLEB": "PLEBToken", + "PLEBONBASE": "PLEB", "PLENTY": "Plenty DeFi", "PLEO": "Empleos", "PLERF": "Plerf", @@ -9431,6 +10829,7 @@ "PLG": "Pledgecamp", "PLGR": "Pledge Finance", "PLI": "Plugin", + "PLINK": "Chainlink (Polygon Portal)", "PLM": "Plasmonics", "PLMC": "Polimec", "PLMT": "Pallium", @@ -9460,6 +10859,7 @@ "PLX": "PlexCoin", "PLXY": "Plxyer", "PLY": "Aurigami", + "PLYR": "PLYR L1", "PLZ": "PLUNZ", "PMA": "PumaPay", "PMD": "Pandemic Multiverse", @@ -9467,6 +10867,7 @@ "PMEER": "Qitmeer", "PMG": "Pomerium Ecosystem Token", "PMGT": "Perth Mint Gold Token", + "PMKR": "Maker (Polygon Portal)", "PMM": "Perpetual Motion Machine", "PMNT": "Paymon", "PMON": "Polkamon", @@ -9488,6 +10889,10 @@ "PNL": "True PNL", "PNODE": "Pinknode", "PNT": "pNetwork Token", + "PNUT": "Peanut the Squirrel", + "PNUTDOGE": "PNUT DOGE", + "PNUTRUMP": "Peanut Trump", + "PNUTS": "Pnuts for squirrel", "PNX": "PhantomX", "PNY": "Peony Coin", "POA": "Poa Network", @@ -9495,13 +10900,15 @@ "POC": "POC Blockchain", "POCAT": "Polite Cat", "POCC": "POC Chain", + "POCHITA": "Pochita", "POCKET": "XPocket", "POCO": "Pocoland", "POD": "Podo Point", "PODFAST": "PodFast", "PODIUM": "Smart League", "PODO": "Power Of Deep Ocean", - "POE": "Po.et", + "POE": "Portal Network", + "POET": "Po.et", "POG": "PolygonumOnline", "POGAI": "POGAI", "POGS": "POG", @@ -9528,6 +10935,7 @@ "POLKER": "Polker", "POLL": "Pollchain", "POLLUK": "Jasse Polluk", + "POLLUX": "Pollux Coin", "POLNX": "eToro Polish Zloty", "POLO": "NftyPlay", "POLS": "Polkastarter", @@ -9543,31 +10951,42 @@ "PONCHO": "Poncho", "POND": "Marlin", "PONGO": "Pongo", + "PONK": "PONK", "PONKE": "Ponke", "PONKEBNB": "Ponke BNB", + "PONKEI": "Chinese Ponkei the Original", "PONYO": "Ponyo Impact", "PONZI": "Ponzi", + "PONZIO": "Ponzio The Cat", "PONZU": "Ponzu Inu", "POO": "POOMOON", + "POOC": "Poo Chi", "POOCOIN": "PooCoin", "POODL": "Poodl", "POODOGE": "Poo Doge", "POOH": "POOH", + "POOKU": "Pooku", "POOL": "PoolTogether", "POOLX": "Poolz Finance", "POOLXT": "Pool-X", "POOLZ": "Poolz Finance", "POOP": "Poopsicle", + "POOPC": "Poopcoin", "POOWEL": "Joram Poowel", - "POP": "PopularCoin", - "POP!": "POP", + "POP": "Popcoin", "POPC": "PopChest", "POPCAT": "Popcat", + "POPCO": "Popcorn", "POPDOG": "PopDog", - "POPE": "Popecoin", + "POPE": "PopPepe", + "POPECOIN": "Popecoin", + "POPEPE": "POPEPE", + "POPGOAT": "Goatseus Poppimus", "POPK": "POPKON", "POPO": "popo", + "POPOETH": "POPO", "POPSICLE": "Popsicle Finance", + "POPULARCOIN": "PopularCoin", "POR": "Portugal National Team Fan Token", "PORA": "PORA AI", "PORK": "PepeFork", @@ -9594,11 +11013,14 @@ "POTS": "Moonpot", "POTTER": "POTTER", "POU": "Pou", + "POUPE": "Poupe", + "POUW": "Pouwifhat", "POW": "PowBlocks", "POWELL": "Jerome Powell", "POWER": "UniPower", "POWR": "Power Ledger", "POWSCHE": "Powsche", + "POX": "Monkey Pox", "PP": "ProducePay Chain", "PPAD": "PlayPad", "PPALPHA": "Phoenix Protocol", @@ -9630,6 +11052,7 @@ "PRDX": "ParamountDax Token", "PRE": "Presearch", "PREAI": "Predict Crypto", + "PREC": "Precipitate.AI", "PRED": "Predictcoin", "PREM": "Premium", "PREME": "PREME Token", @@ -9649,6 +11072,7 @@ "PRIME": "Echelon Prime", "PRIMECHAIN": "PrimeChain", "PRIMEETH": "Prime Staked ETH", + "PRIN": "Print The Pepe", "PRINT": "Printer.Finance", "PRINTERIUM": "Printerium", "PRINTS": "FingerprintsDAO", @@ -9664,6 +11088,8 @@ "PROC": "ProCurrency", "PROD": "Productivist", "PROGE": "Protector Roge", + "PROJECT89": "Project89", + "PROLIFIC": "Prolific Game Studio", "PROM": "Prometeus", "PROOF": "PROVER", "PROP": "Propeller", @@ -9673,6 +11099,7 @@ "PROPS": "Propbase", "PROPSPROJECT": "Props", "PROS": "Prosper", + "PROSP": "Prospective", "PROT": "PROT", "PROTEO": "Proteo DeFi", "PROTO": "Protocon", @@ -9684,6 +11111,7 @@ "PRPS": "Purpose", "PRPT": "Purple Token", "PRQ": "PARSIQ", + "PRRR": "Cats Are Liquidity", "PRS": "PressOne", "PRT": "Parrot Protocol", "PRTC": "Protectorate Protocol", @@ -9694,6 +11122,7 @@ "PRVS": "Previse", "PRX": "Parex", "PRXY": "Proxy", + "PRXYV1": "Proxy v1", "PRY": "PRIMARY", "PRZS": "Perezoso", "PS1": "POLYSPORTS", @@ -9717,6 +11146,7 @@ "PSTAKE": "pSTAKE Finance", "PSTN": "Piston", "PSUB": "Payment Swap Utility Board", + "PSUSHI": "Sushi (Polygon Portal)", "PSWAP": "Polkaswap", "PSY": "PsyOptions", "PSYOP": "PSYOP", @@ -9741,40 +11171,59 @@ "PTU": "Pintu Token", "PTX": "PlatinX", "PUCA": "Puss Cat", + "PUCCA": "PUCCA", "PUFETH": "pufETH", - "PUFF": "Puff", + "PUFF": "Puff The Dragon", + "PUFFCOIN": "Puff", + "PUFFER": "Puffer", "PUFFIN": "Puffin Global", - "PUFFT": "Puff The Dragon", + "PUFFV1": "Puff The Dragon v1", + "PUFFY": "Puffy", "PUGAI": "PUG AI", + "PUGDOG": "PUGDOG", + "PUGGY": "PUGGY Coin", "PUGL": "PugLife", + "PUGWIF": "PUGWIFHAT", + "PUL": "PulseTrailerPark", "PULI": "Puli", "PULSE": "Pulse", "PUMA": "Puma", "PUMBAA": "Pumbaa", "PUMLX": "PUMLx", "PUMP": "PUMP", + "PUMPBTC": "pumpBTC", + "PUMPFUNBAN": "Pump Fun Ban", "PUN": "Punkko", "PUNCH": "PUNCHWORD", "PUNDIX": "Pundi X", "PUNDU": "Pundu", + "PUNGU": "PUNGU", + "PUNI": "Uniswap Protocol Token (Polygon Portal)", "PUNK": "PunkCity", "PUNKAI": "PunkAI", "PUNKV": "Punk Vault (NFTX)", "PUP": "Puppy Coin", "PUPA": "PupaCoin", "PUPPER": "Pupper", + "PUPPET": "Puppet", + "PUPPETH": "Puppeth", "PUPPETS": "Puppets Coin", "PUPPIES": "I love puppies", "PUPS": "PUPS (Ordinals)", + "PUPU": "Pepe's Dog", "PURA": "Pura", "PURE": "Puriever", "PUREALT": "Pure", - "PURR": "SpartaCats", + "PURPE": "Purple Pepe", + "PURR": "Purr", + "PURRC": "Purrcoin", "PURSE": "Pundi X PURSE", "PUS": "Pussy Cat", "PUSD": "PegsUSD", + "PUSDC": "USD Coin (Polygon Portal)", "PUSH": "Ethereum Push Notification Service", "PUSHI": "Pushi", + "PUSS": "PussFi", "PUSSY": "Pussy Financial", "PUSSYINBIO": "Pussy In Bio", "PUT": "PutinCoin", @@ -9790,7 +11239,8 @@ "PWH": "pepewifhat", "PWINGS": "JetSwap pWings", "PWON": "Personal Wager", - "PWR": "PWR Coin", + "PWR": "MaxxChain", + "PWRC": "PWR Coin", "PWT": "PANDAINU", "PX": "PXcoin", "PXB": "PixelBit", @@ -9819,6 +11269,7 @@ "PYT": "Payther", "PYTH": "Pyth Network", "PYUSD": "PayPal USD", + "PZETH": "pzETH", "PZM": "Prizm", "PZP": "PlayZap", "PZT": "Pizon", @@ -9850,6 +11301,8 @@ "QDT": "QCHAIN", "QDX": "Quidax", "QFI": "QFinance", + "QGOLD": "Quorium", + "QGOV": "Q Protocol", "QI": "BENQI", "QIE": "QI Blockchain", "QINGWA": "ShangXin QingWa", @@ -9884,16 +11337,21 @@ "QSR": "Quasar", "QSWAP": "Quantum Network", "QTC": "Qitcoin", + "QTCC": "Quick Transfer coin", "QTCON": "Quiztok", + "QTDAO": "Quantum DAO", "QTF": "Quantfury", "QTK": "QuantCheck", "QTL": "Quatloo", + "QTLX": "Quantlytica", "QTO": "QToken", "QTUM": "QTUM", "QTZ": "Quartz", "QUA": "Quantum Tech", + "QUAC": "QUACK", "QUACK": "Rich Quack", "QUAM": "Quam Network", + "QUAN": "Quant AI", "QUANT": "Quant Finance", "QUARASHI": "Quarashi Network", "QUARK": "Quark", @@ -9903,6 +11361,8 @@ "QUBE": "Qube", "QUBIC": "Qubic", "QUBITICA": "Qubitica", + "QUBY": "Quby", + "QUE": "Queen Of Memes", "QUEEN": "Queen of Engrand", "QUICK": "Quickswap", "QUICKOLD": "Quickswap", @@ -9931,6 +11391,7 @@ "R4RE": "R4RE Token", "RAB": "Rabbit", "RABB": "Rabbit INU", + "RABBI": "Len \"rabbi\" Sassaman", "RABBIT": "Rabbit Finance", "RABI": "Rabi", "RAC": "RAcoin", @@ -9947,6 +11408,7 @@ "RAFFLES": "Degen Raffles", "RAFL": "RAFL", "RAFT": "Raft", + "RAGDOLL": "Ragdoll", "RAGE": "Rage Fan", "RAI": "Rai Reflex Index", "RAID": "Raid Token", @@ -9956,6 +11418,7 @@ "RAIN": "Rainmaker Games", "RAINBOW": "Rainbow Token", "RAINC": "RainCheck", + "RAINCO": "Rain Coin", "RAINI": "Rainicorn", "RAISE": "Raise Token", "RAIT": "Rabbitgame", @@ -9972,6 +11435,7 @@ "RAP": "Philosoraptor", "RAPDOGE": "RapDoge", "RAPTOR": "Jesus-Raptor", + "RAR": "Rare Pepe", "RARE": "SuperRare", "RARI": "Rarible", "RASTA": "ZionLabs Token", @@ -10011,6 +11475,7 @@ "RBUNNY": "Rocket Bunny", "RBW": "Crypto Unicorns Rainbow", "RBX": "RabbitX", + "RBXDEFI": "RBX", "RBXS": "RBXSamurai", "RBY": "RubyCoin", "RC": "Russiacoin", @@ -10022,7 +11487,8 @@ "RCKT": "RocketSwap", "RCM": "READ2N", "RCN": "Ripio", - "RCOIN": "RCoin", + "RCOIN": "ArCoin", + "RCOINEU": "RCoin", "RCT": "RealChain", "RCX": "RedCrowCoin", "RD": "Round Dollar", @@ -10036,6 +11502,7 @@ "RDNT": "Radiant Capital", "RDNTV1": "Radiant Capital v1", "RDO": "Rodeo Finance", + "RDOG": "Repost Dog", "RDPX": "Dopex Rebate Token", "RDR": "Rise of Defenders", "RDS": "Reger Diamond", @@ -10046,17 +11513,22 @@ "REAL": "RealLink", "REALM": "Realm", "REALMS": "Realms of Ethernity", + "REALP": "Real Pepe", "REALPLATFORM": "REAL", + "REALTRACT": "RealTract", "REALY": "Realy Metaverse", "REAP": "ReapChain", "REAPER": "Grim Finance", "REAU": "Vira-lata Finance", + "REBD": "REBORN", "REBL": "REBL", "REBUS": "Rebuschain", "REC": "Rec Token (REC)", "RECA": "The Resistance Cat", "RECKOON": "Reckoon", "RECOM": "Recom", + "RECORD": "Music Protocol", + "RECT": "ReflectionAI", "RED": "RED TOKEN", "REDC": "RedCab", "REDCO": "Redcoin", @@ -10071,6 +11543,7 @@ "REDO": "Resistance Dog", "REDP": "Red Ponzi Gud", "REDPEPE": "Red Pepe", + "REDTH": "Red The Mal", "REDZILLA": "REDZILLA COIN", "REE": "ReeCoin", "REEE": "REEE", @@ -10085,6 +11558,7 @@ "REGALCOIN": "Regalcoin", "REGEN": "Regen Network", "REGENT": "REGENT COIN", + "REGI": "Resistance Girl", "REHA": "Resistance Hamster", "REHAB": "NFT Rehab", "REI": "REI Network", @@ -10100,28 +11574,34 @@ "REM": "REMME", "REMCO": "Remco", "REME": "REME-Coin", + "REMILIA": " Remilia", "REMIT": "BlockRemit", "REN": "REN", "RENA": "Warena", "RENBTC": "renBTC", "RENC": "RENC", + "RENDER": "Render Network", "RENDOGE": "renDOGE", - "RENE": "Renewable Energy", "RENEC": "RENEC", "RENQ": "Renq Finance", "RENS": "Rens", "RENT": "Rent AI", "RENTBE": "Rentberry", "REP": "Augur", + "REPE": "Resistance Pepe", "REPO": "Repo Coin", + "REPUB": "Republican", + "REPUBLICAN": "Republican", "REPUX": "Repux", + "REPV1": "Reputation", "REQ": "Request Network", "RES": "Resistance", "RESCUE": "Rescue", "REST": "Restore", - "RET": "RealTract", + "RET": "Renewable Energy", "RETA": "Realital Metaverse", "RETAIL": "Retail.Global", + "RETARDIA": "RETARDIA", "RETARDIO": "RETARDIO", "RETH": "Rocket Pool ETH", "RETH2": "rETH2", @@ -10132,17 +11612,22 @@ "REV": "Revain", "REV3L": "REV3AL", "REVA": "Revault Network", + "REVAL": "RevaLink Wallet Token", "REVE": "Revenu", "REVO": "Revomon", "REVOAI": "revoAI", + "REVOL": "Revolution", "REVOLAND": "Revoland Governance Token", "REVON": "RevoNetwork", "REVU": "Revuto", "REVV": "REVV", "REW": "Review.Network", + "REWARD": "Rewardable", "REX": "Imbrex", + "REXHAT": "rexwifhat", "REZ": "Renzo", "RF": "Raido Financial", + "RFC": "Royal Finance Coin", "RFCTR": "Reflector.Finance", "RFD": "RefundCoin", "RFDB": "Refund", @@ -10152,6 +11637,7 @@ "RFL": "RAFL", "RFOX": "RedFOX Labs", "RFR": "Refereum", + "RFRM": "Reform DAO", "RFT": "Rangers Fan Token", "RFUEL": "Rio DeFi", "RFX": "Reflex", @@ -10169,12 +11655,14 @@ "RHP": "Rhypton Club", "RIA": "aRIA Currency", "RIB": "Ribus", + "RIBB": "Ribbit", "RIBBIT": "Ribbit", "RIC": "Riecoin", "RICE": "RiceFarm", "RICECOIN": "RiceCoin", "RICH": "Richie", "RICHOFME": "Rich Of Memes", + "RICHR": "RichRabbit", "RICK": "Infinite Ricks", "RICKMORTY": "Rick And Morty", "RIDE": "Holoride", @@ -10189,16 +11677,23 @@ "RIMBIT": "Rimbit", "RIN": "Aldrin", "RING": "Darwinia Network", + "RINGA": "Ring AI", + "RINGF": "Ring Financial", "RINGX": "RING X PLATFORM", "RINIA": "Rinia Inu", + "RINO": "Rino", + "RINT": "Rin Tin Tin", + "RINTARO": "Rintaro", "RINU": "Raichu Inu", "RIO": "Realio Network", "RIOT": "Riot Racers", + "RIOV1": "Realio Network v1", "RIP": "Fantom Doge", "RIPAX": "RipaEx", "RIPO": "RipOffCoin", "RIPT": "RiptideCoin", "RIPTO": "RiptoBuX", + "RIS": "Riser", "RISE": "EverRise", "RISEP": "Rise Protocol", "RISEVISION": "Rise", @@ -10209,7 +11704,9 @@ "RIVUS": "RivusDAO", "RIYA": "Etheriya", "RIZE": "Rizespor Token", - "RIZO": "Rizo", + "RIZO": "HahaYes", + "RIZOLOL": "Rizo", + "RIZZ": "Rizz", "RJV": "Rejuve.AI", "RKC": "Royal Kingdom Coin", "RKI": "RAKHI", @@ -10221,6 +11718,7 @@ "RLM": "MarbleVerse", "RLOOP": "rLoop", "RLT": "Runner Land", + "RLUSD": "Ripple USD", "RLX": "Relex", "RLY": "Rally", "RMATIC": "StaFi Staked MATIC", @@ -10240,6 +11738,7 @@ "RND": "The RandomDAO", "RNDR": "Render Token", "RNDX": "Round X", + "RNEAR": "Near (Rainbow Bridge)", "RNS": "RenosCoin", "RNT": "OneRoot Network", "RNTB": "BitRent", @@ -10252,6 +11751,8 @@ "ROBIN": "Robin of Da Hood", "ROBINH": "ROBIN HOOD", "ROBO": "RoboHero", + "ROBOTA": "TAXI", + "ROBOTAXI": "ROBOTAXI", "ROC": "Rasputin Online Coin", "ROCCO": "Just A Rock", "ROCK": "Bedrock", @@ -10261,10 +11762,12 @@ "ROCKETFI": "RocketFi", "ROCKI": "Rocki", "ROCKY": "Rocky", + "ROCKYCOIN": "ROCKY", "ROCO": "ROCO FINANCE", "RODAI": "ROD.AI", "ROE": "Rover Coin", "ROG": "ROGin AI", + "ROGER": "ROGER", "ROI": "ROIcoin", "ROK": "Rockchain", "ROKM": "Rocket Ma", @@ -10289,7 +11792,10 @@ "ROS": "ROS Coin", "ROSA": "Rosa Inu", "ROSE": "Oasis Labs", + "ROSEC": "Rosecoin", + "ROSEW": "RoseWifHat", "ROSN": "Roseon Finance", + "ROSS": "Ross Ulbricht", "ROSX": "Roseon", "ROT": "Rotten", "ROTTY": "ROTTYCOIN", @@ -10297,6 +11803,7 @@ "ROUP": "Roup (Ordinals)", "ROUSH": "Roush Fenway Racing Fan Token", "ROUTE": "Router Protocol", + "ROUTEV1": "Router Protocol v1", "ROVI": "ROVI", "ROW": "Rage On Wheels", "ROWAN": "Sifchain", @@ -10310,6 +11817,7 @@ "RPD": "Rapids", "RPEPEc": "RoaringPepe", "RPG": "Rangers Protocol", + "RPGV1": "Rangers Protocol v1", "RPILL": "Red Pill", "RPK": "RepubliK", "RPL": "RocketPool", @@ -10320,9 +11828,11 @@ "RPT": "Rug Proof", "RPTR": "Raptor Finance", "RPUT": "Robin8 Profile Utility Token", + "RPX": "Red Pulse Token", "RPZX": "Rapidz", "RRB": "Renrenbit", "RRC": "Recycling Regeneration Chain", + "RREN": "REN (Rainbow Bridge)", "RRT": "Recovery Right Tokens", "RS": "ReadySwap", "RSC": "ResearchCoin", @@ -10339,18 +11849,22 @@ "RST": "REGA Risk Sharing Token", "RSTK": "Restake Finance", "RSUN": "RisingSun", + "RSUSHI": "Sushi (Rainbow Bridge)", "RSV": "Reserve", "RSWETH": "Restaked Swell Ethereum", "RT2": "RotoCoin", "RTB": "AB-CHAIN", "RTC": "Reltime", + "RTD": "Retard", "RTE": "Rate3", "RTF": "Ready to Fight", "RTH": "Rotharium", "RTK": "RetaFi", "RTM": "Raptoreum", + "RTR": "Restore The Republic", "RTT": "Restore Truth Token", "RU": "RIFI United", + "RUBB": "Rubber Ducky Cult", "RUBCASH": "RUBCASH", "RUBIT": "Rublebit", "RUBX": "eToro Russian Ruble", @@ -10360,17 +11874,21 @@ "RUFF": "Ruff", "RUG": "Rug", "RUGA": "RUGAME", + "RUGPULL": "Captain Rug Pull", "RUGZ": "pulltherug.finance", "RULER": "Ruler Protocol", "RUM": "RUM Pirates of The Arrland Token", "RUN": "Run", "RUNE": "Thorchain", + "RUNEVM": "RUNEVM", + "RUNNER": "Runner", "RUNY": "Runy", "RUP": "Rupee", "RUPX": "Rupaya", "RUSD": "Reflecto USD", "RUSH": "RUSH COIN", "RUSHCMC": "RUSHCMC", + "RUSSELL": "Russell", "RUST": "RustCoin", "RUSTBITS": "Rustbits", "RUTH": "RUTH", @@ -10403,23 +11921,27 @@ "RXT": "RIMAUNANGIS", "RYC": "RoyalCoin", "RYCN": "RoyalCoin 2.0", + "RYD": "RYderOSHI", "RYIU": "RYI Unity", - "RYO": "Ryo", + "RYO": "RYO Coin", + "RYOCURRENCY": "Ryo", "RYOMA": "Ryoma", "RYOSHI": "Ryoshis Vision", "RYU": "The Blue Dragon", "RYZ": "Anryze", "RZR": "RazorCoin", "RedFlokiCEO": "Red Floki CEO", + "S": "Sonic Labs", "S2K": "Sports 2K75", "S315": "SWAP315", "S4F": "S4FE", "S8C": "S88 Coin", "SA": "Superalgos", - "SABAI": "Sabai Ecoverse", + "SABAI": "Sabai Protocol", "SABLE": "Sable Finance", "SABR": "SABR Coin", "SAC1": "Sable Coin", + "SAD": "SadCat", "SAF": "Safinus", "SAFE": "Safe", "SAFEBTC": "SafeBTC", @@ -10429,6 +11951,7 @@ "SAFEHAMSTERS": "SafeHamsters", "SAFELIGHT": "SafeLight", "SAFELUNAR": "SafeLunar", + "SAFEM": "SAFEMOON SOLANA", "SAFEMARS": "Safemars", "SAFEMOO": "SafeMoo", "SAFEMOON": "SafeMoon", @@ -10444,6 +11967,7 @@ "SAFUU": "SAFUU", "SAGA": "Saga", "SAGACOIN": "SagaCoin", + "SAGE": "Ceremonies AI", "SAI": "SAI", "SAIL": "SAIL", "SAITA": "SaitaChain", @@ -10452,6 +11976,7 @@ "SAITAMAV1": "Saitama v1", "SAITANOBI": "Saitanobi", "SAITO": "Saito", + "SAIY": "Saiyan PEPE", "SAK": "SharkCoin", "SAKAI": "Sakai Vault", "SAKATA": "Sakata Inu", @@ -10459,20 +11984,24 @@ "SAL": "SalPay", "SALD": "Salad", "SALE": "DxSale Network", + "SALL": "Sallar", "SALLY": "SALAMANDER", "SALMAN": "Mohameme Bit Salman", "SALMON": "Salmon", "SALT": "Salt Lending", "SAM": "Samsunspor Fan Token", "SAMA": "Moonsama", + "SAMMY": "Samoyed", "SAMO": "Samoyedcoin", "SAN": "Santiment", "SANA": "Storage Area Network Anywhere", + "SANCHO": "Sancho", "SAND": "The Sandbox", "SANDG": "Save and Gain", "SANDWICH": " Sandwich Network", "SANDY": "Sandy", "SANI": "Sanin Inu", + "SANIN": "Sanin", "SANJI": "Sanji Inu", "SANSHU": "Sanshu Inu", "SANTA": "SANTA CHRISTMAS INU", @@ -10487,10 +12016,14 @@ "SARCO": "Sarcophagus", "SAROS": "Saros", "SAS": "Stand Share", + "SASHA": "SASHA CAT", "SASHIMI": "Sashimi", "SAT": "Satisfaction Token", "SAT2": "Saturn2Coin", "SATA": "Signata", + "SATAN": "MrBeast's Cat", + "SATO": "Atsuko Sato", + "SATORI": "Satori Network", "SATOSHINAKAMOTO": "Satoshi Nakamoto", "SATOX": "Satoxcoin", "SATOZ": "Satozhi", @@ -10505,21 +12038,25 @@ "SAUDIPEPE": "SAUDI PEPE", "SAUDISHIB": "Saudi Shiba Inu", "SAUNA": "SaunaFinance Token", + "SAV": "Save America", "SAV3": "SAV3", "SAVG": "SAVAGE", "SAVM": "SatoshiVM", + "SAY": "SAY Coin", "SB": "DragonSB", "SBA": "simplyBrand", "SBABE": "SNOOPYBABE", "SBAE": "Salt Bae For The People", "SBC": "StableCoin", "SBCC": "Smart Block Chain City", + "SBCH": "Smart Bitcoin Cash", "SBE": "Sombe", "SBEFE": "BEFE", "SBET": "SBET", "SBF": "SBF In Jail", "SBGO": "Bingo Share", "SBIO": "Vector Space Biosciences, Inc.", + "SBNB": "Binance Coin (SpookySwap)", "SBOX": "SUIBOXER", "SBR": "Saber", "SBRT": "SaveBritney", @@ -10537,17 +12074,21 @@ "SCAPE": "Etherscape", "SCAR": "Velhalla", "SCARAB": "Scarab Finance", + "SCARCITY": "SCARCITY", "SCASH": "SpaceCash", "SCAT": "Sad Cat Token", "SCC": "StockChain Coin", "SCCP": "S.C. Corinthians Fan Token", "SCDS": "Shrine Cloud Storage Network", + "SCF": "Smoking Chicken Fish", "SCFX": "Shui CFX", "SCH": "SoccerHub", "SCHO": "Scholarship Coin", "SCHR": "Schrodinger", + "SCHRO": "Schrodinger", "SCHRODI": "Schrödi", "SCIA": "Stem Cell", + "SCIHUB": "sci-hub", "SCIVIVE": "sciVive", "SCIX": "Scientix", "SCK": "Space Corsair Key", @@ -10565,6 +12106,7 @@ "SCOR": "Scorista", "SCORE": "Scorecoin", "SCOT": "Scotcoin", + "SCOTT": "Scottish", "SCOTTY": "Scotty Beam", "SCP": "ScPrime", "SCPT": "Script Network", @@ -10577,14 +12119,19 @@ "SCRIV": "SCRIV", "SCRL": "Scroll", "SCRM": "Scorum", + "SCROLL": "Scroll Network", + "SCROLLY": "Scrolly the map", "SCROOGE": "Scrooge", "SCRPT": "ScryptCoin", "SCRT": "Secret", + "SCRVUSD": "Savings crvUSD", "SCRYPTA": "Scrypta", + "SCRYPTTOKEN": "ScryptToken", "SCS": "Solcasino Token", "SCSX": "Secure Cash", - "SCT": "ScryptToken", + "SCT": "SuperCells", "SCTK": "SharesChain", + "SCUBA": "Scuba Dog", "SCY": "Synchrony", "SD": "Stader", "SDA": "SDChain", @@ -10594,6 +12141,7 @@ "SDCRV": "Stake DAO CRV", "SDEX": "SmarDex", "SDL": "Saddle Finance", + "SDME": "SDME", "SDN": "Shiden Network", "SDO": "TheSolanDAO", "SDOG": "Small Doge", @@ -10606,7 +12154,8 @@ "SDT": "TerraSDT", "SDUSD": "SDUSD", "SDX": "SwapDEX", - "SEA": "Second Exchange Alliance", + "SEAGULL": "SEAGULL SAM", + "SEAIO": "Second Exchange Alliance", "SEAL": "Seal Finance", "SEALN": "Seal Network", "SEAM": "Seamless Protocol", @@ -10632,26 +12181,37 @@ "SEG": "Solar Energy", "SEI": "Sei", "SEILOR": "Kryptonite", + "SEIYAN": "Seiyan Token", "SEKAI": "Sekai DAO", + "SEKOIA": "sekoia by Virtuals", "SEL": "SelenCoin", "SELF": "SELFCrypto", + "SELFI": "SelfieSteve", "SELFIE": "SelfieDogCoin", + "SELFIEC": "Selfie Cat", + "SELFT": "SelfToken", "SELLC": "Sell Token", "SEM": "Semux", "SEN": "Sentaro", "SENATE": "SENATE", "SENC": "Sentinel Chain", "SEND": "Social Send", + "SENDOR": "Sendor", "SENK": "Senk", "SENNO": "SENNO", "SENSE": "Sense Token", "SENSI": "Sensi", "SENSO": "SENSO", "SENSOR": "Sensor Protocol", + "SENSOV1": "SENSO v1", + "SENSUS": "Sensus", "SENT": "Sentinel", + "SENTI": "Sentinel Bot Ai", + "SENTR": "Sentre Protocol", "SEON": "Seedon", "SEOR": "SEOR Network", "SEOS": "Smart Eye Operating System", + "SEP": "Smart Energy Pay", "SEPA": "Secure Pad", "SEQ": "Sequence", "SER": "Secretum", @@ -10670,6 +12230,7 @@ "SEW": "simpson in a memes world", "SEX": "SEX Odyssey", "SEXY": "EthXY", + "SEXYP": "SEXY PEPE", "SFARM": "SolFarm", "SFC": "Solarflarecoin", "SFCP": "SF Capital", @@ -10682,9 +12243,11 @@ "SFIT": "Sense4FIT", "SFL": "Sunflower Land", "SFLOKI": "SuiFloki-Inu", + "SFLR": "Sceptre Staked FLR", "SFM": "SafeMoon V2", "SFP": "SafePal", "SFR": "SaffronCoin", + "SFRAX": "Staked FRAX", "SFRC": "Safari Crush", "SFRXETH": "Frax Staked Ether", "SFT": "SportsFix", @@ -10711,12 +12274,14 @@ "SHA": "Safe Haven", "SHACK": "Shackleford", "SHACOIN": "Shacoin", + "SHAD": "Shadowswap Finance", "SHADE": "ShadeCoin", "SHAK": "Shakita Inu", "SHAKE": "Spaceswap SHAKE", "SHAMAN": "Shaman King Inu", "SHAN": "Shanum", "SHANG": "Shanghai Inu", + "SHAR": "Shark Cat", "SHARBI": "SHARBI", "SHARD": "ShardCoin", "SHARDS": "SolChicks Shards", @@ -10725,9 +12290,12 @@ "SHARES": "shares.finance", "SHARK": "Sharky", "SHARKC": "Shark Cat", + "SHARKI": "Sharki", + "SHARP": "Sharp", "SHARPE": "Sharpe Capital", "SHAUN": "SHAUN INU", "SHB4": "Super Heavy Booster 4", + "SHC": "School Hack Coin", "SHD": "ShardingDAO", "SHDW": "Shadow Token", "SHE": "Shine Chain", @@ -10735,6 +12303,7 @@ "SHEEESH": "Secret Gem", "SHEESH": "Sheesh it is bussin bussin", "SHEESHA": "Sheesha Finance", + "SHEGEN": "Aiwithdaddyissues", "SHEI": "SheikhSolana", "SHELL": "Shell Token", "SHEN": "Shen", @@ -10754,6 +12323,7 @@ "SHIBAAI": "SHIBAAI", "SHIBAC": "SHIBA CLASSIC", "SHIBACASH": "ShibaCash", + "SHIBADOG": "Shiba San", "SHIBAI": "AiShiba", "SHIBAKEN": "Shibaken Finance", "SHIBAMOM": "Shiba Mom", @@ -10764,6 +12334,7 @@ "SHIBCAT": "SHIBCAT", "SHIBCEO": "ShibCEO", "SHIBDOGE": "ShibaDoge", + "SHIBEINU": "Shibe Inu", "SHIBELON": "ShibElon", "SHIBEMP": "Shiba Inu Empire", "SHIBGF": "Shiba Girlfriend", @@ -10775,6 +12346,8 @@ "SHIBLITE": "Shiba Lite", "SHIBMERICAN": "Shibmerican", "SHIBO": "ShiBonk", + "SHIBON": "SHIB ON SOLANA", + "SHIBS": "Shibsol", "SHIBTC": "Shibabitcoin", "SHIBU": "SHIBU INU", "SHICO": "ShibaCorgi", @@ -10784,6 +12357,7 @@ "SHIFT": "Shift", "SHIH": "Shih Tzu", "SHIK": "Shikoku", + "SHIKOKU": "Mikawa Inu", "SHIL": "Shila Inu", "SHILL": "SHILL Token", "SHILLD": "SHILLD", @@ -10792,10 +12366,14 @@ "SHINA": "Shina Inu", "SHINJA": "Shibnobi", "SHINO": "ShinobiVerse", + "SHINOB": "Shinobi", "SHINT": "Shiba Interstellar", "SHIP": "ShipChain", + "SHIR": "SHIRO", "SHIRYOINU": "Shiryo-Inu", + "SHISHA": "Shisha Coin", "SHIT": "I will poop it NFT", + "SHITC": "Shitcoin", "SHIV": "Shiva Inu", "SHK": "Shrike", "SHL": "Oyster Shell", @@ -10804,11 +12382,14 @@ "SHNT": "Sats Hunters", "SHO": "Showcase Token", "SHOE": "ShoeFy", + "SHOG": "SHOG", + "SHOGGOTH": "Shoggoth", "SHOKI": "Shoki", "SHON": "ShonToken", "SHOOT": "Mars Battle", "SHOOTER": "Top Down Survival Shooter", "SHOP": "Shoppi Coin", + "SHOPN": "ShopNEXT", "SHOPX": "Splyt", "SHORK": "shork", "SHORTY": "ShortyCoin", @@ -10820,10 +12401,12 @@ "SHRED": "ShredN", "SHREK": "ShrekCoin", "SHRIMP": "SHRIMP", + "SHROO": "Shroomates", "SHROOM": "Shroom.Finance", "SHROOMFOX": "Magic Shroom", "SHRUB": "Shrub", "SHS": "SHEESH", + "SHU": "Shutter", "SHUB": "SimpleHub", "SHUFFLE": "SHUFFLE!", "SHVR": "Shivers", @@ -10841,44 +12424,60 @@ "SIFT": "Smart Investment Fund Token", "SIFU": "SIFU", "SIG": "Signal", + "SIGMA": "SIGMA", "SIGN": "Sign Token", "SIGNA": "Signa", "SIGNAT": "SignatureChain", "SIGT": "Signatum", "SIGU": "Singular", + "SIKA": "SikaSwap", "SIL": "SIL Finance Token V2", "SILK": "SilkCoin", "SILKR": "SilkRoadCoin", "SILKT": "SilkChain", + "SILL": "Silly Duck", "SILLY": "Silly Dragon", "SILO": "Silo Finance", + "SILV": "Silver Surfer Solana", "SILV2": "Escrowed Illuvium 2", "SILVA": "Silva Token", "SILVER": "SILVER", + "SILVERKRC": "Silver KRC-20", + "SILVERSTAND": "Silver Standard", "SILVERWAY": "Silverway", + "SIM": "Simpson", "SIMP": "SO-COL", "SIMPLE": "SimpleChain", + "SIMPS": "Simpson MAGA", + "SIMPSO": "Simpson Neiro", "SIMPSON": "Homer", "SIMPSON6900": "Simpson6900 ", + "SIMPSONF": "Simpson FUKU", + "SIMPSONP": "Simpson Predictions", "SIMPSONSINU": "The Simpsons Inu", + "SIMPSONT": "Simpson Trump", "SIMSOL": "SimSol", "SIN": "Sinverse", "SINE": "Sinelock", "SING": "SingularFarm", "SINGLE": "Single Finance", + "SINK": "Let that sink in", "SINS": "SafeInsure", "SINSO": "SINSO", "SINX": "SINX Token", + "SIO": "SAINO", "SION": "FC Sion", "SIP": "Space SIP", "SIPHER": "Sipher", "SIPHON": "Siphon Life Spell", "SIR": "Sir", + "SIRIUS": "first reply", "SIS": "Symbiosis Finance", "SISA": "Strategic Investments in Significant Areas", "SISC": "Shirushi Coin", "SISHI": "Sishi Finance", "SIU": "Siu", + "SIUU": "SIUUU", "SIUUU": "Crustieno Renaldo", "SIV": "Sivasspor Token", "SIX": "SIX Network", @@ -10888,11 +12487,13 @@ "SJCX": "StorjCoin", "SKAI": "Skillful AI", "SKB": "SkullBuzz", + "SKBDI": "Skibidi Toilet", "SKC": "Skeincoin", "SKCS": "Staked KCS", "SKEB": "Skeb", "SKET": "Sketch coin", "SKEY": "SmartKey", + "SKG888": "Safu & Kek Gigafundz 888", "SKI": "Skillchain", "SKIBIDI": "Skibidi Toilet", "SKID": "Success Kid", @@ -10916,14 +12517,18 @@ "SKT": "Sukhavati Network", "SKU": "Sakura", "SKULL": "Pirate Blocks", - "SKY": "Skycoin", + "SKX": "SKPANAX", + "SKY": "Sky", "SKYA": "Sekuya Multiverse", + "SKYCOIN": "Skycoin", "SKYFT": "SKYFchain", "SKYM": "SkyMap", "SKYRIM": "Skyrim Finance", "SKYX": "SKUYX", "SLA": "SUPERLAUNCH", "SLAM": "Slam Token", + "SLAP": "CatSlap", + "SLAVI": "Slavi Coin", "SLB": "Solberg", "SLC": "Solice", "SLCL": "Solcial", @@ -10934,6 +12539,7 @@ "SLERF2": "SLERF 2.0", "SLERFFORK": "SlerfFork", "SLEX": "SLEX Token", + "SLF": "Self Chain", "SLG": "Land Of Conquest", "SLICE": "Tranche Finance", "SLICEC": "SLICE", @@ -10947,8 +12553,10 @@ "SLND": "Solend", "SLNV2": "SLNV2", "SLOKI": "Super Floki", + "SLOP": "Slop", "SLORK": "SLORK", "SLOTH": "Sloth", + "SLOTHA": "Slothana", "SLP": "Smooth Love Potion", "SLPV1": "Smooth Love Potion v1", "SLR": "SolarCoin", @@ -10957,6 +12565,7 @@ "SLS": "SaluS", "SLST": "SmartLands", "SLT": "Social Lending Network", + "SLUGDENG": "SLUG DENG", "SLUMBO": "SLUMBO", "SLVX": "eToro Silver", "SLX": "Slate", @@ -10967,6 +12576,7 @@ "SMART": "SmartCash", "SMARTB": "Smart Coin", "SMARTCREDIT": "SmartCredit Token", + "SMARTH": "SmartHub", "SMARTLOX": "SmartLOX", "SMARTM": "SmartMesh", "SMARTMEME": "SmartMEME", @@ -10981,15 +12591,18 @@ "SMCW": "Space Misfits", "SMD": "SMD Coin", "SMETA": "StarkMeta", + "SMETX": "SpecialMetalX", "SMF": "SmurfCoin", "SMG": "Smaugs NFT", "SMH": "Spacemesh", "SMI": "SafeMoon Inu", "SMIDGE": "Smidge", + "SMIDGEETH": "Smidge", "SMILE": "Smile Token", "SMILEK": "Smilek to the Bank", "SMILEY": "SMILEY", "SMILY": "Smily Trump", + "SMKNG": "SmonkeyKong", "SML": "Saltmarble", "SMLY": "SmileyCoin", "SMM": "TrendingTool.io", @@ -11018,15 +12631,19 @@ "SMX": "Snapmuse.io", "SN": "SpaceN", "SNA": "SUKUYANA", + "SNAC": "SnackboxAI", "SNACK": "Crypto Snack", "SNAIL": "SnailBrook", + "SNAKE": "snake", "SNAKES": "Snakes Game", "SNAP": "SnapEx", + "SNAPCAT": "Snapcat", "SNB": "SynchroBitcoin", "SNC": "SunContract", "SNCT": "SnakeCity", "SND": "Sandcoin", "SNE": "StrongNode", + "SNEED": "Sneed", "SNEK": "Snek", "SNEKE": "Snek on Ethereum", "SNET": "Snetwork", @@ -11034,6 +12651,9 @@ "SNFTS": "Seedify NFT Space", "SNG": "SINERGIA", "SNGLS": "SingularDTV", + "SNGT": "SNG Token", + "SNIBBU": "Snibbu The Crab", + "SNIFT": "StarryNift", "SNIP": "LyrnAI", "SNIPPEPE": "SNIPING PEPE", "SNITCH": "Randall", @@ -11043,6 +12663,7 @@ "SNMT": "Satoshi Nakamoto Token", "SNN": "SeChain", "SNOB": "Snowball", + "SNOLEX": "Snolex", "SNOOP": "SnoopDAO", "SNOOPY": "Snoopy", "SNORK": "Snork", @@ -11072,20 +12693,25 @@ "SOBA": "SOBA Token", "SOBB": "SoBit", "SOBER": "Solabrador", + "SOBULL": "SoBULL", "SOC": "All Sports Coin", "SOCA": "Socaverse", "SOCC": "SocialCoin", "SOCCER": "SoccerInu", + "SOCIAL": "Phavercoin", "SOCKS": "Unisocks", "SOCOLA": "SOCOLA INU", "SODA": "SODA Coin", + "SODAL": "Sodality Coin", "SODO": "Scooby Doo", + "SOFAC": "SofaCat", "SOFI": "RAI Finance", "SOFTCO": "SOFT COQ INU", "SOH": "Stohn Coin", "SOHOT": "SOHOTRN", "SOIL": "SoilCoin", "SOJ": "Sojourn Coin", + "SOK": "shoki", "SOKU": "Soku Swap", "SOL": "Solana", "SOL10": "SOLANA MEME TOKEN", @@ -11094,21 +12720,27 @@ "SOLALA": "Solala", "SOLAMA": "Solama", "SOLAMB": "SOLAMB", + "SOLAN": "Solana Beach", + "SOLANAP": "Solana Poker", + "SOLANAS": "Solana Swap", "SOLAPE": "SolAPE Token", "SOLAR": "Solar", "SOLARA": "Solara", "SOLARDAO": "Solar DAO", "SOLARE": "Solareum", + "SOLAREU": "Solareum", "SOLARFARM": "SolarFarm", "SOLARIX": "SOLARIX", "SOLAV": "SOLAV TOKEN", "SOLBET": "SOL STREET BETS", + "SOLBO": "SolBoss", "SOLBULL": "SOLBULL", "SOLC": "SolCard", "SOLCASH": "SOLCash", "SOLCAT": "SOLCAT", "SOLCEX": "SolCex", "SOLE": "SoleCoin", + "SOLER": "Solerium", "SOLETF": "SOL ETF", "SOLEX": "Solex Launchpad", "SOLFI": "SoliDefi", @@ -11116,13 +12748,18 @@ "SOLGUN": "Solgun", "SOLID": "Solidified", "SOLIDSEX": "SOLIDsex: Tokenized veSOLID", + "SOLITO": "SOLITO", "SOLKIT": "Solana Kit", "SOLLY": "Solly", + "SOLM": "SolMix", "SOLMATES": "SOLMATES", + "SOLME": "Solmedia", "SOLMEME": "TrumpFFIEGMEBidenCAT2024AMC", "SOLNAV": "SOLNAV AI", "SOLNIC": "Solnic", "SOLO": "Sologenic", + "SOLOR": "Solordi", + "SOLP": "SolPets", "SOLPAD": "Solpad Finance", "SOLPAKA": "Solpaka", "SOLPENG": "SOLPENG", @@ -11130,15 +12767,23 @@ "SOLS": "sols", "SOLSCC": "sols", "SOLSPONGE": "Solsponge", + "SOLT": "Soltalk AI", + "SOLTR": "SolTrump", + "SOLVBTC": "Solv Protocol SolvBTC", + "SOLVBTCBBN": "Solv Protocol SolvBTC.BBN", + "SOLVBTCCORE": "Solv Protocol SolvBTC.CORE", "SOLVE": "SOLVE", "SOLWIF": "Solwif", "SOLX": "SolarX", + "SOLXD": "Solxdex", "SOLY": "Solamander", + "SOLYMPICS": "Solympics", "SOLZILLA": "Solzilla", "SOM": "Souls of Meta", "SOMA": "Soma", "SOMM": "Sommelier", "SOMNIUM": "Somnium Space CUBEs", + "SOMPS": "SompsOnKas", "SON": "Simone", "SONAR": "SonarWatch", "SONG": "Song Coin", @@ -11147,8 +12792,10 @@ "SONICO": "Sonic", "SONICWIF": "SonicWifHat", "SONNE": "Sonne Finance", + "SONOF": "Son of Solana", "SOON": "Soonaverse", "SOONCOIN": "SoonCoin", + "SOOTCASE": "I like my sootcase", "SOP": "SoPay", "SOPHON": "Sophon (Atomicals)", "SOR": "Sorcery", @@ -11176,16 +12823,23 @@ "SP": "Sex Pistols", "SP8DE": "Sp8de", "SPA": "Sperax", + "SPAC": "SPACE DOGE", "SPACE": "Spacelens", "SPACECOIN": "SpaceCoin", + "SPACED": "SPACE DRAGON", "SPACEPI": "SpacePi", "SPAD": "SolPad", "SPAI": "Starship AI", "SPAIN": "SpainCoin", "SPANK": "SpankChain", + "SPARK": "Sparklife", + "SPARKLET": "Upland", "SPARKO": "Sparko", "SPARTA": "Spartan Protocol Token", + "SPARTACATS": "SpartaCats", + "SPARTAD": "SpartaDex", "SPAT": "Meta Spatial", + "SPAVAX": "Avalanche (Synapse Protocol)", "SPAY": "SpaceY 2025", "SPC": "SpaceChain ERC20", "SPC.QRC": "SpaceChain (QRC-20)", @@ -11198,6 +12852,7 @@ "SPEC": "SpecCoin", "SPECT": "Spectral", "SPECTRE": "SPECTRE AI", + "SPEE": "SpeedCash", "SPEEDY": "Speedy", "SPELL": "Spell Token", "SPELLFIRE": "Spellfire", @@ -11228,7 +12883,9 @@ "SPIKE": "Spiking", "SPILLWAYS": "SpillWays", "SPIN": "SPIN Protocol", + "SPINT": "Spintria", "SPIRIT": "SpiritSwap", + "SPITT": "Hawk Ttuuaahh", "SPIZ": "SPACE-iZ", "SPK": "SparksPay", "SPKL": "SpokLottery", @@ -11246,9 +12903,10 @@ "SPOODY": "Spoody Man", "SPOOF": "Spoofify", "SPOOL": "Spool DAO Token", - "SPORE": "Enoki Finance", + "SPORE": "Spore", "SPORT": "SportsCoin", "SPORTS": "ZenSports", + "SPORTSP": "SportsPie", "SPOTS": "Spots", "SPOX": "Sports Future Exchange Token", "SPRING": "Spring", @@ -11261,6 +12919,8 @@ "SPS": "Splinterlands", "SPT": "SPECTRUM", "SPUME": "Spume", + "SPUNK": "PUNK", + "SPURD": "Spurdo Spärde", "SPURDO": "spurdo", "SPURS": "Tottenham Hotspur Fan Token", "SPWN": "Bitspawn", @@ -11270,10 +12930,12 @@ "SPYRO": "SPYRO", "SQAT": "Syndiqate", "SQG": "Squid Token", + "SQGROW": "SquidGrow", "SQL": "Squall Coin", "SQR": "Magic Square", "SQT": "SubQuery Network", "SQTS": "Sqts (Ordinals)", + "SQU": "SquadSwap", "SQUA": "Square Token", "SQUAD": "Superpower Squad", "SQUATCH": "SASQUATCH", @@ -11284,7 +12946,10 @@ "SQUID2": "Squid Game 2.0", "SQUIDGROW": "SquidGrow", "SQUIDGROWV1": "SquidGrow v1", + "SQUIDV1": "Squid Game v1", + "SQUIDW": "Squidward Coin", "SQUOGE": "DogeSquatch", + "SR30": "SatsRush", "SRBP": "Super Rare Ball Potion", "SRC": "SecureCoin", "SRCH": "SolSrch", @@ -11314,10 +12979,13 @@ "SSHIP": "SSHIP", "SSLX": "StarSlax", "SSNC": "SatoshiSync", + "SSOL": "Solayer SOL", "SSS": "StarSharks", + "SSSSS": "Snake wif Hat", "SST": "SIMBA Storage Token", "SSTC": "SunShotCoin", "SSU": "Sunny Side up", + "SSUI": "Spring Staked SUI", "SSV": "ssv.network", "SSVCOIN": "SSVCoin", "SSVV1": "Blox", @@ -11325,6 +12993,7 @@ "SSX": "SOMESING", "ST": "Skippy Token", "STA": "STOA Network", + "STAB": "STABLE ASSET", "STABLZ": "Stablz", "STAC": "STAC", "STACK": "StackOS", @@ -11335,6 +13004,7 @@ "STAKEDETH": "StakeHound Staked Ether", "STALIN": "StalinCoin", "STAMP": "SafePost", + "STAN": "Stank Memes", "STANDARD": "Stakeborg DAO", "STAPT": "Ditto Staked Aptos", "STAR": "FileStar", @@ -11351,6 +13021,7 @@ "STARSHI": "Starship", "STARSHIP": "STARSHIP", "STARSHIPDOGE": "Starship Doge", + "STARSHIPONSOL": "Starship", "START": "StartCoin", "STARTA": "Starta", "STARWARS": "Star Wars", @@ -11360,6 +13031,8 @@ "STATE": "New World Order", "STATER": "Stater", "STATERA": "Statera", + "STATOK": "STA", + "STATOKEN": "STA", "STATOM": "Stride Staked ATOM", "STATS": "Stats", "STAX": "Staxcoin", @@ -11373,6 +13046,7 @@ "STEAK": "SteakHut Finance", "STEALTH": "StealthPad", "STEAMPUNK": "SteamPunk", + "STEAMX": "Steam Exchange", "STEEM": "Steem", "STEEMD": "Steem Dollars", "STEEP": "SteepCoin", @@ -11390,6 +13064,7 @@ "STEWIE": "Stewie Coin", "STEX": "STEX", "STF": "Structure Finance", + "STFLOW": "Increment Staked FLOW", "STFX": "STFX", "STG": "Stargate Finance", "STHR": "Stakerush", @@ -11399,12 +13074,14 @@ "STIMA": "STIMA", "STING": "Sting", "STINJ": "Stride Staked INJ", + "STIX": "STIX", "STJUNO": "Stride Staked JUNO", "STK": "STK Token", "STKAAVE": "Staked Aave", "STKATOM": "pSTAKE Staked ATOM", "STKBNB": "pSTAKE Staked BNB", "STKC": "Streakk Chain", + "STKD": "Stkd SCRT", "STKHUAHUA": "pSTAKE Staked HUAHUA", "STKK": "Streakk", "STKSTARS": "pSTAKE Staked STARS", @@ -11416,16 +13093,19 @@ "STND": "Standard Protocol", "STNEAR": "Staked NEAR", "STO": "Save The Ocean", + "STOC": "STO Cash", "STOG": "Stooges", "STOGE": "Stoner Doge Finance", "STOIC": "stoicDAO", "STON": "STON", "STONE": "Stone Token", + "STONEDE": "Stone DeFi", "STONK": "STONK", "STONKS": "HarryPotterObamaWallStreetBets10Inu", "STOP": "SatoPay", "STOR": "Self Storage Coin", "STORE": "Bit Store", + "STOREP": "Storepay", "STORJ": "Storj", "STORM": "Storm", "STORY": "Story", @@ -11437,7 +13117,9 @@ "STPT": "STP Network", "STQ": "Storiqa Token", "STR": "Sourceless", + "STRA": "STRAY", "STRAKS": "Straks", + "STRAT": "Strategic Hub for Innovation in Blockchain", "STRAX": "Stratis", "STRAY": "Stray Dog", "STRD": "Stride", @@ -11451,6 +13133,7 @@ "STRM": "StreamCoin", "STRNGR": "Stronger", "STRONG": "Strong", + "STRONGSOL": "Stronghold Staked SOL", "STRONGX": "StrongX", "STRP": "Strips Finance", "STRS": "STARS", @@ -11471,6 +13154,7 @@ "STUCK": "mouse in pasta", "STUD": "Studyum", "STUDENTC": "Student Coin", + "STUFF": "STUFF.io", "STUMEE": "Stride Staked UMEE", "STUSDT": "Staked USDT", "STV": "Sativa Coin", @@ -11483,6 +13167,7 @@ "STZETA": "ZetaEarn", "STZU": "Shihtzu Exchange Token", "SU": "Smol Su", + "SUB": "Subsocial", "SUBAWU": "Subawu Token", "SUBF": "Super Best Friends", "SUBS": "Substratum Network", @@ -11491,58 +13176,96 @@ "SUGAR": "Sugar Exchange", "SUI": "Sui", "SUIA": "SUIA", + "SUIB": "Suiba Inu", + "SUIJAK": "Suijak", + "SUILAMA": "Suilama", + "SUIMAN": "Suiman", + "SUIMON": "Sui Monster", "SUIP": "SuiPad", "SUISHIB": "SuiShiba", + "SUITE": "Suite", + "SUKI": "SUKI", "SUKU": "SUKU", "SULFERC": "SULFERC", "SUM": "SumSwap", + "SUMI": "SUMI", "SUMMER": "Summer", + "SUMMIT": "Summit", "SUMO": "Sumokoin", "SUN": "Sun Token", "SUNC": "Sunrise", "SUNDAE": "Sundae the Dog", + "SUNDOG": "SUNDOG", "SUNEX": "The Sun Exchange", + "SUNGOAT": "SUNGOAT", + "SUNGOU": "Sungou", "SUNI": "SUNI", + "SUNJAK": "Sunjak", + "SUNLION": "SUNLION", + "SUNMAGA": "SunMaga", + "SUNN": "Sunny on Tron", + "SUNNED": "SUNNED", + "SUNNEIRO": "SunNeiro", "SUNNY": "Sunny Aggregator", "SUNOLD": "Sun Token", + "SUNPEPE": "sunpepe", + "SUNPUMP": "To The Sun", + "SUNTRON": "TRON MASCOT", "SUNV1": "Sun Token v1", + "SUNWUKONG": "SunWukong", "SUP": "Supcoin", "SUP8EME": "SUP8EME Token", "SUPE": "Supe Infinity", "SUPER": "SuperVerse", "SUPERBID": "SuperBid", + "SUPERBONK": "SUPER BONK", "SUPERC": "SuperCoin", + "SUPERCAT": "SUPERCAT", + "SUPERF": "SUPER FLOKI", + "SUPEROETHB": "Super OETH", + "SUPERT": "Super Trump", "SUPERTX": "SuperTX", + "SUPR": "SuperDapp", "SUR": "Suretly", "SURE": "inSure", "SURF": "Surf.Finance", "SURV": "Survival Game Online", "SUSD": "sUSD", + "SUSDA": "sUSDa", "SUSDE": "Ethena Staked USDe", + "SUSDX": "Staked USDX", "SUSHI": "Sushi", + "SUSX": "Savings USX", "SUTEKU": "Suteku", "SUTER": "Suterusu", + "SUWI": "suwi", "SUZUME": "Shita-kiri Suzume", "SVD": "savedroid", + "SVETH": "Savvy ETH", "SVL": "Slash Vision Labs", "SVN": "Savanna", "SVNN": "Savanna Haus", "SVPN": "Shadow Node", "SVS": "GivingToServices SVS", "SVT": "Solvent", + "SVTS": "Syncvault", "SVX": "Savix", "SVY": "Savvy", "SWA": "Swace", "SWACH": "Swachhcoin", "SWAG": "SWAG Finance", + "SWAGGY": "swaggy", + "SWAGT": "Swag Token", "SWAI": "Safe Water AI", "SWAMP": "Swampy", + "SWAN": "Black Swan", "SWAP": "Trustswap", "SWAPP": "SWAPP Protocol", "SWAPZ": "SWAPZ.app", "SWARM": "SwarmCoin", "SWASH": "Swash", "SWAY": "Sway Social", + "SWBTC": "Swell Restaked BTC", "SWC": "Scanetchain Token", "SWCH": "SwissCheese", "SWD": "SW DAO", @@ -11550,11 +13273,14 @@ "SWEAT": "Sweat Economy", "SWEEP": "Sweeptoken", "SWEET": "SweetStake", + "SWELL": "Swell Network", "SWETH": "swETH", "SWFL": "Swapfolio", "SWFTC": "SWFTCoin", "SWG": "Swirge", + "SWGT": "SmartWorld Global", "SWH": "simbawifhat", + "SWIF": "SUNwifHat", "SWIFT": "BitSwift", "SWIFTIES": "Taylor Swift", "SWIM": "SWIM - Spread Wisdom", @@ -11564,12 +13290,14 @@ "SWIPES": "BNDR", "SWIRL": "Swirl Social", "SWIRLX": "SwirlToken", + "SWIS": "Swiss Cash Coin", "SWISE": "StakeWise", "SWITCH": "Switch", "SWM": "Swarm Fund", "SWOLE": "Swole Doge", "SWOP": "Swop", "SWORD": "eZKalibur", + "SWORLD": "Seedworld", "SWOT": "Swot AI", "SWP": "Kava Swap", "SWPR": "Swapr", @@ -11594,6 +13322,7 @@ "SYBL": "Sybulls", "SYBTC": "sBTC", "SYC": "SynchroCoin", + "SYK": "Stryke", "SYL": "XSL Labs", "SYLO": "Sylo", "SYLV": "Sylvester", @@ -11601,15 +13330,18 @@ "SYN": "Synapse", "SYNC": "Syncus", "SYNCC": "SyncCoin", + "SYNCG": "SyncGPT", "SYNCN": "Sync Network", "SYNCO": "Synco", "SYNLEV": "SynLev", "SYNO": "Synonym Finance", "SYNR": "MOBLAND", "SYNT": "Synthetix Network", + "SYNTE": "Synternet", "SYNTH": "Synthswap", "SYNX": "Syndicate", "SYPOOL": "Sypool", + "SYRUP": "Syrup", "SYS": "Syscoin", "SZCB": "Zugacoin", "T": "Threshold Network Token", @@ -11620,8 +13352,10 @@ "TABOO": "Taboo Token", "TAC": "Traceability Chain", "TACHYON": "Tachyon Protocol", - "TAD": "Tadpole Finance", + "TAD": "Tadpole", "TADA": "Ta-da", + "TADDY": "DADDY TRUMP", + "TADPOLEF": "Tadpole Finance", "TAF": "TAF", "TAGR": "Think And Get Rich Coin", "TAI": "TARS Protocol", @@ -11631,8 +13365,13 @@ "TAIYO": "Taiyo", "TAJ": "TajCoin", "TAK": "TakCoin", + "TAKE": "Take America Back", "TAKI": "Taki", + "TALA": "Baby Tala", + "TALAHON": "Talahon", "TALAO": "Talao", + "TALENT": "Talent Protocol", + "TALES": "Tales of Pepe", "TALIS": "Talis Protocol", "TALK": "Talken", "TAMA": "Tamadoge", @@ -11643,8 +13382,11 @@ "TANK": "CryptoTanks", "TANPIN": "Tanpin", "TANUKI": "Tanuki", + "TANUPAD": "Tanuki Launchpad", "TAO": "Bittensor", "TAONU": "TAO INU", + "TAOP": "TaoPad", + "TAOTOOLS": "TAOTools", "TAP": "TAP FANTASY", "TAPC": "Tap Coin", "TAPPINGCOIN": "TappingCoin", @@ -11663,6 +13405,7 @@ "TAT": "Tatcoin", "TATA": "TATA Coin", "TATE": "Tate", + "TATES": "Tate Stop", "TATSU": "Taτsu", "TAU": "Lamden Tau", "TAUC": "Taurus Coin", @@ -11670,6 +13413,7 @@ "TAUR": "Marnotaur", "TAVA": "ALTAVA", "TAX": "MetaToll", + "TAXI": "Robotaxi", "TBAC": "BlockAura", "TBANK": "TaoBank", "TBAR": "Titanium BAR", @@ -11680,6 +13424,7 @@ "TBCX": "TrashBurn", "TBD": "THE BIG DEBATE", "TBE": "TrustBase", + "TBEER": "TRON BEER", "TBFT": "Türkiye Basketbol Federasyon Token", "TBIS": "TBIS token", "TBL": "Tombola", @@ -11687,9 +13432,11 @@ "TBT": "T-BOT", "TBTC": "tBTC", "TBTCV1": "tBTC v1", + "TBULL": "Tron Bull", "TBX": "Tokenbox", "TCANDY": "TripCandy", "TCAP": "Total Crypto Market Cap", + "TCASH": "Trump Cash", "TCAT": "The Currency Analytics", "TCC": "The ChampCoin", "TCG": "Today's Crypto", @@ -11708,12 +13455,13 @@ "TCT": "TokenClub", "TCX": "T-Coin", "TCY": "The Crypto You", - "TD": "Trade Chain", + "TD": "The Big Red", "TDAN": "TDAN", "TDE": "Trade Ecology Token", "TDEFI": "Token Teknoloji A.S. Token DeFi", "TDFB": "TDFB", "TDFY": "Tidefi", + "TDM": "TDM", "TDP": "TrueDeck", "TDROP": "ThetaDrop", "TDS": "TokenDesk", @@ -11748,6 +13496,7 @@ "TENET": "TENET", "TENFI": "TEN", "TENNET": "Tennet", + "TENS": "TensorScan", "TENSHI": "Tenshi", "TENT": "TENT", "TEP": "Tepleton", @@ -11756,12 +13505,17 @@ "TERA": "TERA", "TERADYNE": "Teradyne", "TERAR": "Terareum", + "TERAV1": "Terareum v1", "TERAWATT": "Terawatt", + "TERM": "Terminal of Simpson", + "TERMINAL": "Book Terminal of Truths", + "TERMINUS": "Terminus", "TERN": "Ternio", "TERN.ETH": "Ternio ERC20", "TERR": "Terrier", "TERRA": "Terraport", "TERRAB": "TERRABYTE AI", + "TERRY": "Terry The Disgruntled Turtle", "TERZ": "SHELTERZ", "TES": "TeslaCoin", "TESLA": "TeslaCoilCoin", @@ -11774,6 +13528,7 @@ "TETRA": "Tetra", "TETU": "TETU", "TEW": "Trump in a memes world", + "TF47": "Trump Force 47", "TFBX": "Truefeedback Token", "TFC": "The Freedom Coin", "TFI": "TrustFi Network Token", @@ -11787,34 +13542,49 @@ "TGCC": "TheGCCcoin", "TGPT": "Trading GPT", "TGRAM": "TG20 TGram", + "TGRASS": "Top Grass Club", "TGT": "TargetCoin", + "TGW": "The Green World", "TH": "Team Heretics Fan Token", "THALES": "Thales", + "THAPT": "Thala APT", "THAVAGE": "Mike Tython", "THC": "The Hempcoin", + "THD": "Trump Harris Debate", "THE": "The Protocol", "THE9": "THE9", + "THEAICOIN": "AI", + "THEB": "The Boys Club", "THEBLOX": "The Blox Project", + "THEC": "The CocktailBar", "THECA": "Theca", + "THECAT": "THECAT", "THECITADEL": "The Citadel", "THEDAO": "The DAO", + "THEF": "The Flash Currency", + "THEG": "The GameHub", "THEHARAMBE": "Harambe", + "THEM": "The Meta DAO", "THEMIS": "Themis", "THEN": "THENA", "THEO": "Theopetra", "THEOS": "Theos", + "THES": "The Standard Protocol (USDS)", "THETA": "Theta Network", + "THETAN": "Thetan Coin", "THETRIBE": "The Tribe", "THEX": "Thore Exchange", "THG": "Thetan Arena", "THIK": "ThikDik", "THING": "Nothing", "THINKWAREAI": "ThinkwareAI", + "THISISF": "This is Fine", "THL": "Thala", "THN": "Throne", "THNX": "ThankYou", "THO": "Athero", "THOL": "AngelBlock", + "THOLA": "Tholana", "THOR": "THORSwap", "THOREUM": "Thoreum V3", "THP": "TurboHigh Performance", @@ -11825,6 +13595,7 @@ "THS": "TechShares", "THT": "Thought", "THUG": "Thug Life", + "THUN": "Thunder Brawl", "THUNDER": "ThunderStake", "THX": "Thorenext", "TI": "Titanium22", @@ -11832,11 +13603,14 @@ "TIANHE": "Tianhe", "TIC": "TrueInvestmentCoin", "TIDAL": "Tidal Finance", + "TIDDIES": "TIDDIES", "TIDE": "Tidalflats", "TIE": "Ties Network", + "TIEDAN": "TieDan", + "TIF": "This Is Fine", "TIFI": "TiFi Token", "TIG": "Tigereum", - "TIGER": "JungleKing TigerCoin", + "TIGER": "TIGER", "TIGERC": "TigerCash", "TIGERMOON": "TigerMoon", "TIGRA": "Tigra", @@ -11847,6 +13621,7 @@ "TIKTOKEN": "TikToken", "TIM": "TIMTIM GAMES", "TIME": "Chrono.tech", + "TIMES": "DARKTIMES", "TIMI": "Timicoin", "TIN": "Token IN", "TINC": "Tiny Coin", @@ -11855,6 +13630,7 @@ "TINY": "TinyBits", "TIOX": "TIOx", "TIP": "Tip Blockchain", + "TIPC": "Tipcoin", "TIPINU": "Tip Inu", "TIPS": "FedoraCoin", "TIPSY": "TipsyCoin", @@ -11865,6 +13641,7 @@ "TITANX": "TitanX", "TITC": "TitCoin", "TITI": "TiTi Protocol", + "TITS": "We Love Tits", "TITTY": "TamaKitty", "TIUSD": "TiUSD", "TIX": "Blocktix", @@ -11876,7 +13653,7 @@ "TKING": "Tiger King", "TKINU": "Tsuki Inu", "TKMN": "Tokemon", - "TKN": "Monolith", + "TKN": "Token Name Service", "TKO": "Tokocrypto", "TKP": "TOKPIE", "TKR": "CryptoInsight", @@ -11891,6 +13668,7 @@ "TLOS": "Telos", "TLP": "TulipCoin", "TLW": "TILWIKI", + "TMAGA": "THE MAGA MOVEMENT", "TMANIA": "Trump Mania", "TME": "Timereum", "TMED": "MDsquare", @@ -11899,6 +13677,7 @@ "TMNG": "TMN Global", "TMNT": "TMNT", "TMON": "Two Monkey Juice Bar", + "TMPL": "TMPL", "TMRW": "TMRW Coin", "TMSH": "Bursaspor Fan Token", "TMT": "Tamy Token", @@ -11922,6 +13701,7 @@ "TODD": "TURBO TODD", "TOK": "Tokenplace", "TOKA": "Tonka Finance", + "TOKAMAK": "Tokamak Network", "TOKAU": "Tokyo AU", "TOKC": "Tokyo Coin", "TOKE": "Tokemak", @@ -11931,6 +13711,7 @@ "TOKKI": "CRYPTOKKI", "TOKO": "ToKoin", "TOKU": "TokugawaCoin", + "TOKUD": "Tokuda", "TOL": "Tolar", "TOLO": "Tolo Yacoloco", "TOLYCAT": "Toly's Cat", @@ -11938,48 +13719,64 @@ "TOMAHAWKCOIN": "Tomahawkcoin", "TOMAN": "IRR", "TOMB": "Tomb", + "TOMC": "TOM CAT", "TOMI": "tomiNet", "TOMOE": "TomoChain ERC20", "TOMS": "TomTomCoin", - "TON": "Tokamak Network", + "TON": "Toncoin", "TONALD": "Tonald Trump", - "TONCOIN": "The Open Network", "TONE": "TE-FOOD", "TONI": "Daytona Finance", "TONIC": "Tectonic", "TONK": "Tonk Inu", "TONNEL": "TONNEL Network", "TONS": "TONSniper", + "TONST": "Ton Stars", + "TONT": "TONKIT", "TONTOKEN": "TONToken", "TONUP": "TonUP", "TONY": "TONY THE DUCK", "TOOB": "Toobcoin", + "TOOBIGTORIG": "Too Big To Rig", "TOOKER": "tooker kurlson", "TOOLS": "TOOLS", "TOON": "Pontoon", "TOONF": "Toon Finance", "TOPC": "Topchain", + "TOPCA": "TOP CAT", + "TOPCAT": "Topcat", "TOPG": "Tate Token", + "TOPGP": "TOP G PEPE", + "TOPI": "Topi Meme", "TOPIA": "Hytopia", "TOPN": "TOP Network", "TOR": "TOR", + "TORA": "TORA NEKO", + "TORCH": "Hercules Token", "TORE": "Toreus Finance", "TORG": "TORG", "TORI": "Teritori", "TORII": "Torii Finance", "TORN": "Tornado Cash", + "TORO": "Toro Inoue", + "TORSY": "TORSY", "TOS": "ThingsOperatingSystem", "TOSA": "TosaInu BSC", "TOSC": "T.OS", "TOSDIS": "TosDis", "TOSHE": "Toshe", "TOSHI": "Toshi", + "TOSHKIN": "Toshkin Coin", "TOT": "TotCoin", "TOTEM": "DragonMaster", "TOTM": "Totem", "TOTO": "TOTO", "TOUCHFAN": "TouchFan", + "TOUCHG": "Touch Grass", + "TOUR": "Tour Billion", + "TOURI": "Tourist Token", "TOURISTS": "TOURIST SHIBA INU", + "TOWELI": "Towelie", "TOWER": "Tower", "TOWN": "Town Star", "TOX": "INTOverse", @@ -12006,12 +13803,16 @@ "TRACN": "trac (Ordinals)", "TRADE": "Polytrade", "TRADEBOT": "TradeBot", + "TRADECHAIN": "Trade Chain", "TRADEX": "TradeX AI", "TRAID": "Traid", + "TRAIMP": "TRUMP AI", "TRAIN": "Trump Train", "TRAK": "TrakInvest", + "TRALA": "TRALA", "TRANQ": "Tranquil Finance", "TRANS": "Trans Pepe", + "TRANSFER": "TransferCoin", "TRAT": "Tratok", "TRAVA": "Trava Finance", "TRAXIA": "Traxia Membership Token", @@ -12036,6 +13837,7 @@ "TRET": "Tourist Review", "TRG": "The Rug Game", "TRGI": "The Real Golden Inu", + "TRHUB": "Tradehub", "TRI": "Triangles Coin", "TRIA": "Triaconta", "TRIAS": "Trias", @@ -12048,18 +13850,28 @@ "TRINI": "Trinity Network Credit", "TRIO": "Tripio", "TRIPAD": "TripAdvisor, Inc.", + "TRITON": "Triton", "TRIVIA": "Trivians", "TRIX": "TriumphX", "TRK": "TruckCoin", + "TRKX": "Trakx", "TRL": "Triall", "TRMX": "TourismX Token", "TRNDZ": "Trendsy", + "TRNGUY": "Tron Guy Project", "TROG": "Trog", + "TROGE": "Troge", "TROLL": "Trollcoin", "TROLLHEIM": "Trollheim", + "TROLLICTO": "TROLLI CTO", "TROLLMODE": "TROLL MODE", + "TROLLS": "trolls in a memes world", + "TRONDOG": "TronDog", + "TRONI": "Tron Inu", + "TRONP": "Donald Tronp", "TRONPAD": "TRONPAD", "TROP": "Interop", + "TROPPY": "TROPPY", "TROSS": "Trossard", "TROVE": "Arbitrove Governance Token", "TROY": "Troy", @@ -12070,35 +13882,59 @@ "TRTL": "TurtleCoin", "TRTT": "Trittium", "TRU": "TrueFi", + "TRUAPT": "TruFin Staked APT", "TRUCE": "WORLD PEACE PROJECT", "TRUE": "True Chain", "TRUEBIT": "Truebit Protocol", "TRUF": "Truflation", + "TRUFV1ERC20": "Truflation v1 ERC-20", "TRUM": "TrumpBucks", "TRUMAGA": "TrumpMAGA", "TRUMATIC": "TruFin Staked MATIC", "TRUMP": "MAGA", + "TRUMP2": "Trump2024", "TRUMP2024": "Donald Trump", + "TRUMP3": "Trump MP3", + "TRUMP47": "47th President of the United States", + "TRUMPA": "TRUMP AI", + "TRUMPAMANIA": "TRUMPAMANIA", "TRUMPARMY": "Trump Army", + "TRUMPBASE": "MAGA (magatrumponbase.tech)", "TRUMPBIDEN": "Trump vs Biden", + "TRUMPC": "TrumpCat", + "TRUMPCA": "Trump Card", "TRUMPCAT": "TRUMPCAT", + "TRUMPCATS": "Trump Golden Cat", "TRUMPCOIN": "TrumpCoin", + "TRUMPDAO": "TRUMP DAO", "TRUMPDO": "TRUMP", "TRUMPDOGE": "Trump Doge", "TRUMPE": "Trump Pepe", "TRUMPEPE": "Trump Pepe", + "TRUMPER": "Trump Era", + "TRUMPF": "Trump Fight", "TRUMPHAT": "Trump Hat", "TRUMPINU": "Trump Inu", + "TRUMPJ": "TRUMPJR", "TRUMPJR": "TrumpJr", + "TRUMPM": "TRUMP MAGA PRESIDENT", + "TRUMPMA": "TRUMP MAGA SUPER", + "TRUMPMAGA": "President Trump MAGA", + "TRUMPONBASE": "TRUMP ON BASE", + "TRUMPS": "Trump SOL", + "TRUMPSB": "TrumpsBags", + "TRUMPSFIGHT": "TrumpsFight", "TRUMPSHIBA": "Trump Shiba", "TRUMPTECH": "Trump Tech", "TRUMPTITANS": "TrumpTitans", + "TRUMPVANCE": "Trump Vance 2024", "TRUMPX": "Trump X-Maga", "TRUMPZ": "Trump Zhong", "TRUNK": "Elephant Money", "TRUST": "TrustDAO", "TRUSTNFT": "TrustNFT", "TRUTH": "TruthGPT", + "TRUTHFI": "Truthfi", "TRV": "TrustVerse", "TRVC": "Trivechain", "TRVL": "TRVL", @@ -12107,6 +13943,7 @@ "TRXC": "TRONCLASSIC", "TRXDICE": "TRONdice", "TRXS": "Staked TRX", + "TRXV1": "TRON V1", "TRXWIN": "TronWin", "TRYB": "BiLira", "TRYC": "TRYC", @@ -12122,10 +13959,12 @@ "TSHARE": "Tomb Shares", "TSHP": "12Ships", "TSL": "Energo", + "TSLT": "Tamkin", "TSN": "Tsunami Exchange Token", "TSR": "Tesra", "TSUBASAUT": "TSUBASA Utility Token", "TSUGT": "Captain Tsubasa", + "TSUJI": "Tsutsuji", "TSUKA": "Dejitaru Tsuka", "TSX": "TradeStars", "TT": "ThunderCore", @@ -12135,8 +13974,10 @@ "TTM": "To The Moon", "TTN": "Titan Coin", "TTT": "The Transfer Token", + "TTTU": "T-Project", "TTU": "TaTaTu", "TTV": "TV-TWO", + "TUA": "Atua AI", "TUBE": "BitTube", "TUBES": "TUBES", "TUCKER": "TUCKER CARLSON", @@ -12148,20 +13989,24 @@ "TUNE": "Bitune", "TUP": "Tenup", "TUR": "Turron", - "TURBO": "Turbo Wallet", + "TURB": "TurboX", + "TURBO": "Turbo", + "TURBOB": "Turbo Browser", "TURBOS": "Turbos Finance", - "TURBOT": "Turbo", + "TURBOW": "Turbo Wallet", "TURT": "TurtSat", "TUS": "Treasure Under Sea", "TUSD": "True USD", "TUSDV1": "True USD v1", "TUT": "Tutellus", "TUTTER": "Tutter", + "TUX": "Tux The Penguin", "TUZKI": "Tuzki", "TUZLA": "Tuzlaspor Token", "TVK": "Terra Virtua Kolect", "TVNT": "TravelNote", "TVRS": "TiraVerse", + "TVS": "TVS", "TW": "Winners Coin", "TWC": "Twilight", "TWD": "Terra World Token", @@ -12169,7 +14014,9 @@ "TWEETY": "Tweety", "TWELVE": "TWELVE ZODIAC", "TWEP": "The Web3 Project", + "TWIF": "Tomwifhat", "TWIFB": "TrumpWifBiden", + "TWIGGY": "Twiggy", "TWIN": "Twinci", "TWIST": "TwisterCoin", "TWLV": "Twelve Coin", @@ -12177,12 +14024,14 @@ "TWOGE": "Twoge Inu", "TWP": "TrumpWifPanda", "TWT": "Trust Wallet Token", + "TWURTLE": "twurtle the turtle", "TX": "Tradix", "TX20": "Trex20", "TXA": "TXA", "TXAG": "tSILVER", "TXAU": "tGOLD", "TXBIT": "Txbit Token", + "TXC": "TEXITcoin", "TXG": "TRUSTxGAMING", "TXL": "Autobahn Network", "TXT": "TuneTrade", @@ -12191,14 +14040,19 @@ "TYBGSc": "Base Goddess", "TYC": "Tycoon", "TYCOON": "CryptoTycoon", + "TYKE": "Tyke The Elephant", + "TYLER": "Tyler", "TYOGHOUL": "TYO GHOUL", "TYPE": "TypeAI", "TYPERIUM": "Typerium", + "TYPUS": "Typus", "TYRANT": "Fable Of The Dragon", "TYRION": "Tyrion", + "TYSON": "Mike Tyson", "TYT": "Tianya Token", "TZC": "TrezarCoin", "TZKI": "Tsuzuki Inu", + "TZU": "Sun Tzu", "U": "Unidef", "U8D": "Universal Dollar", "UAEC": "United Arab Emirates Coin", @@ -12240,6 +14094,7 @@ "UDOO": "Hyprr", "UDS": "Undeads Games", "UDT": "Unlock Protocol", + "UE": "UE Coin", "UEC": "United Emirates Coin", "UEDC": "United Emirate Decentralized Coin", "UENC": "UniversalEnergyChain", @@ -12252,6 +14107,7 @@ "UFO": "UFO Gaming", "UFOC": "Unknown Fair Object", "UFOCOIN": "Uniform Fiscal Object", + "UFOP": "UFOPepe", "UFR": "Upfiring", "UFT": "UniLend Finance", "UGAS": "Ultrain", @@ -12273,6 +14129,7 @@ "ULTI": "Ultiverse", "ULTIMA": "Ultima", "ULTIMATEBOT": "Ultimate Tipbot", + "ULTR": "ULTRA MAGA", "ULTRA": "Ultra", "ULTRAP": "ULTRA Prisma Finance", "ULX": "ULTRON", @@ -12284,7 +14141,10 @@ "UMBR": "Umbria Network", "UMC": "Umbrella Coin", "UMI": "Universal Money Instrument", + "UMID": "Umi Digital", + "UMJA": "Umoja", "UMK": "UMKA", + "UMM": "UMM", "UMMA": "UMMA Token", "UMO": "Universal Molecule", "UMT": "UnityMeta", @@ -12296,14 +14156,17 @@ "UNBREAKABLE": "UnbreakableCoin", "UNC": "UnCoin", "UNCL": "UNCL", + "UNCN": "Unseen", "UNCX": "UniCrypt", "UND": "United Network Distribution", "UNDB": "unibot.cash", + "UNDE": "Undead Finance", "UNDEAD": "Undead Blocks", "UNDG": "UniDexGas", "UNDX": "UNODEX", "UNF": "Unfed Coin", "UNFI": "Unifi Protocol DAO", + "UNFK": "UNFK", "UNI": "Uniswap Protocol Token", "UNIBOT": "Unibot", "UNIC": "Unicly", @@ -12311,13 +14174,16 @@ "UNICORN": "UNICORN Token", "UNIDEXAI": "UniDexAI", "UNIDX": "UniDex", + "UNIE": "Uniswap Protocol Token (Avalanche Bridge)", "UNIETH": "Universal ETH", "UNIFY": "Unify", "UNIM": "Unicorn Milk", + "UNIO": "Unio Coin", "UNIQ": "Uniqredit", "UNIQUE": "Unique One", "UNISTAKE": "Unistake", "UNIT": "Universal Currency", + "UNIT0": "UNIT0", "UNITARYSTATUS": "UnitaryStatus Dollar", "UNITED": "UnitedCoins", "UNITRADE": "UniTrade", @@ -12370,11 +14236,15 @@ "URS": "URUS", "URUS": "Urus Token", "URX": "URANIUMX", - "USA": "DEDPRZ", + "USA": "Based USA", + "USACOIN": "American Coin", "USAT": "USAT", + "USBT": "Universal Blockchain", "USC": "Ultimate Secure Cash", "USCC": "USC", "USCOIN": "USCoin", + "USD0": "Usual", + "USD3": "Web 3 Dollar", "USDA": "USDA", "USDAP": "Bond Appetite USD", "USDB": "USD Bancor", @@ -12382,6 +14252,14 @@ "USDBLAST": "USDB Blast", "USDC": "USD Coin", "USDCASH": "USDCASH", + "USDCAT": "UpSideDownCat", + "USDCAV": "USD Coin (Portal from Avalanche)", + "USDCBS": "USD Coin (Portal from BSC)", + "USDCE": "USD Coin (Avalanche Bride)", + "USDCEAV": "USD.e Coin (Portal from Avalanche)", + "USDCET": "USD Coin (Portal from Ethereum)", + "USDCPO": "USD Coin (PoS) (Portal from Polygon)", + "USDCSO": "USD Coin (Portal from Solana)", "USDD": "USDD", "USDE": "Ethena USDe", "USDEBT": "USDEBT", @@ -12392,16 +14270,20 @@ "USDI": "Interest Protocol USDi", "USDJ": "USDJ", "USDK": "USDK", + "USDL": "Lift Dollar", "USDM": "Mountain Protocol", + "USDMA": "USD mars", "USDN": "Neutrino USD", "USDO": "USD Open Dollar", "USDP": "Pax Dollar", "USDPLUS": "Overnight.fi USD+", "USDQ": "USDQ", "USDR": "Real USD", - "USDS": "StableUSD", + "USDS": "Sky Dollar", "USDSB": "USDSB", + "USDSTABLY": "StableUSD", "USDT": "Tether", + "USDTBASE": "USDT (Base)", "USDTV": "TetherTV", "USDTZ": "USDtez", "USDU": "Upper Dollar", @@ -12411,6 +14293,7 @@ "USDZ": "Zedxion USDZ", "USE": "Usechain Token", "USEDCAR": "A Gently Used 2001 Honda", + "USETH": "USETH", "USG": "USGold", "USH": "unshETHing_Token", "USHARK": "uShark", @@ -12421,22 +14304,30 @@ "USNBT": "NuBits", "USNOTA": "NOTA", "USP": "USP Token", + "USPEPE": "American pepe", "USPLUS": "Fluent Finance", + "USR": "Resolv USR", + "USSD": "Autonomous Secure Dollar", "UST": "Wrapped UST Token", "USTB": "Superstate Short Duration U.S. Government Securities Fund", + "USTBL": "Spiko US T-Bills Money Market Fund", "USTC": "TerraClassicUSD", "USTCW": "TerraClassicUSD Wormhole", "USTX": "UpStableToken", + "USUAL": "Usual", "USV": "Universal Store of Value", "USX": "USX Quantum", + "USYC": "Hashnote USYC", "UT": "Ulord", "UTBAI": "UTB.ai", "UTC": "UltraCoin", "UTG": "UltronGlow", "UTH": "Uther", + "UTHX": "Utherverse", "UTI": "Unicorn Technology International", "UTIL": "Utility Coin", "UTK": "Utrust", + "UTKV1": "Utrust", "UTMDOGE": "UltramanDoge", "UTNP": "Universa", "UTT": "United Traders Token", @@ -12450,6 +14341,7 @@ "UWU": "UwU Lend", "UWUCOIN": "uwu", "UX": "Umee", + "UXLINK": "UXLINK", "UXOS": "UXOS", "UXP": "UXD Protocol", "UZUMAKI": "Uzumaki Inu", @@ -12467,11 +14359,14 @@ "VALID": "Validator Token", "VALOR": "Valor Token", "VALORBIT": "Valorbit", + "VALU": "Value", "VALUE": "Value Liquidity", "VAMPIRE": "Vampire Inu", "VAN": "Vanspor Token", "VANA": "Nirvana", "VANCAT": "Vancat", + "VANCE": "JD Vance", + "VANF": "Van Fwogh", "VANRY": "Vanar Chain", "VANT": "Vanta Network", "VANY": "Vanywhere", @@ -12480,6 +14375,7 @@ "VARA": "Vara Network", "VARIUS": "Varius", "VARK": "Aardvark", + "VATO": "vanitis", "VATR": "Vatra INU", "VATRENI": "Croatian FF Fan Token", "VAULT": "Vault Tech", @@ -12538,11 +14434,13 @@ "VEMP": "vEmpire DDAO", "VEN": "VeChain Old", "VENA": "Vena Network", + "VENKO": "VENKO", "VENOM": "Venom", "VENOMAI": "VENOM", "VENT": "Vent Finance", "VENTI": "VentiSwap", "VENTION": "Vention", + "VENTU": "Venture Coin", "VENUS": "VenusEnergy", "VEO": "Amoveo", "VER": "VersalNFT", @@ -12553,6 +14451,7 @@ "VERSA": "Versa Token", "VERSACE": "VERSACE", "VERSE": "Verse", + "VERTAI": "Vertical AI", "VERTEX": "Vertex", "VERUM": "Verum Coin", "VERVE": "Verve", @@ -12569,6 +14468,7 @@ "VFIL": "Venus Filecoin", "VFOX": "VFOX", "VFT": "Value Finance", + "VG": "Viu Ganhou", "VGO": "Vagabond", "VGX": "Voyager Token", "VHC": "Vault Hill City", @@ -12576,6 +14476,7 @@ "VIA": "ViaCoin", "VIB": "Viberate", "VIBE": "VIBEHub", + "VIBEA": "Vibe AI", "VIBLO": "VIBLO", "VIC": "Viction", "VICA": "ViCA Token", @@ -12585,6 +14486,7 @@ "VICTORIUM": "Victorium", "VID": "VideoCoin", "VIDA": "Vidiachange", + "VIDEO": "Videocoin by Drakula", "VIDT": "VIDT Datalink", "VIDY": "Vidy", "VIDYA": "Vidya", @@ -12593,6 +14495,7 @@ "VIEW": "Viewly", "VIG": "TheVig", "VIK": "VIKTAMA", + "VIKITA": "VIKITA", "VIKKY": "VikkyToken", "VIM": "VicMove", "VIN": "VinChain", @@ -12611,18 +14514,24 @@ "VISIO": "Visio", "VISION": "VisionGame", "VISR": "Visor", + "VIST": "VISTA", + "VISTA": "Ethervista", + "VISTADOG": "VISTADOG", "VIT": "Vision Industry Token", "VITA": "VitaDAO", "VITAE": "Vitae", "VITAFAST": "Molecules of Korolchuk IP-NFT", "VITAL": "Vital Network", + "VITALI": "Vitalik's Casper", "VITE": "VITE", "VITRA": "Vitra Studios", "VITY": "Vitteey", "VIU": "Viuly", + "VIVEK": "Head of D.O.G.E", "VIVID": "Vivid Coin", "VIVO": "VIVO Coin", "VIX": "VIXCO", + "VIX7": "VIX777", "VIXV1": "VIXCO v1", "VIZ": "Vision City", "VIZION": "ViZion Protocol", @@ -12652,6 +14561,7 @@ "VNM": "Venom", "VNN": "VINU Network", "VNO": "Veno Finance", + "VNST": "VNST Stablecoin", "VNT": "VNT Chain", "VNTW": "Value Network Token", "VNX": "VisionX", @@ -12660,9 +14570,12 @@ "VNY": "Vanity", "VOCARE": "Vocare ex Machina", "VOCO": "Provoco", + "VODCAT": "VODKA CAT", "VODKA": "Vodka Token", + "VOIP": "Voip Finance", "VOISE": "Voise", "VOL": "Volume Network", + "VOLBOOST": "VolBoost", "VOLLAR": "Vollar", "VOLR": "Volare Network", "VOLT": "Volt Inu", @@ -12731,6 +14644,7 @@ "VTN": "Voltroon", "VTOS": "VTOS", "VTRA": " E.C. Vitoria Fan Token", + "VTRAD": "VTRADING", "VTRO": "Vitruveo DEX", "VTRUMP": "Vote Trump", "VTRX": "Venus TRX", @@ -12742,18 +14656,22 @@ "VUC": "Virta Unique Coin", "VULC": "Vulcano", "VUNI": "Venus UNI", + "VUSD": "Virtual USD", "VUZZ": "Vuzz AI", "VV": "Virtual Versions", + "VVAIFU": "Dasha", "VVI": "VV Coin", "VVS": "VVS Finance", "VX": "ViteX Coin", "VXL": "Voxel X Network", + "VXR": "Vox Royale", "VXRP": "Venus XRP", "VXT": "Voxto Amplify", "VXV": "Vectorspace AI", "VYBE": "Vybe", "VYFI": "VyFinance", "VYNC": "VYNK Chain", + "VYPER": "VYPER.WIN", "VZT": "Vezt", "W": "Wormhole", "W1": "W1", @@ -12764,12 +14682,15 @@ "W3S": "Web3Shot", "W3W": "Web3 Whales", "W8BIT": "8Bit Chain", + "WAAC": "Wrapped AyeAyeCoin", "WAB": "WABnetwork", "WABI": "WABI", + "WABU": "Warrenbuffett", "WACME": "Wrapped Accumulate", "WACO": "Waste Digital Coin", "WAD": "WardenSwap", "WADA": "Wrapped Cardano", + "WAFC": "Wrapped Arsenal FC (Kayen)", "WAFFLES": "Waffles Davincij15's Cat", "WAG": "WagyuSwap", "WAGE": "Digiwage", @@ -12785,8 +14706,11 @@ "WAIFU": "Waifu", "WAIT": "Hourglass", "WAL": "The Wasted Lands", + "WALE": "Waletoken", "WALK": "Walk Token", + "WALL": "Du Rove's Wall", "WALLET": "Ambire Wallet", + "WALLI": "WALLi", "WALLY": "Wally Bot", "WALTER": "walter", "WALV": "Alvey Chain", @@ -12796,9 +14720,11 @@ "WANA": "Wanaka Farm", "WANATHA": "Wrapped ANATHA", "WAND": "WandX", + "WANK": "Wojak The Wanker", "WANKO": "WANKO•MANKO•RUNES", "WANNA": "Wanna Bot", "WANUSDT": "wanUSDT", + "WAP": "Wet Ass Pussy", "WAR": "WeStarter", "WARP": "WarpCoin", "WARPED": "Warped Games", @@ -12811,16 +14737,22 @@ "WASSIE": "WASSIE", "WASTR": "Wrapped Astar", "WAT": "Wat", + "WATC": "WATCoin", + "WATCH": "Yieldwatch", "WATER": "doginwotah", "WAVAX": "Wrapped AVAX", "WAVES": "Waves", + "WAVL": "Wrapped Aston Villa", + "WAWA": "Wawa Cat", "WAXE": "WAXE", "WAXL": "Wrapped Axelar", "WAXP": "Worldwide Asset eXchange", + "WAXS": "Axie Infinity Shards (Wormhole)", "WAY": "WayCoin", "WAZ": "MikeAI", "WBB": "Wild Beast Coin", "WBBC": "Wibcoin", + "WBC": "WorldBrain Coin", "WBCH": "Wrapped Bitcoin Cash", "WBESC": "Wrapped BESC", "WBET": "Wavesbet", @@ -12832,6 +14764,7 @@ "WBOND": "War Bond Token", "WBONE": "Shibarium Wrapped BONE", "WBONES": "Wrapped BONES", + "WBONK": "BONK (Portal Bridge)", "WBS": "Websea", "WBT": "WhiteBIT Token", "WBTC": "Wrapped Bitcoin", @@ -12851,11 +14784,13 @@ "WCKB": "Wrapped Nervos Network", "WCOIN": "WCoin", "WCORE": "Wrapped Core", + "WCRO": "Wrapped CRO", "WCS": "Weecoins", "WCSOV": "Wrapped CrownSterling", "WCT": "Waves Community Token", "WCT1WCT1": "Wrapped Car Token 1", "WCUSD": "Wrapped Celo Dollar", + "WDAI": "Dai (Wormhole)", "WDC": "WorldCoin", "WDOG": "Winterdog", "WDOGE": "Wrapped Dogecoin", @@ -12877,31 +14812,41 @@ "WEC": "Whole Earth Coin", "WECO": "WECOIN", "WED": "Wednesday Inu", + "WEEBS": "Weebs", "WEETH": "Wrapped eETH", + "WEEX": "WEEX Token", "WEF": "DOG WIF CHINESE HAT", "WEFI": "WeFi", "WEGEN": "WeGen Platform", "WEGI": "Wegie", "WEGLD": "Wrapped EGLD", + "WEHMND": "Wrapped eHMND", "WEIRDO": "Weirdo", + "WEL": "Welsh Corgi", "WELA": "Wrapped Elastos", "WELD": "Weld", "WELL": "Moonwell", "WELLTOKEN": "Well", + "WELLV1": "Moonwell v1", "WELSH": "Welshcorgicoin", "WELT": "Fabwelt", "WELUPS": "Welups Blockchain", "WEMIX": "WEMIX", "WEMIXUSD": "WEMIX", "WEN": "Wen", + "WEND": "Wellnode", + "WENIS": "WenisCoin", "WENLAMBO": "Wenlambo", "WEOS": "Wrapped EOS", + "WEPC": "World Earn & Play Community", "WEST": "Waves Enterprise", "WET": "WeShow Token", "WETH": "WETH", "WETHV1": "WETH v1", "WETHW": "Wrapped EthereumPoW", "WEVE": "veDAO", + "WEVER": "Wrapped Ever", + "WEVERV1": "Wrapped Ever v1", "WEVMOS": "Wrapped Evmos", "WEWE": "WEWE", "WEX": "WaultSwap", @@ -12909,11 +14854,13 @@ "WEXPOLY": "WaultSwap Polygon", "WFAI": "WaifuAI", "WFBTC": "Wrapped Fantom Bitcoin", + "WFDP": "WFDP", "WFIL": "Wrapped Filecoin", "WFLAMA": "WIFLAMA", "WFLOW": "Wrapped Flow", "WFO": "WoofOracle", "WFT": "Windfall Token", + "WFTM": "Wrapped Fantom", "WFTN": "Wrapped FTN", "WFUSE": "Wrapped Fuse", "WFX": "WebFlix", @@ -12926,14 +14873,20 @@ "WGR": "Wagerr", "WGRT": "WaykiChain Governance Coin", "WGT": "Web3Games.com", + "WHA": "WHALES DOGE", + "WHAL": "WHALEBERT", "WHALE": "WHALE", "WHALES": "Whales Market", + "WHAT": "What the Duck", "WHBAR": "Wrapped HBAR", + "WHC": "Whales Club", "WHEAT": "Wheat Token", "WHEE": "WHEE (Ordinals)", "WHEEL": "Wheelers", "WHEN": "WhenHub", "WHEX": "Whale Exploder", + "WHI": "White Boy Summer", + "WHINE": "Whine Coin", "WHIRL": "Whirl Finance", "WHISK": "Whiskers", "WHISKEY": "WHISKEY", @@ -12945,18 +14898,26 @@ "WHTETGRMOON": "WHITE TIGER MOON", "WHTGRPXL": "White Tiger Pixel", "WHX": "WHITEX", + "WHY": "WHY", + "WHYCAT": "WhyCat", "WIB": "Wibson", + "WIBE": "Wibegram", "WIC": "Wi Coin", "WICC": "WaykiChain", + "WICKED": "Wicked", "WIF": "dogwifhat", "WIF2": "DogWif2.0", "WIFB": "dogwifball", + "WIFC": "dogwifceo", + "WIFCAT": "WIFCAT COIN", "WIFE": "Wifejak", + "WIFEAR": "TRUMP WIF EAR", "WIFEDOGE": "Wifedoge", "WIFI": "WiFi Map", "WIFICOIN": "Wifi Coin", "WIFS": "dogwifscarf", "WIFSA": "dogwifsaudihat", + "WIGL": "Wigl", "WIGO": "WigoSwap", "WIK": "Wicked Bet", "WIKEN": "Project WITH", @@ -12964,14 +14925,18 @@ "WILC": "Wrapped ILCOIN", "WILD": "Wilder World", "WILDC": "Wild Crypto", + "WILDCOIN": "WILDCOIN", "WIN": "WINk", + "WINB": "WINBIT CASINO", "WINE": "WineCoin", "WING": "Wing Finance", "WINGS": "Wings DAO", "WINK": "Wink", "WINN": "Winnerz", + "WINNIE": "Winnie the Poodle", "WINR": "JustBet", "WINRY": "Winry Inu", + "WINSTON": "Winston", "WINT": "WinToken", "WINTER": "Winter", "WINU": "Walter Inu", @@ -12986,6 +14951,7 @@ "WIT": "Witnet", "WITCH": "Witch", "WITCOIN": "Witcoin", + "WIWI": "Wiggly Willy", "WIX": "Wixlar", "WIZA": "Wizardia", "WJD": "WJD", @@ -12998,6 +14964,7 @@ "WKD": "Wakanda Inu", "WLD": "Worldcoin", "WLF": "Wolfs Group", + "WLFI": "World Liberty Financial", "WLITI": "wLITI", "WLK": "Wolk", "WLKN": "Walken", @@ -13010,9 +14977,11 @@ "WMB": "WatermelonBlock", "WMC": "WMCoin", "WMEMO": "Wonderful Memories", + "WMETIS": "Wrapped Metis", "WMF": "Whale Maker Fund", "WMINIMA": "Wrapped Minima", "WMLX": "Millix", + "WMM": "Weird Medieval Memes", "WMN": "WebMind Network", "WMNT": "Wrapped Mantle", "WMOXY": "Moxy", @@ -13042,14 +15011,16 @@ "WOJ": "Wojak Finance", "WOJAK": "Wojak", "WOJAK2": "Wojak 2.0 Coin", + "WOJAKC": "Wojak Coin", "WOKB": "Wrapped OKB", "WOKT": "Wrapped OKT", "WOL": "World of Legends", - "WOLF": "Landwolf", + "WOLF": "LANDWOLF (AVAX)", "WOLFILAND": "Wolfiland", "WOLFOF": "Wolf of Wall Street", "WOLFP": "Wolfpack Coin", "WOLFY": "WOLFY", + "WOLT": "Wolt", "WOLVERINU": "WOLVERINU", "WOM": "WOM", "WOMB": "Wombat Exchange", @@ -13069,16 +15040,21 @@ "WOOO": "wooonen", "WOOOOO": "Wooooo! Coin", "WOOP": "Woonkly Power", + "WOOPV1": "Woonkly Power", "WOP": "WorldPay", "WOR": "Hollywood Capital Group WARRIOR", "WORK": "Work X", + "WORKE": "Worken", + "WORL": "World Record Banana", "WORLD": "World Token", "WORM": "HealthyWorm", "WORX": "Worx", "WOS": "Wolf Of Solana", + "WOT": "World Of Trump", "WOW": "WOWswap", "WOWS": "Wolves of Wall Street", "WOZX": "Efforce", + "WPAY": "WPAY", "WPC": "WePiggy Coin", "WPE": "OPES (Wrapped PE)", "WPEPE": "Wrapped Pepe", @@ -13086,6 +15062,7 @@ "WPKT": "Wrapped PKT", "WPLS": "Wrapped Pulse", "WPOKT": "wrapped POKT", + "WPOR": "Wrapped Portugal National Team", "WPP": "Green Energy Token", "WPR": "WePower", "WQT": "Work Quest", @@ -13108,7 +15085,9 @@ "WSDOGE": "Doge of Woof Street", "WSG": "Wall Street Games", "WSGV1": "Wall Street Games v1", - "WSHIB": "wShiba", + "WSH": "White Yorkshire", + "WSHIB": "Wrapped Shiba Inu (Wormhole)", + "WSHIBA": "wShiba", "WSI": "WeSendit", "WSIENNA": "Sienna ERC20", "WSM": "Wall Street Memes", @@ -13116,12 +15095,14 @@ "WSTA": "Wrapped Statera", "WSTETH": "Lido wstETH", "WSTOR": "StorageChain", + "WSTORV1": "StorageChain v1", "WSTR": "Wrapped Star", "WSTUSDT": "wstUSDT", "WSX": "WeAreSatoshi", "WT": "WeToken", "WTAO": "Wrapped TAO", "WTC": "Waltonchain", + "WTE": "Wonder Energy Technology", "WTF": "Waterfall Governance", "WTFT": "WTF Token", "WTFUEL": "Wrapped TFUEL", @@ -13134,40 +15115,54 @@ "WTT": "Giga Watt", "WTWOOL": "Wolf Town Wool", "WUF": "WUFFI", + "WUK": "WUKONG", + "WUKONG": "Sun Wukong", "WUSD": "Worldwide USD", "WUST": "Wrapped UST Token", + "WVG0": "Wrapped Virgin Gen-0 CryptoKittties", "WVTRS": "Vitreus", "WW3": "WW3", "WWAN": "Wrapped WAN", "WWB": "Wowbit", + "WWBNB": "Wrapped BNB (Wormhole)", "WWD": "Wolf Works DAO", "WWDOGE": "Wrapped WDOGE", "WWEMIX": "WWEMIX", "WWF": "WWF", + "WWMATIC": "Wrapped Polygon (Wormhole)", + "WWRY": "WeWillRugYou", "WWY": "WeWay", "WX": "WX Token", "WXDAI": "Wrapped XDAI", "WXDC": "Wrapped XDC", + "WXM": "WeatherXM", + "WXRP": "Wrapped XRP", "WXT": "WXT", "WXTZ": "Wrapped Tezos", + "WYN": "Wynn", "WYNN": "Anita Max Wynn", "WYS": "Wysker", + "WYZ": "WYZth", "WZEC": "Wrapped Zcash", "WZEDX": "Wrapped Zedxion", "WZENIQ": "Wrapped Zeniq (ETH)", "WZETA": "Wrapped Zeta", "WZM": "Woozoo Music", + "WZNN": "Wrapped Zenon (Zenon Bridge)", + "WZNNV1": "Wrapped Zenon (Zenon Bridge) v1", "WZRD": "Bitcoin Wizards", - "X": "AI-X", + "X": "X Empire", "X2": "X2Coin", "X2Y2": "X2Y2", "X42": "X42 Protocol", + "X7": "X7", "X7C": "X7 Coin", "X7DAO": "X7DAO", "X7R": "X7R", "X8X": "X8Currency", "XACT": "XactToken", "XAEAXII": "XAEA-Xii Token", + "XAGX": "Silver Token", "XAH": "Xahau", "XAI": "Xai", "XALGO": "Wrapped ALGO", @@ -13179,6 +15174,7 @@ "XAS": "Asch", "XAT": "ShareAt", "XAUC": "XauCoin", + "XAUM": "Matrixdock Gold", "XAUR": "Xaurum", "XAUT": "Tether Gold", "XAVA": "Avalaunch", @@ -13219,6 +15215,7 @@ "XCG": "Xchange", "XCH": "Chia", "XCHF": "CryptoFranc", + "XCHNG": "Chainge Finance", "XCI": "Cannabis Industry Coin", "XCLR": "ClearCoin", "XCM": "CoinMetro", @@ -13283,16 +15280,19 @@ "XG": "XG Sports", "XGB": "GoldenBird", "XGC": "Xiglute Coin", + "XGD": "X Gold", "XGEM": "Exchange Genesis Ethlas Medium", "XGLI": "Glitter Finance", "XGOLD": "XGOLD COIN", "XGOX": "Go!", + "XGP": "XGP", "XGPT": "XGPT", "XGR": "GoldReserve", "XGRO": "Growth DeFi", "XGT": "Xion Finance", "XHI": "HiCoin", "XHP": "XHYPE", + "XHPV1": "XHYPE v1", "XHT": "HollaEx", "XHV": "Haven Protocol", "XI": "Xi", @@ -13302,6 +15302,7 @@ "XIDR": "XIDR", "XIL": "Xillion", "XIN": "Mixin", + "XING": "Xing Xing", "XINU": "XINU", "XIO": "Blockzero Labs", "XIOS": "Xios", @@ -13320,6 +15321,7 @@ "XLN": "LunaOne", "XLQ": "Alqo", "XLR": "Solaris", + "XLS": "Elis", "XLT": "Nexalt", "XM": "xMooney", "XMARK": "xMARK", @@ -13338,11 +15340,13 @@ "XMS": "Megastake", "XMT": "MetalSwap", "XMV": "MoneroV", + "XMW": "Morphware", "XMX": "XMax", "XMY": "MyriadCoin", "XNA": "Neurai", "XNB": "Xeonbit", "XNC": "Xenios", + "XNET": "XNET Mobile", "XNFT": "xNFT Protocol", "XNG": "Enigma", "XNK": "Ink Protocol", @@ -13361,6 +15365,7 @@ "XOT": "Okuru", "XOV": "XOVBank", "XOX": "XOX Labs", + "XOXNO": "XOXNO", "XP": "Experience Points", "XPA": "XPA", "XPAT": "Bitnation Pangea", @@ -13408,6 +15413,7 @@ "XRISE": "Xrise", "XRL": "Rialto.AI", "XRLM": "xRealm.ai", + "XROCK": "xRocket", "XROOTAI": "XRootAI", "XRP": "XRP", "XRP2": "XRP2.0", @@ -13416,6 +15422,7 @@ "XRPAYNET": "XRPayNet", "XRPC": "Xrp Classic", "XRPCHAIN": "Ripple Chain", + "XRPEPE": "XRPEPE", "XRPH": "XRP Healthcare", "XRS": "Xrius", "XRT": "Robonomics Network", @@ -13457,7 +15464,9 @@ "XTRA": "ExtraCredit", "XTRACK": "Xtrack AI", "XTREME": "ExtremeCoin", + "XTREMEV": "Xtremeverse", "XTRM": "XTRM COIN", + "XTRUMP": "X TRUMP", "XTT": "XSwap Treasure", "XTTB20": "XTblock", "XTUSD": "XT Stablecoin XTUSD", @@ -13470,6 +15479,7 @@ "XUP": "UPGRADE", "XUPS": "Xups", "XUV": "XUV Coin", + "XV": "XV", "XVC": "Vcash", "XVE": "The Vegan Initiative", "XVG": "Verge", @@ -13488,11 +15498,14 @@ "XYM": "Symbol", "XYO": "XY Oracle", "XYZ": "Universe.XYZ", + "XZK": "Mystiko Network", + "Y24": "Yield 24", "Y2K": "Y2K", "Y8U": "Y8U", "YAC": "YAcCoin", "YACHT": "YachtingVerse", "YAE": "Cryptonovae", + "YAFA": "Free Palestine", "YAG": "Yaki Gold", "YAI": "Ÿ", "YAK": "Yield Yak", @@ -13506,6 +15519,7 @@ "YAP": "Yap Stone", "YARL": "Yarloo", "YAW": "Yawww", + "YAWN": "YAWN", "YAXIS": "yAxis", "YAY": "YAY Games", "YAYCOIN": "YAYcoin", @@ -13519,6 +15533,7 @@ "YDF": "Yieldification", "YDOGE": "Yorkie Doge", "YDR": "YDragon", + "YEARN": "YearnTogether", "YEC": "Ycash", "YEE": "Yeeco", "YEED": "Yggdrash", @@ -13542,7 +15557,8 @@ "YFFI": "yffi finance", "YFFII": "YFFII Finance", "YFI": "yearn.finance", - "YFIE": "YFIEXCHANGE.FINANCE", + "YFIE": "yearn.finance (Avalanche Bridge)", + "YFIEXCHANGE": "YFIEXCHANGE.FINANCE", "YFII": "DFI.money", "YFIII": "Dify.Finance", "YFIVE": "YFIVE FINANCE", @@ -13553,16 +15569,19 @@ "YFV": "YFValue", "YFX": "Your Futures Exchange", "YGG": "Yield Guild Games", + "YIDO": "Yidocy Plus", "YIELD": "Yield Protocol", "YIELDX": "Yield Finance", "YIKES": "Yikes Dog", "YIN": "YIN Finance", "YINBI": "Yinbi", + "YLAY": "Yelay", "YLC": "YoloCash", "YLD": "YIELD App", "YLDY": "Yieldly", "YMC": "YamahaCoin", "YMS": "Yeni Malatyaspor Token", + "YNETH": "YieldNest Restaked ETH", "YO": "Yobit Token", "YOBASE": "All Your Base", "YOC": "YoCoin", @@ -13571,18 +15590,24 @@ "YODE": "YodeSwap", "YOLO": "YoloNolo", "YOM": "YOM", + "YONNY": "YONNY", "YOOSHI": "YooShi", "YOP": "Yield Optimization Platform & Protocol", + "YORAN": "YORAN THE CAVALIER", + "YORI": "YORI", "YOSHI": "Yoshi.exchange", "YOTD": "Year of the Dragon", "YOTO": "yotoshi", "YOU": "YOU Chain", "YOUC": "yOUcash", + "YOUNES": "YOUNES", "YOURAI": "YOUR AI", + "YOURMOM": "YOUR MOM DOG", "YOVI": "YobitVirtualCoin", "YOYOW": "Yoyow", "YPC": "YoungParrot", "YPIE": "PieDAO Yearn Ecosystem Pie", + "YPRISMA": "Yearn yPRISMA", "YSAFE": "yieldfarming.insure", "YSEC": "Yearn Secure", "YSR": "Ystar", @@ -13592,25 +15617,31 @@ "YTS": "YetiSwap", "YU": "BOUNTYKINDS", "YUANG": "Yuang Coin", + "YUCHEN": "Sun Yuchen", "YUCJ": "Yu Coin", "YUCT": "Yucreat", "YUDI": "Yudi", "YUGE": "YUGE COIN", "YUKI": "YUKI", + "YUKIE": "Yukie", "YUKKY": "YUKKY", "YUM": "Yumerium", "YUMMI": "Yummi Universe", "YUMMY": "Yummy", "YUP": "Crowdholding", "YURI": "YURI", + "YUSD": "YUSD Stablecoin", "YUSE": "Yuse Token", "YUSRA": "YUSRA", + "YUSUF": "Yusuf Dikec Meme", "YUZU": "YuzuSwap", "YVBOOST": "Yearn Compounding veCRV yVault", "YVS": "YVS.Finance", + "YVYFI": "YFI yVault", "YYAVAX": "Yield Yak AVAX", "YYE": "YYE Energy", "YYFI": "YYFI.Protocol", + "YYOLO": "yYOLO", "Z3": "Z-Cubed", "ZABAKU": "Zabaku Inu", "ZACK": "Zack Morris", @@ -13623,10 +15654,14 @@ "ZAO": "zkTAO", "ZAP": "Zap", "ZAPI": "Zapicorn", + "ZAPO": "Zapo AI", "ZARP": "ZARP Stablecoin", "ZARX": "eToro South African Rand", "ZASH": "ZIMBOCASH", "ZAT": "ZatGo", + "ZAZA": "ZAZA", + "ZAZU": "Zazu", + "ZAZZLES": "Zazzles", "ZB": "ZB", "ZBC": "Zebec Protocol", "ZBCN": "Zebec Network", @@ -13634,6 +15669,7 @@ "ZBU": "Zeebu", "ZCC": "ZCC Coin", "ZCC1": "ZeroCarbon", + "ZCD": "ZChains", "ZCG": "ZCashGOLD", "ZCHF": "Frankencoin", "ZCHN": "Zichain", @@ -13646,12 +15682,15 @@ "ZCULT": "Zkcult", "ZCX": "Unizen", "ZDAI": "Zydio AI", + "ZDC": "Zodiacs", + "ZDCV2": "ZodiacsV2", "ZDEX": "Zeedex", "ZDR": "Zloadr", "ZEBU": "ZEBU", "ZEC": "ZCash", "ZECD": "ZCashDarkCoin", - "ZED": "ZedCoins", + "ZED": "ZED Token", + "ZEDCOIN": "ZedCoin", "ZEDD": "ZedDex", "ZEDTOKEN": "Zed Token", "ZEDX": "ZEDXION", @@ -13669,11 +15708,14 @@ "ZENI": "Zennies", "ZENIQ": "Zeniq Coin", "ZENITH": "Zenith Chain", + "ZENQ": "Zenqira", "ZENT": "Zentry", "ZEON": "Zeon Network", "ZEP": "Zeppelin Dao", "ZEPH": "Zephyr Protocol", "ZER": "Zero", + "ZEREBRO": "Zerebro", + "ZERO": "ZeroLend", "ZEROB": "ZeroBank", "ZEROEX": "0.exchange", "ZES": "Zetos", @@ -13686,7 +15728,9 @@ "ZETRIX": "Zetrix", "ZEUM": "Colizeum", "ZEUS": "Zeus Network", + "ZEUSPEPES": "Zeus", "ZEXI": "ZEXICON", + "ZEXY": "ZEXY", "ZF": "zkSwap Finance ", "ZFL": "Zuflo Coin", "ZFLOKI": "zkFloki", @@ -13694,6 +15738,7 @@ "ZGD": "ZambesiGold", "ZGEM": "GemSwap", "ZHC": "ZHC : Zero Hour Cash", + "ZHOA": "Chengpang Zhoa", "ZIBU": "Zibu", "ZIG": "Zignaly", "ZIGAP": "ZIGAP", @@ -13719,6 +15764,7 @@ "ZKARCH": "zkArchive", "ZKB": "ZKBase", "ZKBOB": "BOB", + "ZKCRO": "Cronos zkEVM CRO", "ZKDOGE": "zkDoge", "ZKDX": "ZKDX", "ZKE": "zkEra Finance", @@ -13730,6 +15776,7 @@ "ZKID": "zkSync id", "ZKIN": "zkInfra", "ZKJ": "Polyhedra Network", + "ZKL": "zkLink", "ZKLAB": "zkSync Labs", "ZKLK": "ZkLock", "ZKML": "zKML", @@ -13770,6 +15817,7 @@ "ZONX": "METAZONX", "ZOO": "ZooKeeper", "ZOOA": "Zoopia", + "ZOOC": "ZOO Crypto World", "ZOOM": "ZoomCoin", "ZOOMER": "Zoomer Coin", "ZOON": "CryptoZoon", @@ -13777,6 +15825,7 @@ "ZORA": "Zoracles", "ZORKSEES": "Zorksees", "ZORO": "Zoro Inu", + "ZORRO": "Zorro", "ZORT": "Zort", "ZP": "Zen Protocol", "ZPAE": "ZelaaPayAE", @@ -13789,6 +15838,8 @@ "ZPTC": "Zeptacoin", "ZRC": "ZrCoin", "ZRO": "LayerZero", + "ZRPY": "Zerpaay", + "ZRS": "Zaros", "ZRX": "0x", "ZSC": "Zeusshield", "ZSD": "Zephyr Protocol Stable Dollar", @@ -13797,11 +15848,13 @@ "ZT": "ZBG Token", "ZTC": "ZeTo", "ZTG": "Zeitgeist", + "ZTK": "Zefi", "ZTX": "ZTX", "ZUC": "Zeux", "ZUCKPEPE": "ZuckPepe", "ZUKI": "Zuki Moba", "ZUM": "ZumCoin", + "ZUN": "Zunami Governance Token", "ZUNA": "ZUNA", "ZUNUSD": "Zunami USD", "ZUR": "Zurcoin", @@ -13816,8 +15869,11 @@ "ZWAP": "ZilSwap", "ZXC": "Oxcert", "ZXT": "Zcrypt", + "ZYB": "Zyberswap", "ZYD": "ZayedCoin", + "ZYGO": "Zygo the frog", "ZYN": "Zynecoin", + "ZYNC": "ZynCoin", "ZYNE": "Zynergy", "ZYPTO": "Zypto Token", "ZYR": "Zyrri", @@ -13831,5 +15887,6 @@ "gOHM": "Governance OHM", "redBUX": "redBUX", "sOHM": "Staked Olympus", + "vXDEFI": "vXDEFI", "wsOHM": "Wrapped Staked Olympus" } diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index 17a6bc0f..5a49f671 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -56,10 +56,22 @@ https://ghostfol.io/de/ressourcen ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/de/ressourcen/lexikon + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/de/ressourcen/maerkte + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/de/ressourcen/personal-finance-tools ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/de/ressourcen/ratgeber + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/de/ueber-uns ${currentDate}T00:00:00+00:00 @@ -176,6 +188,10 @@ https://ghostfol.io/en/blog/2024/09/hacktoberfest-2024 ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/en/blog/2024/11/black-weeks-2024 + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/en/faq ${currentDate}T00:00:00+00:00 diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts index 7b7cb09f..6c929c38 100644 --- a/apps/api/src/middlewares/html-template.middleware.ts +++ b/apps/api/src/middlewares/html-template.middleware.ts @@ -87,6 +87,10 @@ const locales = { '/en/blog/2024/09/hacktoberfest-2024': { featureGraphicPath: 'assets/images/blog/hacktoberfest-2024.png', title: `Hacktoberfest 2024 - ${title}` + }, + '/en/blog/2024/11/black-weeks-2024': { + featureGraphicPath: 'assets/images/blog/black-weeks-2024.jpg', + title: `Black Weeks 2024 - ${title}` } }; diff --git a/apps/api/src/models/rules/allocation-cluster-risk/developed-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts similarity index 95% rename from apps/api/src/models/rules/allocation-cluster-risk/developed-markets.ts rename to apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts index 068ebdda..15e11392 100644 --- a/apps/api/src/models/rules/allocation-cluster-risk/developed-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/developed-markets.ts @@ -3,7 +3,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { UserSettings } from '@ghostfolio/common/interfaces'; -export class AllocationClusterRiskDevelopedMarkets extends Rule { +export class EconomicMarketClusterRiskDevelopedMarkets extends Rule { private currentValueInBaseCurrency: number; private developedMarketsValueInBaseCurrency: number; @@ -13,7 +13,7 @@ export class AllocationClusterRiskDevelopedMarkets extends Rule { developedMarketsValueInBaseCurrency: number ) { super(exchangeRateDataService, { - key: AllocationClusterRiskDevelopedMarkets.name, + key: EconomicMarketClusterRiskDevelopedMarkets.name, name: 'Developed Markets' }); diff --git a/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts similarity index 95% rename from apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts rename to apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts index e7c10751..8fccdf1d 100644 --- a/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts +++ b/apps/api/src/models/rules/economic-market-cluster-risk/emerging-markets.ts @@ -3,7 +3,7 @@ import { Rule } from '@ghostfolio/api/models/rule'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { UserSettings } from '@ghostfolio/common/interfaces'; -export class AllocationClusterRiskEmergingMarkets extends Rule { +export class EconomicMarketClusterRiskEmergingMarkets extends Rule { private currentValueInBaseCurrency: number; private emergingMarketsValueInBaseCurrency: number; @@ -13,7 +13,7 @@ export class AllocationClusterRiskEmergingMarkets extends Rule { emergingMarketsValueInBaseCurrency: number ) { super(exchangeRateDataService, { - key: AllocationClusterRiskEmergingMarkets.name, + key: EconomicMarketClusterRiskEmergingMarkets.name, name: 'Emerging Markets' }); diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 10810deb..3dfe5d5c 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -35,6 +35,9 @@ export class ConfigurationService { DATA_SOURCES: json({ default: [DataSource.COINGECKO, DataSource.MANUAL, DataSource.YAHOO] }), + DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER: json({ + default: [] + }), ENABLE_FEATURE_FEAR_AND_GREED_INDEX: bool({ default: false }), ENABLE_FEATURE_READ_ONLY_MODE: bool({ default: false }), ENABLE_FEATURE_SOCIAL_LOGIN: bool({ default: false }), @@ -67,7 +70,7 @@ export class ConfigurationService { REDIS_HOST: str({ default: 'localhost' }), REDIS_PASSWORD: str({ default: '' }), REDIS_PORT: port({ default: 6379 }), - REQUEST_TIMEOUT: num({ default: 2000 }), + REQUEST_TIMEOUT: num({ default: ms('3 seconds') }), ROOT_URL: url({ default: DEFAULT_ROOT_URL }), STRIPE_PUBLIC_KEY: str({ default: '' }), STRIPE_SECRET_KEY: str({ default: '' }), diff --git a/apps/api/src/services/cron.service.ts b/apps/api/src/services/cron.service.ts index 17e970c1..7a1b30b5 100644 --- a/apps/api/src/services/cron.service.ts +++ b/apps/api/src/services/cron.service.ts @@ -1,3 +1,4 @@ +import { UserService } from '@ghostfolio/api/app/user/user.service'; import { DATA_GATHERING_QUEUE_PRIORITY_LOW, GATHER_ASSET_PROFILE_PROCESS, @@ -9,6 +10,7 @@ import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { Injectable } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; +import { ConfigurationService } from './configuration/configuration.service'; import { ExchangeRateDataService } from './exchange-rate-data/exchange-rate-data.service'; import { PropertyService } from './property/property.service'; import { DataGatheringService } from './queues/data-gathering/data-gathering.service'; @@ -19,10 +21,12 @@ export class CronService { private static readonly EVERY_SUNDAY_AT_LUNCH_TIME = '0 12 * * 0'; public constructor( + private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly propertyService: PropertyService, - private readonly twitterBotService: TwitterBotService + private readonly twitterBotService: TwitterBotService, + private readonly userService: UserService ) {} @Cron(CronExpression.EVERY_HOUR) @@ -42,6 +46,13 @@ export class CronService { this.twitterBotService.tweetFearAndGreedIndex(); } + @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT) + public async runEveryDayAtMidnight() { + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + this.userService.resetAnalytics(); + } + } + @Cron(CronService.EVERY_SUNDAY_AT_LUNCH_TIME) public async runEverySundayAtTwelvePm() { if (await this.isDataGatheringEnabled()) { diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts index 01658494..5c9eee12 100644 --- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts +++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -12,7 +11,10 @@ import { IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -119,9 +121,7 @@ export class AlphaVantageService implements DataProviderInterface { return undefined; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { const result = await this.alphaVantage.data.search(query); return { diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index d420c51f..99198016 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -13,7 +12,11 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; import { @@ -83,9 +86,9 @@ export class CoinGeckoService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to get the asset profile for ${symbol} was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to get the asset profile for ${symbol} was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'CoinGeckoService'); @@ -221,9 +224,7 @@ export class CoinGeckoService implements DataProviderInterface { return 'bitcoin'; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { let items: LookupItem[] = []; try { @@ -254,9 +255,9 @@ export class CoinGeckoService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'CoinGeckoService'); diff --git a/apps/api/src/services/data-provider/data-provider.module.ts b/apps/api/src/services/data-provider/data-provider.module.ts index dcfc756f..71b54f01 100644 --- a/apps/api/src/services/data-provider/data-provider.module.ts +++ b/apps/api/src/services/data-provider/data-provider.module.ts @@ -5,6 +5,7 @@ import { AlphaVantageService } from '@ghostfolio/api/services/data-provider/alph import { CoinGeckoService } from '@ghostfolio/api/services/data-provider/coingecko/coingecko.service'; import { EodHistoricalDataService } from '@ghostfolio/api/services/data-provider/eod-historical-data/eod-historical-data.service'; import { FinancialModelingPrepService } from '@ghostfolio/api/services/data-provider/financial-modeling-prep/financial-modeling-prep.service'; +import { GhostfolioService } from '@ghostfolio/api/services/data-provider/ghostfolio/ghostfolio.service'; import { GoogleSheetsService } from '@ghostfolio/api/services/data-provider/google-sheets/google-sheets.service'; import { ManualService } from '@ghostfolio/api/services/data-provider/manual/manual.service'; import { RapidApiService } from '@ghostfolio/api/services/data-provider/rapid-api/rapid-api.service'; @@ -37,6 +38,7 @@ import { DataProviderService } from './data-provider.service'; DataProviderService, EodHistoricalDataService, FinancialModelingPrepService, + GhostfolioService, GoogleSheetsService, ManualService, RapidApiService, @@ -47,6 +49,7 @@ import { DataProviderService } from './data-provider.service'; CoinGeckoService, EodHistoricalDataService, FinancialModelingPrepService, + GhostfolioService, GoogleSheetsService, ManualService, RapidApiService, @@ -58,6 +61,7 @@ import { DataProviderService } from './data-provider.service'; coinGeckoService, eodHistoricalDataService, financialModelingPrepService, + ghostfolioService, googleSheetsService, manualService, rapidApiService, @@ -67,6 +71,7 @@ import { DataProviderService } from './data-provider.service'; coinGeckoService, eodHistoricalDataService, financialModelingPrepService, + ghostfolioService, googleSheetsService, manualService, rapidApiService, diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 385c7b07..3faf5b58 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -1,5 +1,4 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; import { @@ -12,6 +11,7 @@ import { PropertyService } from '@ghostfolio/api/services/property/property.serv import { DEFAULT_CURRENCY, DERIVED_CURRENCIES, + PROPERTY_API_KEY_GHOSTFOLIO, PROPERTY_DATA_SOURCE_MAPPING } from '@ghostfolio/common/config'; import { @@ -20,7 +20,11 @@ import { getStartOfUtcDate, isDerivedCurrency } from '@ghostfolio/common/helper'; -import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; +import { + AssetProfileIdentifier, + LookupItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import type { Granularity, UserWithSettings } from '@ghostfolio/common/types'; import { Inject, Injectable, Logger } from '@nestjs/common'; @@ -88,11 +92,11 @@ export class DataProviderService { const promises = []; - for (const [dataSource, dataGatheringItems] of Object.entries( + for (const [dataSource, assetProfileIdentifiers] of Object.entries( itemsGroupedByDataSource )) { - const symbols = dataGatheringItems.map((dataGatheringItem) => { - return dataGatheringItem.symbol; + const symbols = assetProfileIdentifiers.map(({ symbol }) => { + return symbol; }); for (const symbol of symbols) { @@ -150,6 +154,24 @@ export class DataProviderService { return DataSource[this.configurationService.get('DATA_SOURCE_IMPORT')]; } + public async getDataSources(): Promise { + const dataSources: DataSource[] = this.configurationService + .get('DATA_SOURCES') + .map((dataSource) => { + return DataSource[dataSource]; + }); + + const ghostfolioApiKey = (await this.propertyService.getByKey( + PROPERTY_API_KEY_GHOSTFOLIO + )) as string; + + if (ghostfolioApiKey) { + dataSources.push('GHOSTFOLIO'); + } + + return dataSources.sort(); + } + public async getDividends({ dataSource, from, @@ -239,11 +261,11 @@ export class DataProviderService { } public async getHistoricalRaw({ - dataGatheringItems, + assetProfileIdentifiers, from, to }: { - dataGatheringItems: AssetProfileIdentifier[]; + assetProfileIdentifiers: AssetProfileIdentifier[]; from: Date; to: Date; }): Promise<{ @@ -252,25 +274,32 @@ export class DataProviderService { for (const { currency, rootCurrency } of DERIVED_CURRENCIES) { if ( this.hasCurrency({ - dataGatheringItems, + assetProfileIdentifiers, currency: `${DEFAULT_CURRENCY}${currency}` }) ) { // Skip derived currency - dataGatheringItems = dataGatheringItems.filter(({ symbol }) => { - return symbol !== `${DEFAULT_CURRENCY}${currency}`; - }); + assetProfileIdentifiers = assetProfileIdentifiers.filter( + ({ symbol }) => { + return symbol !== `${DEFAULT_CURRENCY}${currency}`; + } + ); // Add root currency - dataGatheringItems.push({ + assetProfileIdentifiers.push({ dataSource: this.getDataSourceForExchangeRates(), symbol: `${DEFAULT_CURRENCY}${rootCurrency}` }); } } - dataGatheringItems = uniqWith(dataGatheringItems, (obj1, obj2) => { - return obj1.dataSource === obj2.dataSource && obj1.symbol === obj2.symbol; - }); + assetProfileIdentifiers = uniqWith( + assetProfileIdentifiers, + (obj1, obj2) => { + return ( + obj1.dataSource === obj2.dataSource && obj1.symbol === obj2.symbol + ); + } + ); const result: { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; @@ -280,7 +309,7 @@ export class DataProviderService { data: { [date: string]: IDataProviderHistoricalResponse }; symbol: string; }>[] = []; - for (const { dataSource, symbol } of dataGatheringItems) { + for (const { dataSource, symbol } of assetProfileIdentifiers) { const dataProvider = this.getDataProvider(dataSource); if (dataProvider.canHandle(symbol)) { if (symbol === `${DEFAULT_CURRENCY}USX`) { @@ -415,7 +444,7 @@ export class DataProviderService { const promises: Promise[] = []; - for (const [dataSource, dataGatheringItems] of Object.entries( + for (const [dataSource, assetProfileIdentifiers] of Object.entries( itemsGroupedByDataSource )) { const dataProvider = this.getDataProvider(DataSource[dataSource]); @@ -428,7 +457,7 @@ export class DataProviderService { continue; } - const symbols = dataGatheringItems + const symbols = assetProfileIdentifiers .filter(({ symbol }) => { return !isDerivedCurrency(getCurrencyFromSymbol(symbol)); }) @@ -571,19 +600,19 @@ export class DataProviderService { includeIndices?: boolean; query: string; user: UserWithSettings; - }): Promise<{ items: LookupItem[] }> { - const promises: Promise<{ items: LookupItem[] }>[] = []; + }): Promise { let lookupItems: LookupItem[] = []; + const promises: Promise[] = []; if (query?.length < 2) { return { items: lookupItems }; } - const dataProviderServices = this.configurationService - .get('DATA_SOURCES') - .map((dataSource) => { - return this.getDataProvider(DataSource[dataSource]); - }); + const dataSources = await this.getDataSources(); + + const dataProviderServices = dataSources.map((dataSource) => { + return this.getDataProvider(DataSource[dataSource]); + }); for (const dataProviderService of dataProviderServices) { promises.push( @@ -596,16 +625,16 @@ export class DataProviderService { const searchResults = await Promise.all(promises); - searchResults.forEach(({ items }) => { + for (const { items } of searchResults) { if (items?.length > 0) { lookupItems = lookupItems.concat(items); } - }); + } const filteredItems = lookupItems - .filter((lookupItem) => { + .filter(({ currency }) => { // Only allow symbols with supported currency - return lookupItem.currency ? true : false; + return currency ? true : false; }) .sort(({ name: name1 }, { name: name2 }) => { return name1?.toLowerCase().localeCompare(name2?.toLowerCase()); @@ -631,13 +660,13 @@ export class DataProviderService { } private hasCurrency({ - currency, - dataGatheringItems + assetProfileIdentifiers, + currency }: { + assetProfileIdentifiers: AssetProfileIdentifier[]; currency: string; - dataGatheringItems: AssetProfileIdentifier[]; }) { - return dataGatheringItems.some(({ dataSource, symbol }) => { + return assetProfileIdentifiers.some(({ dataSource, symbol }) => { return ( dataSource === this.getDataSourceForExchangeRates() && symbol === currency diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index c3c948b4..1c5696da 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -17,7 +16,11 @@ import { REPLACE_NAME_PARTS } from '@ghostfolio/common/config'; import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { MarketState } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; @@ -317,9 +320,7 @@ export class EodHistoricalDataService implements DataProviderInterface { return 'AAPL.US'; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { const searchResult = await this.getSearchResult(query); return { @@ -409,14 +410,12 @@ export class EodHistoricalDataService implements DataProviderInterface { return name; } - private async getSearchResult(aQuery: string): Promise< - (LookupItem & { + private async getSearchResult(aQuery: string) { + let searchResult: (LookupItem & { assetClass: AssetClass; assetSubClass: AssetSubClass; isin: string; - })[] - > { - let searchResult = []; + })[] = []; try { const abortController = new AbortController(); @@ -455,9 +454,9 @@ export class EodHistoricalDataService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to search for ${aQuery} was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to search for ${aQuery} was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'EodHistoricalDataService'); diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 7d5b3847..a1774fc0 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -13,7 +12,11 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -169,9 +172,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { return 'AAPL'; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { let items: LookupItem[] = []; try { @@ -203,9 +204,9 @@ export class FinancialModelingPrepService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'FinancialModelingPrepService'); diff --git a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts new file mode 100644 index 00000000..25ffdc67 --- /dev/null +++ b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts @@ -0,0 +1,284 @@ +import { environment } from '@ghostfolio/api/environments/environment'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { + DataProviderInterface, + GetDividendsParams, + GetHistoricalParams, + GetQuotesParams, + GetSearchParams +} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; +import { + IDataProviderHistoricalResponse, + IDataProviderResponse +} from '@ghostfolio/api/services/interfaces/interfaces'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { + HEADER_KEY_TOKEN, + PROPERTY_API_KEY_GHOSTFOLIO +} from '@ghostfolio/common/config'; +import { DATE_FORMAT } from '@ghostfolio/common/helper'; +import { + DataProviderInfo, + DividendsResponse, + HistoricalResponse, + LookupResponse, + QuotesResponse +} from '@ghostfolio/common/interfaces'; + +import { Injectable, Logger } from '@nestjs/common'; +import { DataSource, SymbolProfile } from '@prisma/client'; +import { format } from 'date-fns'; +import got from 'got'; +import { StatusCodes } from 'http-status-codes'; + +@Injectable() +export class GhostfolioService implements DataProviderInterface { + private readonly URL = environment.production + ? 'https://ghostfol.io/api' + : `${this.configurationService.get('ROOT_URL')}/api`; + + public constructor( + private readonly configurationService: ConfigurationService, + private readonly propertyService: PropertyService + ) {} + + public canHandle() { + return true; + } + + public async getAssetProfile({ + symbol + }: { + symbol: string; + }): Promise> { + const { items } = await this.search({ query: symbol }); + const searchResult = items?.[0]; + + return { + symbol, + assetClass: searchResult?.assetClass, + assetSubClass: searchResult?.assetSubClass, + currency: searchResult?.currency, + dataSource: this.getName(), + name: searchResult?.name + }; + } + + public getDataProviderInfo(): DataProviderInfo { + return { + isPremium: true, + name: 'Ghostfolio', + url: 'https://ghostfo.io' + }; + } + + public async getDividends({ + from, + granularity = 'day', + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbol, + to + }: GetDividendsParams): Promise<{ + [date: string]: IDataProviderHistoricalResponse; + }> { + let response: { + [date: string]: IDataProviderHistoricalResponse; + } = {}; + + try { + const abortController = new AbortController(); + + setTimeout(() => { + abortController.abort(); + }, requestTimeout); + + const { dividends } = await got( + `${this.URL}/v1/data-providers/ghostfolio/dividends/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format( + to, + DATE_FORMAT + )}`, + { + headers: await this.getRequestHeaders(), + // @ts-ignore + signal: abortController.signal + } + ).json(); + + response = dividends; + } catch (error) { + let message = error; + + if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { + message = 'RequestError: The daily request limit has been exceeded'; + } else if (error.response?.statusCode === StatusCodes.UNAUTHORIZED) { + message = + 'RequestError: The provided API key is invalid. Please update it in the Settings section of the Admin Control panel.'; + } + + Logger.error(message, 'GhostfolioService'); + } + + return response; + } + + public async getHistorical({ + from, + granularity = 'day', + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbol, + to + }: GetHistoricalParams): Promise<{ + [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; + }> { + try { + const abortController = new AbortController(); + + setTimeout(() => { + abortController.abort(); + }, requestTimeout); + + const { historicalData } = await got( + `${this.URL}/v1/data-providers/ghostfolio/historical/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format( + to, + DATE_FORMAT + )}`, + { + headers: await this.getRequestHeaders(), + // @ts-ignore + signal: abortController.signal + } + ).json(); + + return { + [symbol]: historicalData + }; + } catch (error) { + let message = error; + + if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { + message = 'RequestError: The daily request limit has been exceeded'; + } else if (error.response?.statusCode === StatusCodes.UNAUTHORIZED) { + message = + 'RequestError: The provided API key is invalid. Please update it in the Settings section of the Admin Control panel.'; + } + + Logger.error(message, 'GhostfolioService'); + + throw new Error( + `Could not get historical market data for ${symbol} (${this.getName()}) from ${format( + from, + DATE_FORMAT + )} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}` + ); + } + } + + public getMaxNumberOfSymbolsPerRequest() { + return 20; + } + + public getName(): DataSource { + return DataSource.GHOSTFOLIO; + } + + public async getQuotes({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbols + }: GetQuotesParams): Promise<{ + [symbol: string]: IDataProviderResponse; + }> { + let response: { [symbol: string]: IDataProviderResponse } = {}; + + if (symbols.length <= 0) { + return response; + } + + try { + const abortController = new AbortController(); + + setTimeout(() => { + abortController.abort(); + }, requestTimeout); + + const { quotes } = await got( + `${this.URL}/v1/data-providers/ghostfolio/quotes?symbols=${symbols.join(',')}`, + { + headers: await this.getRequestHeaders(), + // @ts-ignore + signal: abortController.signal + } + ).json(); + + response = quotes; + } catch (error) { + let message = error; + + if (error?.code === 'ABORT_ERR') { + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; + } else if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { + message = 'RequestError: The daily request limit has been exceeded'; + } else if (error.response?.statusCode === StatusCodes.UNAUTHORIZED) { + message = + 'RequestError: The provided API key is invalid. Please update it in the Settings section of the Admin Control panel.'; + } + + Logger.error(message, 'GhostfolioService'); + } + + return response; + } + + public getTestSymbol() { + return 'AAPL.US'; + } + + public async search({ query }: GetSearchParams): Promise { + let searchResult: LookupResponse = { items: [] }; + + try { + const abortController = new AbortController(); + + setTimeout(() => { + abortController.abort(); + }, this.configurationService.get('REQUEST_TIMEOUT')); + + searchResult = await got( + `${this.URL}/v1/data-providers/ghostfolio/lookup?query=${query}`, + { + headers: await this.getRequestHeaders(), + // @ts-ignore + signal: abortController.signal + } + ).json(); + } catch (error) { + let message = error; + + if (error?.code === 'ABORT_ERR') { + message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; + } else if (error.response?.statusCode === StatusCodes.TOO_MANY_REQUESTS) { + message = 'RequestError: The daily request limit has been exceeded'; + } else if (error.response?.statusCode === StatusCodes.UNAUTHORIZED) { + message = + 'RequestError: The provided API key is invalid. Please update it in the Settings section of the Admin Control panel.'; + } + + Logger.error(message, 'GhostfolioService'); + } + + return searchResult; + } + + private async getRequestHeaders() { + const apiKey = (await this.propertyService.getByKey( + PROPERTY_API_KEY_GHOSTFOLIO + )) as string; + + return { + [HEADER_KEY_TOKEN]: `Bearer ${apiKey}` + }; + } +} diff --git a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts index 9f234423..f18d670d 100644 --- a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts +++ b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -14,7 +13,10 @@ import { import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -157,9 +159,7 @@ export class GoogleSheetsService implements DataProviderInterface { return 'INDEXSP:.INX'; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { const items = await this.prismaService.symbolProfile.findMany({ select: { assetClass: true, diff --git a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts index 3b364447..e448b4e1 100644 --- a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts +++ b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts @@ -1,9 +1,11 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Granularity } from '@ghostfolio/common/types'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -19,7 +21,13 @@ export interface DataProviderInterface { getDataProviderInfo(): DataProviderInfo; - getDividends({ from, granularity, symbol, to }: GetDividendsParams): Promise<{ + getDividends({ + from, + granularity, + requestTimeout, + symbol, + to + }: GetDividendsParams): Promise<{ [date: string]: IDataProviderHistoricalResponse; }>; @@ -44,10 +52,7 @@ export interface DataProviderInterface { getTestSymbol(): string; - search({ - includeIndices, - query - }: GetSearchParams): Promise<{ items: LookupItem[] }>; + search({ includeIndices, query }: GetSearchParams): Promise; } export interface GetDividendsParams { diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 030ab8ea..30c7efa6 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -20,6 +19,7 @@ import { } from '@ghostfolio/common/helper'; import { DataProviderInfo, + LookupResponse, ScraperConfiguration } from '@ghostfolio/common/interfaces'; @@ -219,9 +219,7 @@ export class ManualService implements DataProviderInterface { return undefined; } - public async search({ - query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({ query }: GetSearchParams): Promise { let items = await this.prismaService.symbolProfile.findMany({ select: { assetClass: true, diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts index e47e96d8..e7abc0ff 100644 --- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface, @@ -13,7 +12,10 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config'; import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -121,7 +123,7 @@ export class RapidApiService implements DataProviderInterface { return undefined; } - public async search({}: GetSearchParams): Promise<{ items: LookupItem[] }> { + public async search({}: GetSearchParams): Promise { return { items: [] }; } @@ -157,9 +159,9 @@ export class RapidApiService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'RapidApiService'); diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 2d67c646..27da18ab 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -1,4 +1,3 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; import { YahooFinanceDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service'; import { @@ -14,7 +13,11 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { + DataProviderInfo, + LookupItem, + LookupResponse +} from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -224,7 +227,7 @@ export class YahooFinanceService implements DataProviderInterface { public async search({ includeIndices = false, query - }: GetSearchParams): Promise<{ items: LookupItem[] }> { + }: GetSearchParams): Promise { const items: LookupItem[] = []; try { diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index 8d6dd34d..2f94739f 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -15,6 +15,7 @@ export interface Environment extends CleanedEnvAccessors { DATA_SOURCE_EXCHANGE_RATES: string; DATA_SOURCE_IMPORT: string; DATA_SOURCES: string[]; + DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER: string[]; ENABLE_FEATURE_FEAR_AND_GREED_INDEX: boolean; ENABLE_FEATURE_READ_ONLY_MODE: boolean; ENABLE_FEATURE_SOCIAL_LOGIN: boolean; diff --git a/apps/api/src/services/prisma/prisma.module.ts b/apps/api/src/services/prisma/prisma.module.ts index 3875c8ca..24da6104 100644 --- a/apps/api/src/services/prisma/prisma.module.ts +++ b/apps/api/src/services/prisma/prisma.module.ts @@ -1,9 +1,10 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { Module } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; @Module({ - providers: [PrismaService], - exports: [PrismaService] + exports: [PrismaService], + providers: [ConfigService, PrismaService] }) export class PrismaModule {} diff --git a/apps/api/src/services/prisma/prisma.service.ts b/apps/api/src/services/prisma/prisma.service.ts index e99d6ecf..4673cbd1 100644 --- a/apps/api/src/services/prisma/prisma.service.ts +++ b/apps/api/src/services/prisma/prisma.service.ts @@ -1,16 +1,38 @@ import { Injectable, Logger, + LogLevel, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; -import { PrismaClient } from '@prisma/client'; +import { ConfigService } from '@nestjs/config'; +import { Prisma, PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { + public constructor(configService: ConfigService) { + let customLogLevels: LogLevel[]; + + try { + customLogLevels = JSON.parse( + configService.get('LOG_LEVELS') + ) as LogLevel[]; + } catch {} + + const log: Prisma.LogDefinition[] = + customLogLevels?.includes('debug') || customLogLevels?.includes('verbose') + ? [{ emit: 'stdout', level: 'query' }] + : []; + + super({ + log, + errorFormat: 'colorless' + }); + } + public async onModuleInit() { try { await this.$connect(); diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts index dc8cc599..eedad747 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts @@ -89,7 +89,7 @@ export class DataGatheringProcessor { ); const historicalData = await this.dataProviderService.getHistoricalRaw({ - dataGatheringItems: [{ dataSource, symbol }], + assetProfileIdentifiers: [{ dataSource, symbol }], from: currentDate, to: new Date() }); diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts index 72b8ac71..b79b2a09 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.service.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts @@ -122,7 +122,7 @@ export class DataGatheringService { }) { try { const historicalData = await this.dataProviderService.getHistoricalRaw({ - dataGatheringItems: [{ dataSource, symbol }], + assetProfileIdentifiers: [{ dataSource, symbol }], from: date, to: date }); diff --git a/apps/client/src/app/app-routing.module.ts b/apps/client/src/app/app-routing.module.ts index 8a517c5f..f4b61ea3 100644 --- a/apps/client/src/app/app-routing.module.ts +++ b/apps/client/src/app/app-routing.module.ts @@ -32,6 +32,15 @@ const routes: Routes = [ loadChildren: () => import('./pages/admin/admin-page.module').then((m) => m.AdminPageModule) }, + { + canActivate: [AuthGuard], + loadComponent: () => + import('./pages/api/api-page.component').then( + (c) => c.GfApiPageComponent + ), + path: 'api', + title: 'Ghostfolio API' + }, { path: 'auth', loadChildren: () => diff --git a/apps/client/src/app/app.component.html b/apps/client/src/app/app.component.html index b1285548..7560e15e 100644 --- a/apps/client/src/app/app.component.html +++ b/apps/client/src/app/app.component.html @@ -33,6 +33,7 @@ [deviceType]="deviceType" [hasPermissionToChangeDateRange]="hasPermissionToChangeDateRange" [hasPermissionToChangeFilters]="hasPermissionToChangeFilters" + [hasPromotion]="hasPromotion" [hasTabs]="hasTabs" [info]="info" [pageTitle]="pageTitle" diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index 75841686..86d4282a 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -57,6 +57,7 @@ export class AppComponent implements OnDestroy, OnInit { public hasPermissionToAccessFearAndGreedIndex: boolean; public hasPermissionToChangeDateRange: boolean; public hasPermissionToChangeFilters: boolean; + public hasPromotion = false; public hasTabs = false; public info: InfoItem; public pageTitle: string; @@ -136,6 +137,10 @@ export class AppComponent implements OnDestroy, OnInit { permissions.enableFearAndGreedIndex ); + this.hasPromotion = + !!this.info?.subscriptionOffers?.default?.coupon || + !!this.info?.subscriptionOffers?.default?.durationExtension; + this.impersonationStorageService .onChangeHasImpersonation() .pipe(takeUntil(this.unsubscribeSubject)) @@ -231,6 +236,14 @@ export class AppComponent implements OnDestroy, OnInit { this.hasInfoMessage = this.canCreateAccount || !!this.user?.systemMessage; + this.hasPromotion = + !!this.info?.subscriptionOffers?.[ + this.user?.subscription?.offer ?? 'default' + ]?.coupon || + !!this.info?.subscriptionOffers?.[ + this.user?.subscription?.offer ?? 'default' + ]?.durationExtension; + this.initializeTheme(this.user?.settings.colorScheme); this.changeDetectorRef.markForCheck(); diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.module.ts b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.module.ts deleted file mode 100644 index 9f4e1b3b..00000000 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; - -import { CommonModule } from '@angular/common'; -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; - -import { AdminMarketDataDetailComponent } from './admin-market-data-detail.component'; -import { GfMarketDataDetailDialogModule } from './market-data-detail-dialog/market-data-detail-dialog.module'; - -@NgModule({ - declarations: [AdminMarketDataDetailComponent], - exports: [AdminMarketDataDetailComponent], - imports: [CommonModule, GfLineChartComponent, GfMarketDataDetailDialogModule], - schemas: [CUSTOM_ELEMENTS_SCHEMA] -}) -export class GfAdminMarketDataDetailModule {} diff --git a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.module.ts b/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.module.ts deleted file mode 100644 index f3b55d71..00000000 --- a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatDialogModule } from '@angular/material/dialog'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; - -import { MarketDataDetailDialog } from './market-data-detail-dialog.component'; - -@NgModule({ - declarations: [MarketDataDetailDialog], - imports: [ - CommonModule, - FormsModule, - MatButtonModule, - MatDatepickerModule, - MatDialogModule, - MatFormFieldModule, - MatInputModule, - ReactiveFormsModule - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] -}) -export class GfMarketDataDetailDialogModule {} diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss index b63df013..7057aad8 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.scss @@ -3,5 +3,9 @@ .mat-mdc-dialog-content { max-height: unset; + + gf-line-chart { + aspect-ratio: 16/9; + } } } diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index aacf387e..4fdc2298 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -1,15 +1,17 @@ import { UpdateAssetProfileDto } from '@ghostfolio/api/app/admin/update-asset-profile.dto'; -import { UpdateMarketDataDto } from '@ghostfolio/api/app/admin/update-market-data.dto'; import { AdminMarketDataService } from '@ghostfolio/client/components/admin-market-data/admin-market-data.service'; import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; import { validateObjectForForm } from '@ghostfolio/client/util/form.util'; import { ghostfolioScraperApiSymbolPrefix } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { AdminMarketDataDetails, - AssetProfileIdentifier + AssetProfileIdentifier, + LineChartItem, + User } from '@ghostfolio/common/interfaces'; import { translate } from '@ghostfolio/ui/i18n'; @@ -23,7 +25,6 @@ import { } from '@angular/core'; import { FormBuilder, FormControl, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; import { AssetClass, AssetSubClass, @@ -31,7 +32,6 @@ import { SymbolProfile } from '@prisma/client'; import { format } from 'date-fns'; -import { parse as csvToJson } from 'papaparse'; import { EMPTY, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; @@ -75,11 +75,13 @@ export class AssetProfileDialog implements OnDestroy, OnInit { }; public currencies: string[] = []; public ghostfolioScraperApiSymbolPrefix = ghostfolioScraperApiSymbolPrefix; + public historicalDataItems: LineChartItem[]; public isBenchmark = false; - public marketDataDetails: MarketData[] = []; + public marketDataItems: MarketData[] = []; public sectors: { [name: string]: { name: string; value: number }; }; + public user: User; private static readonly HISTORICAL_DATA_TEMPLATE = `date;marketPrice\n${format( new Date(), @@ -96,7 +98,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit { public dialogRef: MatDialogRef, private formBuilder: FormBuilder, private notificationService: NotificationService, - private snackBar: MatSnackBar + private userService: UserService ) {} public ngOnInit() { @@ -109,6 +111,16 @@ export class AssetProfileDialog implements OnDestroy, OnInit { } public initialize() { + this.historicalDataItems = undefined; + + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + } + }); + this.adminService .fetchAdminMarketDataBySymbol({ dataSource: this.data.dataSource, @@ -121,10 +133,19 @@ export class AssetProfileDialog implements OnDestroy, OnInit { this.assetProfileClass = translate(this.assetProfile?.assetClass); this.assetProfileSubClass = translate(this.assetProfile?.assetSubClass); this.countries = {}; + this.isBenchmark = this.benchmarks.some(({ id }) => { return id === this.assetProfile.id; }); - this.marketDataDetails = marketData; + + this.historicalDataItems = marketData.map(({ date, marketPrice }) => { + return { + date: format(date, DATE_FORMAT), + value: marketPrice + }; + }); + + this.marketDataItems = marketData; this.sectors = {}; if (this.assetProfile?.countries?.length > 0) { @@ -200,47 +221,6 @@ export class AssetProfileDialog implements OnDestroy, OnInit { .subscribe(); } - public onImportHistoricalData() { - try { - const marketData = csvToJson( - this.assetProfileForm.controls['historicalData'].controls['csvString'] - .value, - { - dynamicTyping: true, - header: true, - skipEmptyLines: true - } - ).data as UpdateMarketDataDto[]; - - this.adminService - .postMarketData({ - dataSource: this.data.dataSource, - marketData: { - marketData - }, - symbol: this.data.symbol - }) - .pipe( - catchError(({ error, message }) => { - this.snackBar.open(`${error}: ${message[0]}`, undefined, { - duration: 3000 - }); - return EMPTY; - }), - takeUntil(this.unsubscribeSubject) - ) - .subscribe(() => { - this.initialize(); - }); - } catch { - this.snackBar.open( - $localize`Oops! Could not parse historical data.`, - undefined, - { duration: 3000 } - ); - } - } - public onMarketDataChanged(withRefresh: boolean = false) { if (withRefresh) { this.initialize(); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index a5d2205d..eeb43e93 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -68,50 +68,28 @@
- + -
- - - Historical Data (CSV) - - - -
- -
- -
-
- NEW + @if (isGhostfolioApiKeyValid === false) { + NEW + } Ghostfolio Premium + @if (isGhostfolioApiKeyValid === true) { +
+ + Valid until + {{ + ghostfolioApiStatus?.subscription?.expiresAt + | date: defaultDateFormat + }} +
+ }
- + @if (isGhostfolioApiKeyValid === true) { +
+
+ {{ ghostfolioApiStatus.dailyRequests }} + of + {{ ghostfolioApiStatus.dailyRequestsMax }} + daily requests +
+ + + + +
+ } @else if (isGhostfolioApiKeyValid === false) { + + }
diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.ts b/apps/client/src/app/components/admin-settings/admin-settings.component.ts index 2dd2555b..1ff67e01 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.ts @@ -1,5 +1,17 @@ +import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/confirmation-dialog/confirmation-dialog.type'; +import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; +import { AdminService } from '@ghostfolio/client/services/admin.service'; +import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { User } from '@ghostfolio/common/interfaces'; +import { + DEFAULT_LANGUAGE_CODE, + PROPERTY_API_KEY_GHOSTFOLIO +} from '@ghostfolio/common/config'; +import { getDateFormatString } from '@ghostfolio/common/helper'; +import { + DataProviderGhostfolioStatusResponse, + User +} from '@ghostfolio/common/interfaces'; import { ChangeDetectionStrategy, @@ -10,7 +22,7 @@ import { } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; +import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; import { GfGhostfolioPremiumApiDialogComponent } from './ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component'; @@ -21,6 +33,9 @@ import { GfGhostfolioPremiumApiDialogComponent } from './ghostfolio-premium-api- templateUrl: './admin-settings.component.html' }) export class AdminSettingsComponent implements OnDestroy, OnInit { + public defaultDateFormat: string; + public ghostfolioApiStatus: DataProviderGhostfolioStatusResponse; + public isGhostfolioApiKeyValid: boolean; public pricingUrl: string; private deviceType: string; @@ -28,9 +43,12 @@ export class AdminSettingsComponent implements OnDestroy, OnInit { private user: User; public constructor( + private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, + private dataService: DataService, private deviceService: DeviceDetectorService, private matDialog: MatDialog, + private notificationService: NotificationService, private userService: UserService ) {} @@ -43,29 +61,86 @@ export class AdminSettingsComponent implements OnDestroy, OnInit { if (state?.user) { this.user = state.user; + this.defaultDateFormat = getDateFormatString( + this.user?.settings?.locale + ); + + const languageCode = + this.user?.settings?.language ?? DEFAULT_LANGUAGE_CODE; + this.pricingUrl = - `https://ghostfol.io/${this.user.settings.language}/` + + `https://ghostfol.io/${languageCode}/` + $localize`:snake-case:pricing`; this.changeDetectorRef.markForCheck(); } }); + + this.initialize(); + } + + public onRemoveGhostfolioApiKey() { + this.notificationService.confirm({ + confirmFn: () => { + this.dataService + .putAdminSetting(PROPERTY_API_KEY_GHOSTFOLIO, { value: undefined }) + .subscribe(() => { + this.initialize(); + }); + }, + confirmType: ConfirmationDialogType.Warn, + title: $localize`Do you really want to delete the API key?` + }); } public onSetGhostfolioApiKey() { - this.matDialog.open(GfGhostfolioPremiumApiDialogComponent, { - autoFocus: false, - data: { - deviceType: this.deviceType, - pricingUrl: this.pricingUrl - }, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - }); + const dialogRef = this.matDialog.open( + GfGhostfolioPremiumApiDialogComponent, + { + autoFocus: false, + data: { + deviceType: this.deviceType, + pricingUrl: this.pricingUrl + }, + height: this.deviceType === 'mobile' ? '98vh' : undefined, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + } + ); + + dialogRef + .afterClosed() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.initialize(); + }); } public ngOnDestroy() { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); } + + private initialize() { + this.adminService + .fetchGhostfolioDataProviderStatus() + .pipe( + catchError(() => { + this.isGhostfolioApiKeyValid = false; + + this.changeDetectorRef.markForCheck(); + + return of(null); + }), + filter((status) => { + return status !== null; + }), + takeUntil(this.unsubscribeSubject) + ) + .subscribe((status) => { + this.ghostfolioApiStatus = status; + this.isGhostfolioApiKeyValid = true; + + this.changeDetectorRef.markForCheck(); + }); + } } diff --git a/apps/client/src/app/components/admin-settings/admin-settings.module.ts b/apps/client/src/app/components/admin-settings/admin-settings.module.ts index 3a3e04a2..5a5c39cd 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.module.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.module.ts @@ -6,6 +6,7 @@ import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; +import { MatMenuModule } from '@angular/material/menu'; import { RouterModule } from '@angular/router'; import { AdminSettingsComponent } from './admin-settings.component'; @@ -19,6 +20,7 @@ import { AdminSettingsComponent } from './admin-settings.component'; GfPremiumIndicatorComponent, MatButtonModule, MatCardModule, + MatMenuModule, RouterModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA] diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts index 856ddc85..f15866f1 100644 --- a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts @@ -1,3 +1,5 @@ +import { DataService } from '@ghostfolio/client/services/data.service'; +import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { CommonModule } from '@angular/common'; @@ -30,10 +32,28 @@ import { GhostfolioPremiumApiDialogParams } from './interfaces/interfaces'; export class GfGhostfolioPremiumApiDialogComponent { public constructor( @Inject(MAT_DIALOG_DATA) public data: GhostfolioPremiumApiDialogParams, + private dataService: DataService, public dialogRef: MatDialogRef ) {} public onCancel() { this.dialogRef.close(); } + + public onSetGhostfolioApiKey() { + let ghostfolioApiKey = prompt( + $localize`Please enter your Ghostfolio API key:` + ); + ghostfolioApiKey = ghostfolioApiKey?.trim(); + + if (ghostfolioApiKey) { + this.dataService + .putAdminSetting(PROPERTY_API_KEY_GHOSTFOLIO, { + value: ghostfolioApiKey + }) + .subscribe(() => { + this.dialogRef.close(); + }); + } + } } diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html index 25673075..f2f75375 100644 --- a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html @@ -29,9 +29,19 @@ href="mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Data Provider&body=Hello%0D%0DPlease notify me as soon as the Ghostfolio Premium Data Provider is available.%0D%0DKind regards" i18n mat-flat-button + >Notify me - Notify me - +
+ or +
+
diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 86759376..91c258f9 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -4,11 +4,19 @@ import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper'; import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { differenceInSeconds, @@ -24,6 +32,8 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './admin-users.html' }) export class AdminUsersComponent implements OnDestroy, OnInit { + @ViewChild(MatPaginator) paginator: MatPaginator; + public dataSource = new MatTableDataSource(); public defaultDateFormat: string; public displayedColumns: string[] = []; @@ -32,6 +42,8 @@ export class AdminUsersComponent implements OnDestroy, OnInit { public hasPermissionToImpersonateAllUsers: boolean; public info: InfoItem; public isLoading = false; + public pageSize = DEFAULT_PAGE_SIZE; + public totalItems = 0; public user: User; private unsubscribeSubject = new Subject(); @@ -60,6 +72,7 @@ export class AdminUsersComponent implements OnDestroy, OnInit { 'accounts', 'activities', 'engagementPerDay', + 'dailyApiRequests', 'lastRequest', 'actions' ]; @@ -136,19 +149,33 @@ export class AdminUsersComponent implements OnDestroy, OnInit { window.location.reload(); } + public onChangePage(page: PageEvent) { + this.fetchUsers({ + pageIndex: page.pageIndex + }); + } + public ngOnDestroy() { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); } - private fetchUsers() { + private fetchUsers({ pageIndex }: { pageIndex: number } = { pageIndex: 0 }) { this.isLoading = true; + if (pageIndex === 0 && this.paginator) { + this.paginator.pageIndex = 0; + } + this.adminService - .fetchUsers() + .fetchUsers({ + skip: pageIndex * this.pageSize, + take: this.pageSize + }) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ users }) => { + .subscribe(({ count, users }) => { this.dataSource = new MatTableDataSource(users); + this.totalItems = count; this.isLoading = false; diff --git a/apps/client/src/app/components/admin-users/admin-users.html b/apps/client/src/app/components/admin-users/admin-users.html index 2c806684..ca8ef055 100644 --- a/apps/client/src/app/components/admin-users/admin-users.html +++ b/apps/client/src/app/components/admin-users/admin-users.html @@ -169,6 +169,27 @@ /> + + + API Requests Today + + + + + } @if (hasPermissionForSubscription) { @@ -246,6 +267,17 @@ > + + + @if (isLoading) { Pricing + + Pricing + @if (currentRoute !== routePricing && hasPromotion) { + % + } + + }
  • @@ -290,12 +295,17 @@ ) { Pricing + + Pricing + @if (currentRoute !== routePricing && hasPromotion) { + % + } + + } Pricing + + Pricing + @if (currentRoute !== routePricing && hasPromotion) { + % + } + +
  • } @if (hasPermissionToAccessFearAndGreedIndex) { diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts index 33069aa2..004fa5f3 100644 --- a/apps/client/src/app/components/header/header.component.ts +++ b/apps/client/src/app/components/header/header.component.ts @@ -58,6 +58,7 @@ export class HeaderComponent implements OnChanges { @Input() deviceType: string; @Input() hasPermissionToChangeDateRange: boolean; @Input() hasPermissionToChangeFilters: boolean; + @Input() hasPromotion: boolean; @Input() hasTabs: boolean; @Input() info: InfoItem; @Input() pageTitle: string; @@ -174,17 +175,17 @@ export class HeaderComponent implements OnChanges { const userSetting: UpdateUserSettingDto = {}; for (const filter of filters) { - let filtersType: string; - if (filter.type === 'ACCOUNT') { - filtersType = 'accounts'; + userSetting['filters.accounts'] = filter.id ? [filter.id] : null; } else if (filter.type === 'ASSET_CLASS') { - filtersType = 'assetClasses'; + userSetting['filters.assetClasses'] = filter.id ? [filter.id] : null; + } else if (filter.type === 'DATA_SOURCE') { + userSetting['filters.dataSource'] = filter.id ? filter.id : null; + } else if (filter.type === 'SYMBOL') { + userSetting['filters.symbol'] = filter.id ? filter.id : null; } else if (filter.type === 'TAG') { - filtersType = 'tags'; + userSetting['filters.tags'] = filter.id ? [filter.id] : null; } - - userSetting[`filters.${filtersType}`] = filter.id ? [filter.id] : null; } this.dataService diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index f1c4e7e8..abbc93b3 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -7,23 +7,21 @@
    - @if (user?.settings?.isExperimentalFeatures) { -
    -
    - - - - - - - - -
    +
    +
    + + + + + + + +
    - } +
    {{ data.rule.name }}
    -
    -
    - Threshold Min: - @if (data.rule.configuration.threshold.unit === '%') { - {{ data.settings.thresholdMin | percent: '1.2-2' }} - } @else { - {{ data.settings.thresholdMin }} - } -
    - @if (data.rule.configuration.threshold.unit === '%') { - - } @else { - - } - +
    + Threshold range: + @if (data.rule.configuration.threshold.unit === '%') { + {{ data.settings.thresholdMin | percent: '1.2-2' }} + } @else { + {{ data.settings.thresholdMin }} + } + - + @if (data.rule.configuration.threshold.unit === '%') { + {{ data.settings.thresholdMax | percent: '1.2-2' }} + } @else { + {{ data.settings.thresholdMax }} + } +
    +
    + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } + + + + + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } +
    +
    + } @else { +
    - - - @if (data.rule.configuration.threshold.unit === '%') { - - } @else { - - } -
    -
    -
    - Threshold Max: - @if (data.rule.configuration.threshold.unit === '%') { - {{ data.settings.thresholdMax | percent: '1.2-2' }} - } @else { - {{ data.settings.thresholdMax }} - } -
    - @if (data.rule.configuration.threshold.unit === '%') { - - } @else { - - } - + Threshold Min: + @if (data.rule.configuration.threshold.unit === '%') { + {{ data.settings.thresholdMin | percent: '1.2-2' }} + } @else { + {{ data.settings.thresholdMin }} + } + +
    + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } + + + + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } +
    +
    +
    - - - @if (data.rule.configuration.threshold.unit === '%') { - - } @else { - - } -
    +
    + Threshold Max: + @if (data.rule.configuration.threshold.unit === '%') { + {{ data.settings.thresholdMax | percent: '1.2-2' }} + } @else { + {{ data.settings.thresholdMax }} + } +
    +
    + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } + + + + @if (data.rule.configuration.threshold.unit === '%') { + + } @else { + + } +
    +
    + }
    diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss index dc9093b4..0f6fce3d 100644 --- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss +++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss @@ -1,2 +1,5 @@ :host { + label { + margin-bottom: 0; + } } diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts index 93bbe641..bde555d8 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts @@ -16,6 +16,7 @@ import { MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar'; +import { StringValue } from 'ms'; import { StripeService } from 'ngx-stripe'; import { EMPTY, Subject } from 'rxjs'; import { catchError, switchMap, takeUntil } from 'rxjs/operators'; @@ -31,6 +32,7 @@ export class UserAccountMembershipComponent implements OnDestroy { public coupon: number; public couponId: string; public defaultDateFormat: string; + public durationExtension: StringValue; public hasPermissionForSubscription: boolean; public hasPermissionToUpdateUserSettings: boolean; public price: number; @@ -51,7 +53,7 @@ export class UserAccountMembershipComponent implements OnDestroy { private stripeService: StripeService, private userService: UserService ) { - const { baseCurrency, globalPermissions, subscriptions } = + const { baseCurrency, globalPermissions, subscriptionOffers } = this.dataService.fetchInfo(); this.baseCurrency = baseCurrency; @@ -76,11 +78,18 @@ export class UserAccountMembershipComponent implements OnDestroy { permissions.updateUserSettings ); - this.coupon = subscriptions?.[this.user.subscription.offer]?.coupon; + this.coupon = + subscriptionOffers?.[this.user.subscription.offer]?.coupon; this.couponId = - subscriptions?.[this.user.subscription.offer]?.couponId; - this.price = subscriptions?.[this.user.subscription.offer]?.price; - this.priceId = subscriptions?.[this.user.subscription.offer]?.priceId; + subscriptionOffers?.[this.user.subscription.offer]?.couponId; + this.durationExtension = + subscriptionOffers?.[ + this.user.subscription.offer + ]?.durationExtension; + this.price = + subscriptionOffers?.[this.user.subscription.offer]?.price; + this.priceId = + subscriptionOffers?.[this.user.subscription.offer]?.priceId; this.changeDetectorRef.markForCheck(); } diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.html b/apps/client/src/app/components/user-account-membership/user-account-membership.html index d30ce7bd..82b329a6 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.html +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -34,6 +34,16 @@  per year
    } + @if (durationExtension) { +
    +
    + Limited Offer! Get + {{ durationExtension }} extra +
    +
    + } }
    @if (!user?.subscription?.expiresAt) { diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index 442be2fb..d92f1b63 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -117,7 +117,7 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit { } public isCommunityLanguage() { - return !(this.language === 'de' || this.language === 'en'); + return !['de', 'en'].includes(this.language); } public onChangeUserSetting(aKey: string, aValue: string) { diff --git a/apps/client/src/app/core/auth.interceptor.ts b/apps/client/src/app/core/auth.interceptor.ts index b0dbdf64..7491cecf 100644 --- a/apps/client/src/app/core/auth.interceptor.ts +++ b/apps/client/src/app/core/auth.interceptor.ts @@ -2,6 +2,7 @@ import { ImpersonationStorageService } from '@ghostfolio/client/services/imperso import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { HEADER_KEY_IMPERSONATION, + HEADER_KEY_SKIP_INTERCEPTOR, HEADER_KEY_TIMEZONE, HEADER_KEY_TOKEN } from '@ghostfolio/common/config'; @@ -27,6 +28,16 @@ export class AuthInterceptor implements HttpInterceptor { next: HttpHandler ): Observable> { let request = req; + + if (request.headers.has(HEADER_KEY_SKIP_INTERCEPTOR)) { + // Bypass the interceptor + request = request.clone({ + headers: req.headers.delete(HEADER_KEY_SKIP_INTERCEPTOR) + }); + + return next.handle(request); + } + let headers = request.headers.set( HEADER_KEY_TIMEZONE, Intl?.DateTimeFormat().resolvedOptions().timeZone diff --git a/apps/client/src/app/core/http-response.interceptor.ts b/apps/client/src/app/core/http-response.interceptor.ts index 0e24533e..203d3adf 100644 --- a/apps/client/src/app/core/http-response.interceptor.ts +++ b/apps/client/src/app/core/http-response.interceptor.ts @@ -103,7 +103,7 @@ export class HttpResponseInterceptor implements HttpInterceptor { } else if (error.status === StatusCodes.UNAUTHORIZED) { if (this.webAuthnService.isEnabled()) { this.router.navigate(['/webauthn']); - } else { + } else if (!error.url.includes('/data-providers/ghostfolio/status')) { this.tokenStorageService.signOut(); } } diff --git a/apps/client/src/app/pages/api/api-page.component.ts b/apps/client/src/app/pages/api/api-page.component.ts new file mode 100644 index 00000000..aa176c0f --- /dev/null +++ b/apps/client/src/app/pages/api/api-page.component.ts @@ -0,0 +1,131 @@ +import { DATE_FORMAT } from '@ghostfolio/common/helper'; +import { + DataProviderGhostfolioStatusResponse, + DividendsResponse, + HistoricalResponse, + LookupResponse, + QuotesResponse +} from '@ghostfolio/common/interfaces'; + +import { CommonModule } from '@angular/common'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { format, startOfYear } from 'date-fns'; +import { map, Observable, Subject, takeUntil } from 'rxjs'; + +@Component({ + host: { class: 'page' }, + imports: [CommonModule], + selector: 'gf-api-page', + standalone: true, + styleUrls: ['./api-page.scss'], + templateUrl: './api-page.html' +}) +export class GfApiPageComponent implements OnInit { + public dividends$: Observable; + public historicalData$: Observable; + public quotes$: Observable; + public status$: Observable; + public symbols$: Observable; + + private unsubscribeSubject = new Subject(); + + public constructor(private http: HttpClient) {} + + public ngOnInit() { + this.dividends$ = this.fetchDividends({ symbol: 'KO' }); + this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL.US' }); + this.quotes$ = this.fetchQuotes({ symbols: ['AAPL.US', 'VOO.US'] }); + this.status$ = this.fetchStatus(); + this.symbols$ = this.fetchSymbols({ query: 'apple' }); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } + + private fetchDividends({ symbol }: { symbol: string }) { + const params = new HttpParams() + .set('from', format(startOfYear(new Date()), DATE_FORMAT)) + .set('to', format(new Date(), DATE_FORMAT)); + + return this.http + .get( + `/api/v1/data-providers/ghostfolio/dividends/${symbol}`, + { params } + ) + .pipe( + map(({ dividends }) => { + return dividends; + }), + takeUntil(this.unsubscribeSubject) + ); + } + + private fetchHistoricalData({ symbol }: { symbol: string }) { + const params = new HttpParams() + .set('from', format(startOfYear(new Date()), DATE_FORMAT)) + .set('to', format(new Date(), DATE_FORMAT)); + + return this.http + .get( + `/api/v1/data-providers/ghostfolio/historical/${symbol}`, + { params } + ) + .pipe( + map(({ historicalData }) => { + return historicalData; + }), + takeUntil(this.unsubscribeSubject) + ); + } + + private fetchQuotes({ symbols }: { symbols: string[] }) { + const params = new HttpParams().set('symbols', symbols.join(',')); + + return this.http + .get('/api/v1/data-providers/ghostfolio/quotes', { + params + }) + .pipe( + map(({ quotes }) => { + return quotes; + }), + takeUntil(this.unsubscribeSubject) + ); + } + + private fetchStatus() { + return this.http + .get( + '/api/v1/data-providers/ghostfolio/status' + ) + .pipe(takeUntil(this.unsubscribeSubject)); + } + + private fetchSymbols({ + includeIndices = false, + query + }: { + includeIndices?: boolean; + query: string; + }) { + let params = new HttpParams().set('query', query); + + if (includeIndices) { + params = params.append('includeIndices', includeIndices); + } + + return this.http + .get('/api/v1/data-providers/ghostfolio/lookup', { + params + }) + .pipe( + map(({ items }) => { + return items; + }), + takeUntil(this.unsubscribeSubject) + ); + } +} diff --git a/apps/client/src/app/pages/api/api-page.html b/apps/client/src/app/pages/api/api-page.html new file mode 100644 index 00000000..a1f286c0 --- /dev/null +++ b/apps/client/src/app/pages/api/api-page.html @@ -0,0 +1,62 @@ +
    +
    +

    Status

    +
    {{ status$ | async | json }}
    +
    +
    +

    Lookup

    + @if (symbols$) { + @let symbols = symbols$ | async; +
      + @for (item of symbols; track item.symbol) { +
    • {{ item.name }} ({{ item.symbol }})
    • + } +
    + } +
    +
    +

    Quotes

    + @if (quotes$) { + @let quotes = quotes$ | async; +
      + @for (quote of quotes | keyvalue; track quote) { +
    • + {{ quote.key }}: {{ quote.value.marketPrice }} + {{ quote.value.currency }} +
    • + } +
    + } +
    +
    +

    Historical

    + @if (historicalData$) { + @let historicalData = historicalData$ | async; +
      + @for ( + historicalDataItem of historicalData | keyvalue; + track historicalDataItem + ) { +
    • + {{ historicalDataItem.key }}: + {{ historicalDataItem.value.marketPrice }} +
    • + } +
    + } +
    +
    +

    Dividends

    + @if (dividends$) { + @let dividends = dividends$ | async; +
      + @for (dividend of dividends | keyvalue; track dividend) { +
    • + {{ dividend.key }}: + {{ dividend.value.marketPrice }} +
    • + } +
    + } +
    +
    diff --git a/apps/client/src/app/pages/api/api-page.scss b/apps/client/src/app/pages/api/api-page.scss new file mode 100644 index 00000000..5d4e87f3 --- /dev/null +++ b/apps/client/src/app/pages/api/api-page.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts b/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts new file mode 100644 index 00000000..5b380a3c --- /dev/null +++ b/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts @@ -0,0 +1,17 @@ +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; + +import { Component } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { RouterModule } from '@angular/router'; + +@Component({ + host: { class: 'page' }, + imports: [GfPremiumIndicatorComponent, MatButtonModule, RouterModule], + selector: 'gf-black-weeks-2024-page', + standalone: true, + templateUrl: './black-weeks-2024-page.html' +}) +export class BlackWeeks2024PageComponent { + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; +} diff --git a/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html b/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html new file mode 100644 index 00000000..aeac1cf1 --- /dev/null +++ b/apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html @@ -0,0 +1,180 @@ +
    +
    +
    +
    +
    +

    Black Weeks 2024

    +
    2024-11-16
    + Black Week 2024 Teaser +
    +
    +

    + Take advantage of our exclusive Black Weeks offer + and save 25% on your annual + Ghostfolio Premium + + + subscription, plus get 3 months extra for free! +

    +
    +
    +

    + Ghostfolio + is a powerful personal finance dashboard, designed to simplify your + investment journey. With this Open Source Software (OSS) platform, + you can: +

    +
      +
    • + Unify your assets: Track your financial + portfolio, including stocks, ETFs, cryptocurrencies, etc. +
    • +
    • + Gain deeper insights: Access real-time analytics + and data-driven insights. +
    • +
    • + Make informed decisions: Empower yourself with + actionable information. +
    • +
    +
    +
    +

    + Don’t miss this limited-time offer to optimize your financial + future. +

    +

    + Get the Deal +

    +

    + For more information, visit our + pricing page. +

    +
    +
    +
      +
    • + 2024 +
    • +
    • + Black Friday +
    • +
    • + Black Weeks +
    • +
    • + Cryptocurrency +
    • +
    • + Dashboard +
    • +
    • + Deal +
    • +
    • + DeFi +
    • +
    • + ETF +
    • +
    • + Finance +
    • +
    • + Fintech +
    • +
    • + Ghostfolio +
    • +
    • + Ghostfolio Premium +
    • +
    • + Hosting +
    • +
    • + Investment +
    • +
    • + Open Source +
    • +
    • + OSS +
    • +
    • + Personal Finance +
    • +
    • + Portfolio +
    • +
    • + Portfolio Tracker +
    • +
    • + Pricing +
    • +
    • + Promotion +
    • +
    • + SaaS +
    • +
    • + Sale +
    • +
    • + Software +
    • +
    • + Stock +
    • +
    • + Subscription +
    • +
    • + Wealth +
    • +
    • + Wealth Management +
    • +
    • + Web3 +
    • +
    • + Web 3.0 +
    • +
    +
    + +
    +
    +
    +
    diff --git a/apps/client/src/app/pages/blog/blog-page-routing.module.ts b/apps/client/src/app/pages/blog/blog-page-routing.module.ts index 3c28543e..d6c510c2 100644 --- a/apps/client/src/app/pages/blog/blog-page-routing.module.ts +++ b/apps/client/src/app/pages/blog/blog-page-routing.module.ts @@ -165,15 +165,6 @@ const routes: Routes = [ ).then((c) => c.Hacktoberfest2023PageComponent), title: 'Hacktoberfest 2023' }, - { - canActivate: [AuthGuard], - path: '2023/11/hacktoberfest-2023-debriefing', - loadComponent: () => - import( - './2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component' - ).then((c) => c.Hacktoberfest2023DebriefingPageComponent), - title: 'Hacktoberfest 2023 Debriefing' - }, { canActivate: [AuthGuard], path: '2023/11/black-week-2023', @@ -183,6 +174,15 @@ const routes: Routes = [ ), title: 'Black Week 2023' }, + { + canActivate: [AuthGuard], + path: '2023/11/hacktoberfest-2023-debriefing', + loadComponent: () => + import( + './2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component' + ).then((c) => c.Hacktoberfest2023DebriefingPageComponent), + title: 'Hacktoberfest 2023 Debriefing' + }, { canActivate: [AuthGuard], path: '2024/09/hacktoberfest-2024', @@ -191,6 +191,15 @@ const routes: Routes = [ './2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component' ).then((c) => c.Hacktoberfest2024PageComponent), title: 'Hacktoberfest 2024' + }, + { + canActivate: [AuthGuard], + path: '2024/11/black-weeks-2024', + loadComponent: () => + import('./2024/11/black-weeks-2024/black-weeks-2024-page.component').then( + (c) => c.BlackWeeks2024PageComponent + ), + title: 'Black Weeks 2024' } ]; diff --git a/apps/client/src/app/pages/blog/blog-page.html b/apps/client/src/app/pages/blog/blog-page.html index 73b4b090..babeec4c 100644 --- a/apps/client/src/app/pages/blog/blog-page.html +++ b/apps/client/src/app/pages/blog/blog-page.html @@ -8,6 +8,32 @@ finance + @if (hasPermissionForSubscription) { + + + + + + }
    diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index e647c54f..fa5a4751 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -7,7 +7,7 @@ import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config'; import { prettifySymbol } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, - Holding, + HoldingWithParents, PortfolioDetails, PortfolioPosition, User @@ -86,7 +86,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { value: number; }; }; - public topHoldings: Holding[]; + public topHoldings: HoldingWithParents[]; public topHoldingsMap: { [name: string]: { name: string; value: number }; }; @@ -490,6 +490,36 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { name, allocationInPercentage: this.totalValueInEtf > 0 ? value / this.totalValueInEtf : 0, + parents: Object.entries(this.portfolioDetails.holdings) + .map(([symbol, holding]) => { + if (holding.holdings.length > 0) { + const currentParentHolding = holding.holdings.find( + (parentHolding) => { + return parentHolding.name === name; + } + ); + + return currentParentHolding + ? { + allocationInPercentage: + currentParentHolding.valueInBaseCurrency / value, + name: holding.name, + position: holding, + symbol: prettifySymbol(symbol), + valueInBaseCurrency: + currentParentHolding.valueInBaseCurrency + } + : null; + } + + return null; + }) + .filter((item) => { + return item !== null; + }) + .sort((a, b) => { + return b.allocationInPercentage - a.allocationInPercentage; + }), valueInBaseCurrency: value }; }) diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html index 3431501f..f2dff76f 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html @@ -347,6 +347,7 @@ [locale]="user?.settings?.locale" [pageSize]="10" [topHoldings]="topHoldings" + (holdingClicked)="onSymbolChartClicked($event)" /> diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 8858faea..560dd5bb 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -2,7 +2,7 @@ import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.com import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { PageEvent } from '@angular/material/paginator'; import { HistoricalDataItem, InvestmentItem, diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts b/apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts index 885dc550..96260add 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts @@ -10,7 +10,7 @@ const routes: Routes = [ canActivate: [AuthGuard], component: FirePageComponent, path: '', - title: $localize`FIRE` + title: 'FIRE' } ]; diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts index ea83500c..897b9824 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts @@ -1,12 +1,7 @@ -import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { - PortfolioReport, - PortfolioReportRule, - User -} from '@ghostfolio/common/interfaces'; +import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; @@ -21,18 +16,11 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './fire-page.html' }) export class FirePageComponent implements OnDestroy, OnInit { - public accountClusterRiskRules: PortfolioReportRule[]; - public allocationClusterRiskRules: PortfolioReportRule[]; - public currencyClusterRiskRules: PortfolioReportRule[]; public deviceType: string; - public emergencyFundRules: PortfolioReportRule[]; - public feeRules: PortfolioReportRule[]; public fireWealth: Big; public hasImpersonationId: boolean; public hasPermissionToUpdateUserSettings: boolean; - public inactiveRules: PortfolioReportRule[]; public isLoading = false; - public isLoadingPortfolioReport = false; public user: User; public withdrawalRatePerMonth: Big; public withdrawalRatePerYear: Big; @@ -95,8 +83,6 @@ export class FirePageComponent implements OnDestroy, OnInit { this.changeDetectorRef.markForCheck(); } }); - - this.initializePortfolioReport(); } public onAnnualInterestRateChange(annualInterestRate: number) { @@ -133,21 +119,6 @@ export class FirePageComponent implements OnDestroy, OnInit { }); }); } - - public onRulesUpdated(event: UpdateUserSettingDto) { - this.dataService - .putUserSetting(event) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(() => { - this.userService - .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(); - - this.initializePortfolioReport(); - }); - } - public onSavingsRateChange(savingsRate: number) { this.dataService .putUserSetting({ savingsRate }) @@ -187,66 +158,4 @@ export class FirePageComponent implements OnDestroy, OnInit { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); } - - private initializePortfolioReport() { - this.isLoadingPortfolioReport = true; - - this.dataService - .fetchPortfolioReport() - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((portfolioReport) => { - this.inactiveRules = this.mergeInactiveRules(portfolioReport); - - this.accountClusterRiskRules = - portfolioReport.rules['accountClusterRisk']?.filter( - ({ isActive }) => { - return isActive; - } - ) ?? null; - - this.allocationClusterRiskRules = - portfolioReport.rules['allocationClusterRisk']?.filter( - ({ isActive }) => { - return isActive; - } - ) ?? null; - - this.currencyClusterRiskRules = - portfolioReport.rules['currencyClusterRisk']?.filter( - ({ isActive }) => { - return isActive; - } - ) ?? null; - - this.emergencyFundRules = - portfolioReport.rules['emergencyFund']?.filter(({ isActive }) => { - return isActive; - }) ?? null; - - this.feeRules = - portfolioReport.rules['fees']?.filter(({ isActive }) => { - return isActive; - }) ?? null; - - this.isLoadingPortfolioReport = false; - - this.changeDetectorRef.markForCheck(); - }); - } - - private mergeInactiveRules(report: PortfolioReport): PortfolioReportRule[] { - let inactiveRules: PortfolioReportRule[] = []; - - for (const category in report.rules) { - const rulesArray = report.rules[category]; - - inactiveRules = inactiveRules.concat( - rulesArray.filter(({ isActive }) => { - return !isActive; - }) - ); - } - - return inactiveRules; - } } diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html index 4eedca30..77fd1640 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.html +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -101,133 +101,3 @@ }
    - -
    -
    -
    -

    X-ray

    -

    - Ghostfolio X-ray uses static analysis to identify potential issues - and risks in your portfolio. - It will be highly configurable in the future: activate / deactivate - rules and customize the thresholds to match your personal investment - style. -

    -
    -

    - Emergency Fund - @if (user?.subscription?.type === 'Basic') { - - } -

    - -
    -
    -

    - Currency Cluster Risks - @if (user?.subscription?.type === 'Basic') { - - } -

    - -
    -
    -

    - Account Cluster Risks - @if (user?.subscription?.type === 'Basic') { - - } -

    - -
    -
    -

    - Allocation Cluster Risks - @if (user?.subscription?.type === 'Basic') { - - } -

    - -
    -
    -

    - Fees - @if (user?.subscription?.type === 'Basic') { - - } -

    - -
    - @if (inactiveRules?.length > 0) { -
    -

    Inactive

    - -
    - } -
    -
    -
    diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.module.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.module.ts index 60e3127d..a606ae1b 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.module.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.module.ts @@ -1,4 +1,3 @@ -import { GfRulesModule } from '@ghostfolio/client/components/rules/rules.module'; import { GfFireCalculatorComponent } from '@ghostfolio/ui/fire-calculator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -17,7 +16,6 @@ import { FirePageComponent } from './fire-page.component'; FirePageRoutingModule, GfFireCalculatorComponent, GfPremiumIndicatorComponent, - GfRulesModule, GfValueComponent, NgxSkeletonLoaderModule ], diff --git a/apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts b/apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts index 6146c573..20de6f8f 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts @@ -34,6 +34,11 @@ const routes: Routes = [ path: 'fire', loadChildren: () => import('./fire/fire-page.module').then((m) => m.FirePageModule) + }, + { + path: 'x-ray', + loadChildren: () => + import('./x-ray/x-ray-page.module').then((m) => m.XRayPageModule) } ], component: PortfolioPageComponent, diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts index 0c980e25..7f40bf1d 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts @@ -46,8 +46,13 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { }, { iconName: 'calculator-outline', - label: 'FIRE / X-ray', + label: 'FIRE ', path: ['/portfolio', 'fire'] + }, + { + iconName: 'scan-outline', + label: 'X-ray', + path: ['/portfolio', 'x-ray'] } ]; this.user = state.user; diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page-routing.module.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page-routing.module.ts new file mode 100644 index 00000000..091cbc49 --- /dev/null +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page-routing.module.ts @@ -0,0 +1,21 @@ +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { XRayPageComponent } from './x-ray-page.component'; + +const routes: Routes = [ + { + canActivate: [AuthGuard], + component: XRayPageComponent, + path: '', + title: 'X-ray' + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class XRayPageRoutingModule {} diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html new file mode 100644 index 00000000..cd03b49b --- /dev/null +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html @@ -0,0 +1,123 @@ +
    +
    +
    +

    X-ray

    +

    + Ghostfolio X-ray uses static analysis to uncover potential issues and + risks in your portfolio. Adjust the rules below and set custom + thresholds to align with your personal investment strategy. +

    +
    +

    + Emergency Fund + @if (user?.subscription?.type === 'Basic') { + + } +

    + +
    +
    +

    + Currency Cluster Risks + @if (user?.subscription?.type === 'Basic') { + + } +

    + +
    +
    +

    + Account Cluster Risks + @if (user?.subscription?.type === 'Basic') { + + } +

    + +
    +
    +

    + Economic Market Cluster Risks + @if (user?.subscription?.type === 'Basic') { + + } +

    + +
    +
    +

    + Fees + @if (user?.subscription?.type === 'Basic') { + + } +

    + +
    + @if (inactiveRules?.length > 0) { +
    +

    Inactive

    + +
    + } +
    +
    +
    diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.scss b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.scss new file mode 100644 index 00000000..5d4e87f3 --- /dev/null +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts new file mode 100644 index 00000000..36f42fc3 --- /dev/null +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts @@ -0,0 +1,150 @@ +import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; +import { DataService } from '@ghostfolio/client/services/data.service'; +import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { + PortfolioReportRule, + PortfolioReport +} from '@ghostfolio/common/interfaces'; +import { User } from '@ghostfolio/common/interfaces/user.interface'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; + +import { ChangeDetectorRef, Component } from '@angular/core'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + selector: 'gf-x-ray-page', + styleUrl: './x-ray-page.component.scss', + templateUrl: './x-ray-page.component.html' +}) +export class XRayPageComponent { + public accountClusterRiskRules: PortfolioReportRule[]; + public currencyClusterRiskRules: PortfolioReportRule[]; + public economicMarketClusterRiskRules: PortfolioReportRule[]; + public emergencyFundRules: PortfolioReportRule[]; + public feeRules: PortfolioReportRule[]; + public hasImpersonationId: boolean; + public hasPermissionToUpdateUserSettings: boolean; + public inactiveRules: PortfolioReportRule[]; + public isLoadingPortfolioReport = false; + public user: User; + + private unsubscribeSubject = new Subject(); + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private dataService: DataService, + private impersonationStorageService: ImpersonationStorageService, + private userService: UserService + ) {} + + public ngOnInit() { + this.impersonationStorageService + .onChangeHasImpersonation() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((impersonationId) => { + this.hasImpersonationId = !!impersonationId; + }); + + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + + this.hasPermissionToUpdateUserSettings = + this.user.subscription?.type === 'Basic' + ? false + : hasPermission( + this.user.permissions, + permissions.updateUserSettings + ); + + this.changeDetectorRef.markForCheck(); + } + }); + + this.initializePortfolioReport(); + } + + public onRulesUpdated(event: UpdateUserSettingDto) { + this.dataService + .putUserSetting(event) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + + this.initializePortfolioReport(); + }); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } + + private initializePortfolioReport() { + this.isLoadingPortfolioReport = true; + + this.dataService + .fetchPortfolioReport() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((portfolioReport) => { + this.inactiveRules = this.mergeInactiveRules(portfolioReport); + + this.accountClusterRiskRules = + portfolioReport.rules['accountClusterRisk']?.filter( + ({ isActive }) => { + return isActive; + } + ) ?? null; + + this.currencyClusterRiskRules = + portfolioReport.rules['currencyClusterRisk']?.filter( + ({ isActive }) => { + return isActive; + } + ) ?? null; + + this.economicMarketClusterRiskRules = + portfolioReport.rules['economicMarketClusterRisk']?.filter( + ({ isActive }) => { + return isActive; + } + ) ?? null; + + this.emergencyFundRules = + portfolioReport.rules['emergencyFund']?.filter(({ isActive }) => { + return isActive; + }) ?? null; + + this.feeRules = + portfolioReport.rules['fees']?.filter(({ isActive }) => { + return isActive; + }) ?? null; + + this.isLoadingPortfolioReport = false; + + this.changeDetectorRef.markForCheck(); + }); + } + + private mergeInactiveRules(report: PortfolioReport): PortfolioReportRule[] { + let inactiveRules: PortfolioReportRule[] = []; + + for (const category in report.rules) { + const rulesArray = report.rules[category]; + + inactiveRules = inactiveRules.concat( + rulesArray.filter(({ isActive }) => { + return !isActive; + }) + ); + } + + return inactiveRules; + } +} diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.module.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.module.ts new file mode 100644 index 00000000..bff4f4dc --- /dev/null +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.module.ts @@ -0,0 +1,22 @@ +import { GfRulesModule } from '@ghostfolio/client/components/rules/rules.module'; +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; + +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; + +import { XRayPageRoutingModule } from './x-ray-page-routing.module'; +import { XRayPageComponent } from './x-ray-page.component'; + +@NgModule({ + declarations: [XRayPageComponent], + imports: [ + CommonModule, + GfPremiumIndicatorComponent, + GfRulesModule, + NgxSkeletonLoaderModule, + XRayPageRoutingModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class XRayPageModule {} diff --git a/apps/client/src/app/pages/pricing/pricing-page.component.ts b/apps/client/src/app/pages/pricing/pricing-page.component.ts index 8bd0f1bd..f86a7590 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.component.ts +++ b/apps/client/src/app/pages/pricing/pricing-page.component.ts @@ -6,6 +6,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { translate } from '@ghostfolio/ui/i18n'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { StringValue } from 'ms'; import { StripeService } from 'ngx-stripe'; import { Subject } from 'rxjs'; import { catchError, switchMap, takeUntil } from 'rxjs/operators'; @@ -20,6 +21,7 @@ export class PricingPageComponent implements OnDestroy, OnInit { public baseCurrency: string; public coupon: number; public couponId: string; + public durationExtension: StringValue; public hasPermissionToUpdateUserSettings: boolean; public importAndExportTooltipBasic = translate( 'DATA_IMPORT_AND_EXPORT_TOOLTIP_BASIC' @@ -51,11 +53,12 @@ export class PricingPageComponent implements OnDestroy, OnInit { ) {} public ngOnInit() { - const { baseCurrency, subscriptions } = this.dataService.fetchInfo(); + const { baseCurrency, subscriptionOffers } = this.dataService.fetchInfo(); this.baseCurrency = baseCurrency; - this.coupon = subscriptions?.default?.coupon; - this.price = subscriptions?.default?.price; + this.coupon = subscriptionOffers?.default?.coupon; + this.durationExtension = subscriptionOffers?.default?.durationExtension; + this.price = subscriptionOffers?.default?.price; this.userService.stateChanged .pipe(takeUntil(this.unsubscribeSubject)) @@ -68,11 +71,18 @@ export class PricingPageComponent implements OnDestroy, OnInit { permissions.updateUserSettings ); - this.coupon = subscriptions?.[this.user?.subscription?.offer]?.coupon; + this.coupon = + subscriptionOffers?.[this.user?.subscription?.offer]?.coupon; this.couponId = - subscriptions?.[this.user.subscription.offer]?.couponId; - this.price = subscriptions?.[this.user?.subscription?.offer]?.price; - this.priceId = subscriptions?.[this.user.subscription.offer]?.priceId; + subscriptionOffers?.[this.user.subscription.offer]?.couponId; + this.durationExtension = + subscriptionOffers?.[ + this.user?.subscription?.offer + ]?.durationExtension; + this.price = + subscriptionOffers?.[this.user?.subscription?.offer]?.price; + this.priceId = + subscriptionOffers?.[this.user.subscription.offer]?.priceId; this.changeDetectorRef.markForCheck(); } diff --git a/apps/client/src/app/pages/pricing/pricing-page.html b/apps/client/src/app/pages/pricing/pricing-page.html index fe805ef6..605ad5d2 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.html +++ b/apps/client/src/app/pages/pricing/pricing-page.html @@ -101,6 +101,11 @@

    } + @if (durationExtension) { + + }
    @@ -159,6 +164,11 @@

    } + @if (durationExtension) { + + } @@ -289,6 +299,14 @@

    } + @if (durationExtension) { +
    +
    + Limited Offer! Get + {{ durationExtension }} extra +
    +
    + } diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts index ea14bbc6..39dbc481 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -35,9 +35,9 @@ export class GfProductPageComponent implements OnInit { ) {} public ngOnInit() { - const { subscriptions } = this.dataService.fetchInfo(); + const { subscriptionOffers } = this.dataService.fetchInfo(); - this.price = subscriptions?.default?.price; + this.price = subscriptionOffers?.default?.price; this.product1 = { founded: 2021, diff --git a/apps/client/src/app/services/admin.service.ts b/apps/client/src/app/services/admin.service.ts index 4c011e8c..5d252f00 100644 --- a/apps/client/src/app/services/admin.service.ts +++ b/apps/client/src/app/services/admin.service.ts @@ -5,6 +5,12 @@ import { UpdatePlatformDto } from '@ghostfolio/api/app/platform/update-platform. import { CreateTagDto } from '@ghostfolio/api/app/tag/create-tag.dto'; import { UpdateTagDto } from '@ghostfolio/api/app/tag/update-tag.dto'; import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; +import { + HEADER_KEY_SKIP_INTERCEPTOR, + HEADER_KEY_TOKEN, + PROPERTY_API_KEY_GHOSTFOLIO +} from '@ghostfolio/common/config'; +import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, @@ -13,6 +19,7 @@ import { AdminMarketData, AdminMarketDataDetails, AdminUsers, + DataProviderGhostfolioStatusResponse, EnhancedSymbolProfile, Filter } from '@ghostfolio/common/interfaces'; @@ -23,8 +30,9 @@ import { SortDirection } from '@angular/material/sort'; import { DataSource, MarketData, Platform, Tag } from '@prisma/client'; import { JobStatus } from 'bull'; import { format, parseISO } from 'date-fns'; -import { Observable, map } from 'rxjs'; +import { Observable, map, switchMap } from 'rxjs'; +import { environment } from '../../environments/environment'; import { DataService } from './data.service'; @Injectable({ @@ -136,6 +144,22 @@ export class AdminService { ); } + public fetchGhostfolioDataProviderStatus() { + return this.fetchAdminData().pipe( + switchMap(({ settings }) => { + return this.http.get( + `${environment.production ? 'https://ghostfol.io' : ''}/api/v1/data-providers/ghostfolio/status`, + { + headers: { + [HEADER_KEY_SKIP_INTERCEPTOR]: 'true', + [HEADER_KEY_TOKEN]: `Bearer ${settings[PROPERTY_API_KEY_GHOSTFOLIO]}` + } + } + ); + }) + ); + } + public fetchJobs({ status }: { status?: JobStatus[] }) { let params = new HttpParams(); @@ -156,8 +180,19 @@ export class AdminService { return this.http.get('/api/v1/tag'); } - public fetchUsers() { - return this.http.get('/api/v1/admin/user'); + public fetchUsers({ + skip, + take = DEFAULT_PAGE_SIZE + }: { + skip?: number; + take?: number; + }) { + let params = new HttpParams(); + + params = params.append('skip', skip); + params = params.append('take', take); + + return this.http.get('/api/v1/admin/user', { params }); } public gather7Days() { diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index abf4b21a..dccbb064 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -10,7 +10,6 @@ import { } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto'; import { PortfolioHoldingDetail } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-holding-detail.interface'; -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface'; import { DeleteOwnUserDto } from '@ghostfolio/api/app/user/delete-own-user.dto'; import { UserItem } from '@ghostfolio/api/app/user/interfaces/user-item.interface'; @@ -30,6 +29,7 @@ import { Filter, ImportResponse, InfoItem, + LookupResponse, OAuthResponse, PortfolioDetails, PortfolioDividends, @@ -464,10 +464,10 @@ export class DataService { } return this.http - .get<{ items: LookupItem[] }>('/api/v1/symbol/lookup', { params }) + .get('/api/v1/symbol/lookup', { params }) .pipe( - map((respose) => { - return respose.items; + map(({ items }) => { + return items; }) ); } @@ -532,7 +532,7 @@ export class DataService { }: { filters?: Filter[]; range?: DateRange; - }) { + } = {}) { let params = this.buildFiltersAsQueryParams({ filters }); if (range) { diff --git a/apps/client/src/app/services/user/user.service.ts b/apps/client/src/app/services/user/user.service.ts index 3ecc58c1..aa91a90b 100644 --- a/apps/client/src/app/services/user/user.service.ts +++ b/apps/client/src/app/services/user/user.service.ts @@ -65,6 +65,20 @@ export class UserService extends ObservableStore { }); } + if (user?.settings['filters.dataSource']) { + filters.push({ + id: user.settings['filters.dataSource'], + type: 'DATA_SOURCE' + }); + } + + if (user?.settings['filters.symbol']) { + filters.push({ + id: user.settings['filters.symbol'], + type: 'SYMBOL' + }); + } + if (user?.settings['filters.tags']) { filters.push({ id: user.settings['filters.tags'][0], diff --git a/apps/client/src/assets/images/blog/black-weeks-2024.jpg b/apps/client/src/assets/images/blog/black-weeks-2024.jpg new file mode 100644 index 00000000..c71827c5 Binary files /dev/null and b/apps/client/src/assets/images/blog/black-weeks-2024.jpg differ diff --git a/apps/client/src/assets/oss-friends.json b/apps/client/src/assets/oss-friends.json index 0fe72651..c3a12793 100644 --- a/apps/client/src/assets/oss-friends.json +++ b/apps/client/src/assets/oss-friends.json @@ -1,5 +1,5 @@ { - "createdAt": "2024-08-31T00:00:00.000Z", + "createdAt": "2024-11-27T00:00:00.000Z", "data": [ { "name": "Aptabase", @@ -53,7 +53,7 @@ }, { "name": "Formbricks", - "description": "Survey granular user segments at any point in the user journey. Gather up to 6x more insights with targeted micro-surveys. All open-source.", + "description": "Open source survey software and Experience Management Platform. Understand your customers, keep full control over your data.", "href": "https://formbricks.com" }, { @@ -81,6 +81,11 @@ "description": "Open source, end-to-end encrypted platform that lets you securely manage secrets and configs across your team, devices, and infrastructure.", "href": "https://infisical.com" }, + { + "name": "KeepHQ", + "description": "Keep is an open-source AIOps (AI for IT operations) platform", + "href": "https://www.keephq.dev" + }, { "name": "Langfuse", "description": "Open source LLM engineering platform. Debug, analyze and iterate together.", diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index d4260f52..751ef908 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -6,7 +6,7 @@ Característiques apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -14,7 +14,7 @@ Internacionalització apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -22,11 +22,11 @@ Iniciar sessió apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -58,7 +58,7 @@ Finances Personals apps/client/src/app/app.component.html - 56 + 57 @@ -66,11 +66,11 @@ Mercats apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -86,7 +86,7 @@ Recursos apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -94,7 +94,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -106,15 +106,15 @@ Sobre apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -122,7 +122,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -204,6 +204,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -214,7 +218,7 @@ Registre de canvis apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -226,11 +230,11 @@ Característiques apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -242,7 +246,7 @@ Preguntes Freqüents (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -254,7 +258,7 @@ Llicències apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -266,19 +270,19 @@ Preu apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -290,7 +294,7 @@ Política de privacitat apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -302,7 +306,7 @@ Comunitat apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -350,7 +354,7 @@ El risc d’assumir pèrdues en les inversions és substancial. No és recomanable invertir diners que pugui necessitar a curt termini. apps/client/src/app/app.component.html - 199 + 200 @@ -359,27 +363,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -448,7 +452,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -465,7 +469,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -482,7 +486,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -515,15 +519,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -561,13 +565,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -580,15 +588,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -621,19 +629,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -641,7 +649,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -679,6 +687,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -694,11 +706,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -722,7 +734,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -731,15 +743,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -1039,7 +1051,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -1143,7 +1159,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -1495,7 +1515,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -2135,7 +2155,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2179,7 +2199,7 @@ Plataformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -2187,7 +2207,7 @@ Etiquetes apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2203,7 +2223,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -2331,7 +2351,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2363,7 +2383,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -2375,7 +2395,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -2387,7 +2407,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -2395,7 +2415,7 @@ Millora la teva Subscripció apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -2407,7 +2427,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -2415,7 +2435,7 @@ Renova la teva Subscripció apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -2423,7 +2443,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -2431,7 +2451,7 @@ Tu apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -2443,7 +2463,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -2451,7 +2471,7 @@ El meu Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -2459,7 +2479,7 @@ Sobre Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -2471,7 +2491,7 @@ Iniciar Sessió apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -2483,7 +2503,7 @@ Primers Passos apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -2491,7 +2511,7 @@ Oooh! El testimoni de seguretat és incorrecte. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -2602,8 +2622,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -2643,7 +2663,7 @@ Taula apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -2651,7 +2671,7 @@ Gràfic apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -2659,7 +2679,7 @@ Gestionar Activitats apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -2821,6 +2841,10 @@ or or + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2970,8 +2994,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -3079,7 +3103,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3099,7 +3123,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3115,7 +3139,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3131,7 +3155,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3143,7 +3167,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3159,7 +3183,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3187,7 +3211,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -3199,7 +3223,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -3211,7 +3235,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -3223,7 +3247,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -3235,7 +3259,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -3295,7 +3319,7 @@ Please enter your coupon code: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -3303,7 +3327,7 @@ Could not redeem coupon code apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -3311,7 +3335,7 @@ Coupon code has been redeemed apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -3319,7 +3343,7 @@ Reload apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -3331,7 +3355,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -3339,7 +3363,7 @@ Try Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -3347,7 +3371,7 @@ Redeem Coupon apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -4187,7 +4211,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -4773,6 +4797,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -4975,7 +5003,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -5186,14 +5214,6 @@ 351 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -5226,28 +5246,20 @@ 67 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5299,11 +5311,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -5315,11 +5327,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -5331,11 +5343,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -5347,11 +5359,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -5379,7 +5391,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -5387,7 +5399,7 @@ For new investors who are just getting started with trading. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -5395,11 +5407,11 @@ Fully managed Ghostfolio cloud offering. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -5407,7 +5419,7 @@ For ambitious investors who need the full picture of their financial assets. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -5415,7 +5427,7 @@ Email and Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -5423,7 +5435,7 @@ One-time payment, no auto-renewal. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -5431,7 +5443,7 @@ It’s free. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -6035,7 +6047,7 @@ Find holding... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6043,7 +6055,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6051,7 +6063,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6059,7 +6071,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6067,7 +6079,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6075,7 +6087,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6083,7 +6095,7 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6091,7 +6103,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6127,7 +6139,7 @@ Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6135,7 +6147,7 @@ Reset Filters libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6143,7 +6155,7 @@ Apply Filters libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6271,7 +6283,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -6743,7 +6759,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -7030,8 +7046,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 903e82ce..b57ae2c1 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -22,7 +22,7 @@ Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst. apps/client/src/app/app.component.html - 199 + 200 @@ -166,7 +166,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -238,7 +242,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -554,7 +562,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -790,7 +798,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -834,7 +842,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -846,7 +854,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -866,7 +874,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -890,7 +898,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -898,7 +906,7 @@ Ressourcen apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -906,7 +914,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -918,19 +926,19 @@ Preise apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -942,15 +950,15 @@ Über apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -958,7 +966,7 @@ Ich apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -966,7 +974,7 @@ Mein Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -974,7 +982,7 @@ Über Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -986,11 +994,11 @@ Features apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1002,11 +1010,11 @@ Märkte apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1034,11 +1042,11 @@ Einloggen apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1046,7 +1054,7 @@ Ups! Falsches Sicherheits-Token. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1058,7 +1066,7 @@ Aktivitäten verwalten apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1096,6 +1104,10 @@ or oder + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1150,7 +1162,7 @@ Einloggen apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1245,8 +1257,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1346,7 +1358,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1362,7 +1374,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1382,7 +1394,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -1414,7 +1430,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1426,7 +1442,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1438,7 +1454,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1450,7 +1466,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1462,7 +1478,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1498,7 +1514,7 @@ Datenschutzbestimmungen apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1510,7 +1526,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -1592,6 +1608,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -1602,7 +1622,7 @@ Changelog apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1614,7 +1634,7 @@ Lizenz apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1646,7 +1666,7 @@ Bitte gebe deinen Gutscheincode ein: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1654,7 +1674,7 @@ Gutscheincode konnte nicht eingelöst werden apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1662,7 +1682,7 @@ Gutscheincode wurde eingelöst apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1670,7 +1690,7 @@ Neu laden apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1710,7 +1730,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1718,7 +1738,7 @@ Premium ausprobieren apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1726,7 +1746,7 @@ Gutschein einlösen apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -1962,7 +1982,7 @@ Features apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2145,14 +2165,6 @@ 214 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -2390,7 +2402,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2618,7 +2630,7 @@ Registrieren apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -3226,7 +3238,7 @@ Community apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3396,6 +3408,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3522,7 +3538,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3538,7 +3554,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3554,7 +3570,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3570,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3586,7 +3602,7 @@ Abonnement abschliessen apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3598,7 +3614,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3618,11 +3634,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3634,11 +3650,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3650,11 +3666,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3674,7 +3690,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3682,7 +3698,7 @@ Für Einsteiger, die gerade mit dem Börsenhandel beginnen. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3690,11 +3706,11 @@ Vollständig verwaltetes Ghostfolio Cloud-Angebot. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3702,7 +3718,7 @@ Für ambitionierte Anleger, die den vollständigen Überblick über ihr Anlagevermögen benötigen. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3710,7 +3726,7 @@ Einmalige Zahlung, keine automatische Erneuerung. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3726,7 +3742,7 @@ Es ist kostenlos. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3741,8 +3757,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3762,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3782,11 +3798,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3810,7 +3826,7 @@ E-Mail und Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3870,7 +3886,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3886,7 +3902,7 @@ Abonnement erneuern apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3894,7 +3910,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3982,7 +3998,7 @@ Plattformen apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4130,7 +4146,7 @@ Private Finanzen apps/client/src/app/app.component.html - 56 + 57 @@ -4138,7 +4154,7 @@ Häufig gestellte Fragen (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4714,7 +4730,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4922,7 +4938,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5191,7 +5207,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5224,15 +5240,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5270,13 +5286,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5289,27 +5309,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5378,7 +5398,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5395,7 +5415,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5412,15 +5432,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5453,19 +5473,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5473,7 +5493,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5511,6 +5531,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5526,11 +5550,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5554,7 +5578,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5563,15 +5587,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5870,28 +5894,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray nutzt statische Analysen, um potenzielle Probleme und Risiken in deinem Portfolio zu identifizieren. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Währungsklumpenrisiken - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Kontoklumpenrisiken - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5983,7 +5999,7 @@ Finde Position... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6351,7 +6367,7 @@ Seit Wochenbeginn libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Seit Monatsbeginn libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Seit Jahresbeginn libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Filter zurücksetzen libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ Jahr libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ Jahre libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Anlageklassen libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Filter anwenden libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internationalisierung apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Mehr anzeigen libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Tabelle apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Diagramm apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Inaktiv - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7092,18 +7108,18 @@ Threshold Min - Threshold Min + Schwellenwert (Minimum) apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 Threshold Max - Threshold Max + Schwellenwert (Maximum) apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Schliessen apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ Keine automatische Erneuerung. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Ups! Es konnten leider keine Assets gefunden werden. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEU apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key + + Set API key API-Schlüssel setzen apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Benachrichtige mich - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Erhalte Zugang zu 100’000+ Tickern von über 50 Handelsplätzen @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allokationsklumpenrisiken - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Lexikon @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Schwellenwertbereich + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray nutzt statische Analysen, um potenzielle Probleme und Risiken in deinem Portfolio aufzudecken. Passe die untenstehenden Regeln an und lege individuelle Schwellenwerte fest, um sie mit deiner persönlichen Anlagestrategie abzustimmen. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Wirtschaftsraumklumpenrisiken + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + von + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + täglichen Anfragen + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + API-Schlüssel löschen + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Möchtest du den API-Schlüssel wirklich löschen? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Bitte gib den API-Schlüssel ein: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Benachrichtige mich + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + Ich habe einen API-Schlüssel + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 74664782..13d3706b 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -23,7 +23,7 @@ El riesgo de pérdida en trading puede ser sustancial. No es aconsejable invertir dinero que puedas necesitar a corto plazo. apps/client/src/app/app.component.html - 199 + 200 @@ -167,7 +167,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -239,7 +243,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -555,7 +563,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -791,7 +799,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -835,7 +843,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -847,7 +855,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -867,7 +875,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -891,7 +899,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -899,7 +907,7 @@ Recursos apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -907,7 +915,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -919,19 +927,19 @@ Precios apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -943,15 +951,15 @@ Sobre apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -959,7 +967,7 @@ apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -967,7 +975,7 @@ Mi Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -975,7 +983,7 @@ Sobre Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -987,11 +995,11 @@ Funcionalidades apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1003,11 +1011,11 @@ Mercados apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1035,11 +1043,11 @@ Iniciar sesión apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1047,7 +1055,7 @@ Vaya! Token de seguridad incorrecto. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1059,7 +1067,7 @@ Gestión de las operaciones apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1097,6 +1105,10 @@ or o + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1151,7 +1163,7 @@ Iniciar sesión apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1246,8 +1258,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1347,7 +1359,7 @@ Etiquetas apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1363,7 +1375,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1383,7 +1395,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -1415,7 +1431,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1427,7 +1443,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1439,7 +1455,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1451,7 +1467,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1463,7 +1479,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1499,7 +1515,7 @@ Política de privacidad apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1511,7 +1527,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -1593,6 +1609,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -1603,7 +1623,7 @@ Registro de cambios apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1615,7 +1635,7 @@ Licencia de uso apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1647,7 +1667,7 @@ Por favor, ingresa tu código de cupón: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1655,7 +1675,7 @@ No se puede canjear este código de cupón apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1663,7 +1683,7 @@ El codigo de cupón ha sido canjeado apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1671,7 +1691,7 @@ Refrescar apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1711,7 +1731,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1719,7 +1739,7 @@ Prueba Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1727,7 +1747,7 @@ Canjea el cupón apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -1963,7 +1983,7 @@ Funcionalidades apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2146,14 +2166,6 @@ 214 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -2391,7 +2403,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2619,7 +2631,7 @@ Comenzar apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -3227,7 +3239,7 @@ Comunidad apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3397,6 +3409,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3523,7 +3539,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3539,7 +3555,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3555,7 +3571,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3571,7 +3587,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3587,7 +3603,7 @@ Mejorar plan apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3599,7 +3615,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3619,11 +3635,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3635,11 +3651,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3651,11 +3667,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3675,7 +3691,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3683,7 +3699,7 @@ Para nuevos inversores que estan empezando con el trading. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3691,11 +3707,11 @@ Oferta en la nube de Ghostfolio totalmente administrada. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3703,7 +3719,7 @@ Para inversores ambiciosos que necesitan una visión completa de sus activos financieros apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3711,7 +3727,7 @@ Pago único, sin renovación automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3727,7 +3743,7 @@ Es gratis. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3742,8 +3758,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3763,7 +3779,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3783,11 +3799,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3811,7 +3827,7 @@ Soporte a Traves de Email y Chat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3871,7 +3887,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3887,7 +3903,7 @@ Renovar Plan apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3895,7 +3911,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3983,7 +3999,7 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4131,7 +4147,7 @@ Personal Finance apps/client/src/app/app.component.html - 56 + 57 @@ -4139,7 +4155,7 @@ Frequently Asked Questions (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4715,7 +4731,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4923,7 +4939,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5192,7 +5208,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5225,15 +5241,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5271,13 +5287,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5290,27 +5310,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5379,7 +5399,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5396,7 +5416,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5413,15 +5433,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5454,19 +5474,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5474,7 +5494,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5512,6 +5532,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5527,11 +5551,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5555,7 +5579,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5564,15 +5588,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5871,28 +5895,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5984,7 +6000,7 @@ Find holding... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6352,7 +6368,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6360,7 +6376,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6368,7 +6384,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6376,7 +6392,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6384,7 +6400,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6420,7 +6436,7 @@ Reiniciar filtros libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6428,7 +6444,7 @@ año libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6436,7 +6452,7 @@ años libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6444,7 +6460,7 @@ Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6452,7 +6468,7 @@ Aplicar filtros libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6624,7 +6640,7 @@ Internacionalización apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6688,7 +6704,7 @@ Mostrar más libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6728,7 +6744,7 @@ Tabla apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6736,7 +6752,7 @@ Grafico apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7031,8 +7047,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7096,7 +7112,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7104,7 +7120,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7112,7 +7128,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7128,7 +7144,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7304,7 +7320,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7320,15 +7336,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7339,14 +7355,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7379,14 +7387,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7437,6 +7437,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index bf8efff8..ee5c6eb6 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -6,7 +6,7 @@ Le risque de perte en investissant peut être important. Il est déconseillé d’investir de l’argent dont vous pourriez avoir besoin à court terme. apps/client/src/app/app.component.html - 199 + 200 @@ -178,7 +178,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -298,7 +302,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -614,7 +622,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -954,7 +962,7 @@ Étiquettes apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -970,7 +978,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1058,7 +1066,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -1086,7 +1094,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1146,7 +1154,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -1178,7 +1186,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -1190,7 +1198,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -1202,7 +1210,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -1210,7 +1218,7 @@ Ressources apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -1218,7 +1226,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -1230,19 +1238,19 @@ Prix apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -1254,15 +1262,15 @@ À propos apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -1270,7 +1278,7 @@ Moi apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -1278,7 +1286,7 @@ Mon Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -1286,7 +1294,7 @@ À propos de Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -1298,11 +1306,11 @@ Fonctionnalités apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1314,11 +1322,11 @@ Marchés apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1334,7 +1342,7 @@ Se connecter apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1346,7 +1354,7 @@ Démarrer apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -1354,11 +1362,11 @@ Se connecter apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1366,7 +1374,7 @@ Oups! Jeton de Sécurité Incorrect. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1378,7 +1386,7 @@ Gérer les Activités apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1456,6 +1464,10 @@ or ou + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1593,8 +1605,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1726,7 +1738,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1738,7 +1750,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1750,7 +1762,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1762,7 +1774,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1774,7 +1786,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1846,7 +1858,7 @@ Historique des modifications apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1858,7 +1870,7 @@ License apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1882,7 +1894,7 @@ Politique de Vie Privée apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1910,7 +1922,7 @@ Veuillez entrer votre code promotionnel : apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1918,7 +1930,7 @@ Le code promotionnel n’a pas pu être appliqué apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1926,7 +1938,7 @@ Le code promotionnel a été appliqué apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1934,7 +1946,7 @@ Rafraîchir apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1974,7 +1986,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1982,7 +1994,7 @@ Essayer Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1990,7 +2002,7 @@ Utiliser un Code Promotionnel apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -2022,7 +2034,7 @@ Communauté apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2262,7 +2274,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -2344,6 +2356,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2374,7 +2390,7 @@ Fonctionnalités apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2797,14 +2813,6 @@ 351 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -3154,7 +3162,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -3396,6 +3408,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3522,7 +3538,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3538,7 +3554,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3554,7 +3570,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3570,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3586,7 +3602,7 @@ Mettre à niveau l’Abonnement apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3598,7 +3614,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3618,11 +3634,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3634,11 +3650,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3650,11 +3666,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3674,7 +3690,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3682,7 +3698,7 @@ Pour les nouveaux investisseurs qui débutent en Bourse. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3690,11 +3706,11 @@ Offre Ghostfolio cloud complètement administrée. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3702,7 +3718,7 @@ Pour les investisseurs ambitieux qui ont besoin d’une vue complète de leurs actifs financiers. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3710,7 +3726,7 @@ Paiement unique, sans auto-renouvellement. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3726,7 +3742,7 @@ C’est gratuit. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3741,8 +3757,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3762,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3782,11 +3798,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3810,7 +3826,7 @@ Support par E-mail et Tchat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3870,7 +3886,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3886,7 +3902,7 @@ Renouveler l’Abonnement apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3894,7 +3910,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3982,7 +3998,7 @@ Platformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4130,7 +4146,7 @@ Finance Personnelle apps/client/src/app/app.component.html - 56 + 57 @@ -4138,7 +4154,7 @@ Questions Fréquentes (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4714,7 +4730,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4922,7 +4938,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5191,7 +5207,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5224,15 +5240,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5270,13 +5286,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5289,27 +5309,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5378,7 +5398,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5395,7 +5415,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5412,15 +5432,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5453,19 +5473,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5473,7 +5493,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5511,6 +5531,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5526,11 +5550,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5554,7 +5578,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5563,15 +5587,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5870,28 +5894,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray utilise l'analyse statique pour identifier de potentiels problèmes et risques dans votre portefeuille. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Risques de change - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Risques liés aux regroupements de comptes - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5983,7 +5999,7 @@ Chercher un actif... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6351,7 +6367,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Réinitialiser les Filtres libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ année libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ années libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Types d'Actifs libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Appliquer les Filtres libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internationalisation apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Voir plus libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Tableau apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Inactif - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 9364d835..5d840375 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -23,7 +23,7 @@ Il rischio di perdita nel trading può essere notevole. Non è consigliabile investire denaro di cui potresti avere bisogno a breve termine. apps/client/src/app/app.component.html - 199 + 200 @@ -167,7 +167,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -239,7 +243,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -555,7 +563,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -791,7 +799,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -835,7 +843,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -847,7 +855,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -867,7 +875,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -891,7 +899,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -899,7 +907,7 @@ Risorse apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -907,7 +915,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -919,19 +927,19 @@ Prezzi apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -943,15 +951,15 @@ Informazioni su apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -959,7 +967,7 @@ Io apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -967,7 +975,7 @@ Il mio Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -975,7 +983,7 @@ Informazioni su Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -987,11 +995,11 @@ Funzionalità apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1003,11 +1011,11 @@ Mercati apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1035,11 +1043,11 @@ Accedi apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1047,7 +1055,7 @@ Ops! Token di sicurezza errato. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1059,7 +1067,7 @@ Gestione delle attività apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1097,6 +1105,10 @@ or oppure + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1151,7 +1163,7 @@ Accedi apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1246,8 +1258,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1347,7 +1359,7 @@ Tag apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1363,7 +1375,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1383,7 +1395,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -1415,7 +1431,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1427,7 +1443,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1439,7 +1455,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1451,7 +1467,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1463,7 +1479,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1499,7 +1515,7 @@ Informativa sulla privacy apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1511,7 +1527,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -1593,6 +1609,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -1603,7 +1623,7 @@ Registro delle modifiche apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1615,7 +1635,7 @@ Licenza d’uso apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1647,7 +1667,7 @@ Inserisci il tuo codice del buono: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1655,7 +1675,7 @@ Impossibile riscattare il codice del buono apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1663,7 +1683,7 @@ Il codice del buono è stato riscattato apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1671,7 +1691,7 @@ Ricarica apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1711,7 +1731,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1719,7 +1739,7 @@ Prova Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1727,7 +1747,7 @@ Riscatta il buono apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -1963,7 +1983,7 @@ Funzionalità apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2146,14 +2166,6 @@ 214 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -2391,7 +2403,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2619,7 +2631,7 @@ Inizia apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -2872,7 +2884,7 @@ Hello, has shared a Portfolio with you! - Salve, ha condiviso un Portafoglio con te! + Salve, ha condiviso un Portafoglio con te! apps/client/src/app/pages/public/public-page.html 4 @@ -3227,7 +3239,7 @@ Comunità apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3397,6 +3409,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3523,7 +3539,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3539,7 +3555,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3555,7 +3571,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3571,7 +3587,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3587,7 +3603,7 @@ Aggiorna il piano apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3599,7 +3615,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3619,11 +3635,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3635,11 +3651,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3651,11 +3667,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3675,7 +3691,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3683,7 +3699,7 @@ Per i nuovi investitori che hanno appena iniziato a fare trading. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3691,11 +3707,11 @@ Offerta cloud Ghostfolio completamente gestita. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3703,7 +3719,7 @@ Per gli investitori ambiziosi che hanno bisogno di un quadro completo dei propri asset finanziari. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3711,7 +3727,7 @@ Pagamento una tantum, senza rinnovo automatico. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3727,7 +3743,7 @@ È gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3742,8 +3758,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3763,7 +3779,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3783,11 +3799,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3811,7 +3827,7 @@ Supporto via email e chat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3871,7 +3887,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3887,7 +3903,7 @@ Rinnova il piano apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3895,7 +3911,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3983,7 +3999,7 @@ Piattaforme apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4131,7 +4147,7 @@ Finanza personale apps/client/src/app/app.component.html - 56 + 57 @@ -4139,7 +4155,7 @@ Domande più frequenti (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4715,7 +4731,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4923,7 +4939,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5192,7 +5208,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5225,15 +5241,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5271,13 +5287,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5290,27 +5310,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5379,7 +5399,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5396,7 +5416,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5413,15 +5433,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5454,19 +5474,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5474,7 +5494,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5512,6 +5532,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5527,11 +5551,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5555,7 +5579,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5564,15 +5588,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5871,28 +5895,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray usa l'analisi statica per identificare potenziali problemi e rischi del tuo portafoglio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks - Currency Cluster Risks + Rischio di Concentrazione Valutario - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks - Account Cluster Risks + Rischi di Concentrazione dei Conti - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5984,7 +6000,7 @@ Trova possedimenti... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6237,7 +6253,7 @@ Restricted view - Restricted view + Vista limitata apps/client/src/app/components/access-table/access-table.component.html 26 @@ -6352,15 +6368,15 @@ Da inizio settimana libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 WTD - WTD + Settimana corrente libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6368,15 +6384,15 @@ Da inizio mese libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 MTD - MTD + Mese corrente libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6384,7 +6400,7 @@ Da inizio anno libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6420,7 +6436,7 @@ Reset Filtri libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6428,7 +6444,7 @@ anno libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6436,7 +6452,7 @@ anni libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6444,7 +6460,7 @@ classi degli Asset libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6452,7 +6468,7 @@ Applica i Filtri libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6597,7 +6613,7 @@ {VAR_PLURAL, plural, =1 {activity} other {activities}} - {VAR_PLURAL, plural, =1 {activity} other {activities}} + {VAR_PLURAL, plural, =1 {attività} other {attività}} apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 14 @@ -6624,7 +6640,7 @@ Internazionalizzazione apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6688,7 +6704,7 @@ Visualizza di più libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6728,7 +6744,7 @@ Tabella apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6736,7 +6752,7 @@ Grafico apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -6781,7 +6797,7 @@ Family Office - Family Office + Ufficio familiare apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 87 @@ -6837,7 +6853,7 @@ User Experience - User Experience + Esperienza Utente apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 98 @@ -7031,8 +7047,8 @@ Inactive Inattivo - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7061,7 +7077,7 @@ Copy link to clipboard - Copy link to clipboard + Copia link negli appunti apps/client/src/app/components/access-table/access-table.component.html 70 @@ -7069,7 +7085,7 @@ Portfolio Snapshot - Portfolio Snapshot + Stato del Portfolio apps/client/src/app/components/admin-jobs/admin-jobs.html 39 @@ -7077,7 +7093,7 @@ Change with currency effect Change - Change with currency effect Change + Cambio con effetto valuta Cambia apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 50 @@ -7085,7 +7101,7 @@ Performance with currency effect Performance - Performance with currency effect Performance + Prestazioni con effetto valuta Prestazioni apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 69 @@ -7093,31 +7109,31 @@ Threshold Min - Threshold Min + Soglia Minima apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 Threshold Max - Threshold Max + Soglia Massima apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 Close - Close + Chiudi apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 Customize - Customize + Personalizza apps/client/src/app/components/rule/rule.component.html 67 @@ -7125,15 +7141,15 @@ No auto-renewal. - No auto-renewal. + No rinnovo automatico. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 Today - Today + Oggi apps/client/src/app/pages/public/public-page.html 24 @@ -7141,7 +7157,7 @@ This year - This year + Anno corrente apps/client/src/app/pages/public/public-page.html 42 @@ -7149,7 +7165,7 @@ From the beginning - From the beginning + Dall'inizio apps/client/src/app/pages/public/public-page.html 60 @@ -7157,7 +7173,7 @@ Oops! Invalid currency. - Oops! Invalid currency. + Oops! Valuta sbagliata. apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 49 @@ -7165,7 +7181,7 @@ This page has been archived. - This page has been archived. + Questa pagina è stata archiviata. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 14 @@ -7173,7 +7189,7 @@ is Open Source Software - is Open Source Software + è un programma Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 139 @@ -7181,7 +7197,7 @@ is not Open Source Software - is not Open Source Software + non è un programma Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 146 @@ -7189,7 +7205,7 @@ is Open Source Software - is Open Source Software + è un programma Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 156 @@ -7197,7 +7213,7 @@ is not Open Source Software - is not Open Source Software + non è un programma Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 163 @@ -7205,7 +7221,7 @@ can be self-hosted - can be self-hosted + può essere ospitato in proprio apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 178 @@ -7213,7 +7229,7 @@ cannot be self-hosted - cannot be self-hosted + non può essere ospitato in proprio apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 185 @@ -7221,7 +7237,7 @@ can be self-hosted - can be self-hosted + può essere ospitato in proprio apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 195 @@ -7229,7 +7245,7 @@ cannot be self-hosted - cannot be self-hosted + non può essere ospitato in proprio apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 202 @@ -7237,7 +7253,7 @@ can be used anonymously - can be used anonymously + può essere usato anonimamente apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 217 @@ -7245,7 +7261,7 @@ cannot be used anonymously - cannot be used anonymously + non può essere usato anonimamente apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 224 @@ -7253,7 +7269,7 @@ can be used anonymously - can be used anonymously + può essere usato anonimamente apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 234 @@ -7261,7 +7277,7 @@ cannot be used anonymously - cannot be used anonymously + non può essere usato anonimamente apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 241 @@ -7269,7 +7285,7 @@ offers a free plan - offers a free plan + ha un piano gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 256 @@ -7277,7 +7293,7 @@ does not offer a free plan - does not offer a free plan + non ha un piano gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 263 @@ -7285,7 +7301,7 @@ offers a free plan - offers a free plan + ha un piano gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 273 @@ -7293,7 +7309,7 @@ does not offer a free plan - does not offer a free plan + non ha un piano gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 280 @@ -7301,15 +7317,15 @@ Oops! Could not find any assets. - Oops! Could not find any assets. + Oops! Non ho trovato alcun asset. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 Data Providers - Data Providers + Fornitori di dati apps/client/src/app/components/admin-settings/admin-settings.component.html 4 @@ -7317,39 +7333,31 @@ NEW - NEW + NUOVO apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Imposta API Key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 Want to stay updated? Click below to get notified as soon as it’s available. - Want to stay updated? Click below to get notified as soon as it’s available. + Vuoi seguire le novità? Clicca sotto per essere notificato appena è disponibile. apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges - Get access to 100’000+ tickers from over 50 exchanges + Ottieni accesso a oltre 100’000+ titoli da oltre 50 borse libs/ui/src/lib/i18n.ts 24 @@ -7357,7 +7365,7 @@ Ukraine - Ukraine + Ucraina libs/ui/src/lib/i18n.ts 92 @@ -7365,7 +7373,7 @@ Skip - Skip + Salta apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 83 @@ -7373,23 +7381,15 @@ Join now - Join now + Iscriviti adesso apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary - Glossary + Glossario apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts 10 @@ -7401,7 +7401,7 @@ Guides - Guides + Guide apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts 10 @@ -7413,7 +7413,7 @@ guides - guides + guide snake-case apps/client/src/app/pages/resources/overview/resources-overview.component.ts @@ -7426,7 +7426,7 @@ glossary - glossary + glossario snake-case apps/client/src/app/pages/resources/overview/resources-overview.component.ts @@ -7437,6 +7437,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 9a12eb0f..b8dbd38a 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -22,7 +22,7 @@ Het risico op verlies bij handelen kan aanzienlijk zijn. Het is niet aan te raden om geld te investeren dat je misschien op korte termijn nodig heeft. apps/client/src/app/app.component.html - 199 + 200 @@ -166,7 +166,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -238,7 +242,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -554,7 +562,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -790,7 +798,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -834,7 +842,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -846,7 +854,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -866,7 +874,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -890,7 +898,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -898,7 +906,7 @@ Middelen apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -906,7 +914,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -918,19 +926,19 @@ Prijzen apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -942,15 +950,15 @@ Over apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -958,7 +966,7 @@ Ik apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -966,7 +974,7 @@ Mijn Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -974,7 +982,7 @@ Over Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -986,11 +994,11 @@ Functionaliteiten apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1002,11 +1010,11 @@ Markten apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1034,11 +1042,11 @@ Aanmelden apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1046,7 +1054,7 @@ Oeps! Onjuiste beveiligingstoken. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1058,7 +1066,7 @@ Activiteiten beheren apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1096,6 +1104,10 @@ or of + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1150,7 +1162,7 @@ Aanmelden apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1245,8 +1257,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1346,7 +1358,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1362,7 +1374,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1382,7 +1394,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -1414,7 +1430,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1426,7 +1442,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1438,7 +1454,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1450,7 +1466,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1462,7 +1478,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1498,7 +1514,7 @@ Privacybeleid apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1510,7 +1526,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -1592,6 +1608,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -1602,7 +1622,7 @@ Changelog apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1614,7 +1634,7 @@ Licentie apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1646,7 +1666,7 @@ Voer je couponcode in: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1654,7 +1674,7 @@ Kon je kortingscode niet inwisselen apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1662,7 +1682,7 @@ Je couponcode is ingewisseld apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1670,7 +1690,7 @@ Herladen apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1710,7 +1730,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1718,7 +1738,7 @@ Probeer Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1726,7 +1746,7 @@ Coupon inwisselen apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -1962,7 +1982,7 @@ Functionaliteiten apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2145,14 +2165,6 @@ 214 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -2390,7 +2402,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2618,7 +2630,7 @@ Aan de slag apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -3226,7 +3238,7 @@ Gemeenschap apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3396,6 +3408,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3522,7 +3538,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3538,7 +3554,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3554,7 +3570,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3570,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3586,7 +3602,7 @@ Abonnement uitbreiden apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3598,7 +3614,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3618,11 +3634,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3634,11 +3650,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3650,11 +3666,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3674,7 +3690,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3682,7 +3698,7 @@ Voor nieuwe beleggers die net beginnen met handelen. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3690,11 +3706,11 @@ Volledig beheerd Ghostfolio cloud-aanbod. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3702,7 +3718,7 @@ Voor ambitieuze beleggers die een volledig beeld willen hebben van hun financiële assets. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3710,7 +3726,7 @@ Eenmalige betaling, geen automatische verlenging. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3726,7 +3742,7 @@ Het is gratis. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3741,8 +3757,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3762,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3782,11 +3798,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3810,7 +3826,7 @@ Ondersteuning via e-mail en chat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3870,7 +3886,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3886,7 +3902,7 @@ Abonnement Vernieuwen apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3894,7 +3910,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3982,7 +3998,7 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4130,7 +4146,7 @@ Persoonlijke financiën apps/client/src/app/app.component.html - 56 + 57 @@ -4138,7 +4154,7 @@ Veelgestelde Vragen apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4714,7 +4730,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4922,7 +4938,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5191,7 +5207,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5224,15 +5240,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5270,13 +5286,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5289,27 +5309,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5378,7 +5398,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5395,7 +5415,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5412,15 +5432,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5453,19 +5473,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5473,7 +5493,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5511,6 +5531,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5526,11 +5550,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5554,7 +5578,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5563,15 +5587,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5870,28 +5894,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5983,7 +5999,7 @@ Find holding... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6351,7 +6367,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Reset Filters libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Apply Filters libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internationalization apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Chart apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 3a183045..76e4decb 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -7,27 +7,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -96,7 +96,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -129,15 +129,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -175,13 +175,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -194,7 +198,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -211,15 +215,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -252,19 +256,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -272,7 +276,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -310,6 +314,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -325,7 +333,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -342,11 +350,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -370,7 +378,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -379,15 +387,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -467,7 +475,7 @@ Finanse Osobiste apps/client/src/app/app.component.html - 56 + 57 @@ -475,11 +483,11 @@ Rynki apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -495,7 +503,7 @@ Zasoby apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -503,7 +511,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -515,15 +523,15 @@ O programie apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -531,7 +539,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -613,6 +621,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -623,7 +635,7 @@ Dziennik Zmian apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -635,11 +647,11 @@ Funkcje apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -651,7 +663,7 @@ Często Zadawane Pytania (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -663,7 +675,7 @@ Licencja apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -675,19 +687,19 @@ Cennik apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -699,7 +711,7 @@ Polityka Prywatności apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -711,7 +723,7 @@ Społeczność apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -759,7 +771,7 @@ Ryzyko strat na rynku może być znaczne. Nie jest zalecane inwestowanie pieniędzy, które mogą być potrzebne w krótkim okresie. apps/client/src/app/app.component.html - 199 + 200 @@ -967,7 +979,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -1071,7 +1087,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -1387,7 +1407,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -1963,7 +1983,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2007,7 +2027,7 @@ Platformy apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -2015,7 +2035,7 @@ Tagi apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2031,7 +2051,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -2159,7 +2179,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2191,7 +2211,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -2203,7 +2223,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -2215,7 +2235,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -2223,7 +2243,7 @@ Ja apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -2235,7 +2255,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -2243,7 +2263,7 @@ Moje Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -2251,7 +2271,7 @@ O Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -2263,7 +2283,7 @@ Zaloguj się apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -2275,7 +2295,7 @@ Rozpocznij apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -2283,11 +2303,11 @@ Zaloguj się apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -2295,7 +2315,7 @@ Ups! Nieprawidłowy token bezpieczeństwa. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -2307,7 +2327,7 @@ Zarządzaj Aktywnościami apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -2469,6 +2489,10 @@ or lub + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2574,8 +2598,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -2622,8 +2646,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -2811,7 +2835,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -2831,7 +2855,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -2847,7 +2871,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -2863,7 +2887,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -2875,7 +2899,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -2891,7 +2915,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -2915,7 +2939,7 @@ Ulepsz Plan apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -2927,7 +2951,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -2939,7 +2963,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -2951,7 +2975,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -2963,7 +2987,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -2975,7 +2999,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -2987,7 +3011,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -3019,7 +3043,7 @@ Wpisz kod kuponu: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -3027,7 +3051,7 @@ Nie udało się zrealizować kodu kuponu apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -3035,7 +3059,7 @@ Kupon został zrealizowany apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -3043,7 +3067,7 @@ Odśwież apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -3055,7 +3079,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -3063,7 +3087,7 @@ Wypróbuj Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -3071,7 +3095,7 @@ Wykorzystaj kupon apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -3571,7 +3595,7 @@ Funkcje apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -3803,7 +3827,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -4381,6 +4405,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -4583,7 +4611,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4722,14 +4750,6 @@ 351 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -4754,28 +4774,20 @@ 40 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray wykorzystuje analizę statyczną do identyfikacji potencjalnych problemów i zagrożeń w Twoim portfelu. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -4847,11 +4859,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -4863,11 +4875,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -4879,11 +4891,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -4895,11 +4907,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -4927,7 +4939,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -4935,7 +4947,7 @@ Dla początkujących inwestorów, którzy dopiero zaczynają swoją przygodę z tradingiem. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -4943,11 +4955,11 @@ W pełni zarządzana oferta Ghostfolio w chmurze. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -4955,7 +4967,7 @@ Dla ambitnych inwestorów, którzy potrzebują pełnego obrazu swoich aktywów finansowych. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -4963,7 +4975,7 @@ Wsparcie przez E-mail i Czat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -4971,7 +4983,7 @@ Odnów Plan apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -4979,7 +4991,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -4987,7 +4999,7 @@ Płatność jednorazowa, bez automatycznego odnawiania. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -5003,7 +5015,7 @@ It’s free. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -5551,7 +5563,7 @@ Znajdź portfel akcji... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -5675,7 +5687,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -6351,7 +6367,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Resetuj Filtry libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Klasy Aktywów libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Zastosuj Filtry libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internacjonalizacja apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Pokaż więcej libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Tabela apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Wykres apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Nieaktywny - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 39404bbf..404e4d2b 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -6,7 +6,7 @@ O risco de perda em investimentos pode ser substancial. Não é aconselhável investir dinheiro que possa vir a precisar a curto prazo. apps/client/src/app/app.component.html - 199 + 200 @@ -178,7 +178,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -298,7 +302,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -614,7 +622,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -922,7 +930,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -950,7 +958,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1010,7 +1018,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -1042,7 +1050,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -1054,7 +1062,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -1066,7 +1074,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -1074,7 +1082,7 @@ Recursos apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -1082,7 +1090,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -1094,19 +1102,19 @@ Preços apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -1118,15 +1126,15 @@ Sobre apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -1134,7 +1142,7 @@ Eu apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -1142,7 +1150,7 @@ O meu Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -1150,7 +1158,7 @@ Sobre o Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -1162,11 +1170,11 @@ Funcionalidades apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -1178,11 +1186,11 @@ Mercados apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -1198,7 +1206,7 @@ Iniciar sessão apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1210,7 +1218,7 @@ Começar apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -1218,11 +1226,11 @@ Iniciar sessão apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -1230,7 +1238,7 @@ Oops! Token de Segurança Incorreto. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1242,7 +1250,7 @@ Gerir Atividades apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -1328,6 +1336,10 @@ or ou + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -1465,8 +1477,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -1650,7 +1662,7 @@ Marcadores apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1666,7 +1678,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1686,7 +1698,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -1706,7 +1722,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -1718,7 +1734,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -1730,7 +1746,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -1742,7 +1758,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -1754,7 +1770,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -1826,7 +1842,7 @@ Changelog apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -1838,7 +1854,7 @@ Licença apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -1862,7 +1878,7 @@ Política de Privacidade apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -1890,7 +1906,7 @@ Por favor, insira o seu código de cupão: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -1898,7 +1914,7 @@ Não foi possível resgatar o código de cupão apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -1906,7 +1922,7 @@ Código de cupão foi resgatado apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -1914,7 +1930,7 @@ Atualizar apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -1954,7 +1970,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -1962,7 +1978,7 @@ Experimentar Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -1970,7 +1986,7 @@ Resgatar Cupão apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -2182,7 +2198,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -2264,6 +2280,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2294,7 +2314,7 @@ Funcionalidades apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -2673,14 +2693,6 @@ 294 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE FIRE @@ -3270,7 +3282,7 @@ Comunidade apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3396,6 +3408,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -3522,7 +3538,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -3538,7 +3554,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -3554,7 +3570,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -3570,7 +3586,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -3586,7 +3602,7 @@ Atualizar Plano apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -3598,7 +3614,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -3618,11 +3634,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -3634,11 +3650,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -3650,11 +3666,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -3674,7 +3690,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -3682,7 +3698,7 @@ Para novos investidores que estão a começar a investir agora. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -3690,11 +3706,11 @@ Ghostfolio hospedado na nuvem, totalmente gerido. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -3702,7 +3718,7 @@ Para investidores ambiciosos que precisam de ter uma visão completa de seus ativos financeiros. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -3710,7 +3726,7 @@ Pagamento único, sem renovação automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -3726,7 +3742,7 @@ É gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -3741,8 +3757,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -3762,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -3782,11 +3798,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -3810,7 +3826,7 @@ Suporte por Email e Chat apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -3870,7 +3886,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -3886,7 +3902,7 @@ Renovar Plano apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -3894,7 +3910,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -3982,7 +3998,7 @@ Plataformas apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -4130,7 +4146,7 @@ Finanças pessoais apps/client/src/app/app.component.html - 56 + 57 @@ -4138,7 +4154,7 @@ Perguntas Frequentes (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -4714,7 +4730,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4922,7 +4938,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -5191,7 +5207,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -5224,15 +5240,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -5270,13 +5286,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5289,27 +5309,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -5378,7 +5398,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -5395,7 +5415,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -5412,15 +5432,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -5453,19 +5473,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -5473,7 +5493,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -5511,6 +5531,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -5526,11 +5550,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -5554,7 +5578,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -5563,15 +5587,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -5870,28 +5894,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5983,7 +5999,7 @@ Find holding... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6351,7 +6367,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Reset Filters libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Apply Filters libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internationalization apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Chart apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 7d5d657c..307817d0 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -7,27 +7,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -96,7 +96,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -129,15 +129,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -175,13 +175,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -194,7 +198,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -211,15 +215,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -252,19 +256,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -272,7 +276,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -310,6 +314,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -325,7 +333,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -342,11 +350,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -370,7 +378,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -379,15 +387,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -443,7 +451,7 @@ Kişisel Finans apps/client/src/app/app.component.html - 56 + 57 @@ -451,11 +459,11 @@ Piyasalar apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -471,7 +479,7 @@ Piyasalar apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -479,7 +487,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -491,15 +499,15 @@ Hakkında apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -507,7 +515,7 @@ Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -589,6 +597,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -599,7 +611,7 @@ Değişiklik Günlüğü apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -611,11 +623,11 @@ Özellikler apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -627,7 +639,7 @@ Sıkça Sorulan Sorular (SSS) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -639,7 +651,7 @@ Lisans apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -651,19 +663,19 @@ Fiyatlandırma apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -675,7 +687,7 @@ Gizlilik Politikası apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -687,7 +699,7 @@ Topluluk apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -735,7 +747,7 @@ Alım satımda kayıp riski büyük boyutta olabilir. Kısa vadede ihtiyaç duyabileceğiniz parayla yatırım yapmak tavsiye edilmez. apps/client/src/app/app.component.html - 199 + 200 @@ -931,7 +943,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -1035,7 +1051,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -1351,7 +1371,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -1751,7 +1771,7 @@ Etiketler apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1767,7 +1787,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -1879,7 +1899,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1923,7 +1943,7 @@ Platformlar apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -1943,7 +1963,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -2023,7 +2043,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2055,7 +2075,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -2067,7 +2087,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -2079,7 +2099,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -2087,7 +2107,7 @@ Ben apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -2095,7 +2115,7 @@ Ghostfolio’m apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -2103,7 +2123,7 @@ Ghostfolio Hakkında apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -2115,7 +2135,7 @@ Giriş apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -2127,7 +2147,7 @@ Haydi Başlayalım apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -2135,11 +2155,11 @@ Giriş apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -2147,7 +2167,7 @@ Hay Allah! Güvenlik anahtarı yanlış. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -2159,7 +2179,7 @@ İşlemleri Yönet apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -2321,6 +2341,10 @@ or veya + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2458,8 +2482,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -2614,8 +2638,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -2655,7 +2679,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -2675,7 +2699,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -2691,7 +2715,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -2707,7 +2731,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -2719,7 +2743,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -2735,7 +2759,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -2759,7 +2783,7 @@ Üyeliğinizi Yükseltin apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -2771,7 +2795,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -2783,7 +2807,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -2795,7 +2819,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -2807,7 +2831,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -2819,7 +2843,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -2831,7 +2855,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -3123,7 +3147,7 @@ Özellikler apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -3343,7 +3367,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -3861,6 +3885,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -4071,7 +4099,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4210,14 +4238,6 @@ 351 - - FIRE - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE Finansal Özgürlük ve Erken Emeklilik (FIRE) @@ -4311,11 +4331,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -4327,11 +4347,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -4343,11 +4363,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -4359,11 +4379,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -4391,7 +4411,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -4399,7 +4419,7 @@ Alım satıma henüz başlamış yeni yatırımcılar için. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -4407,11 +4427,11 @@ Eksiksiz yönetilen Ghostfolio bulut teklifi. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -4419,7 +4439,7 @@ Finansal varlıklarının tamamını görmeye ihtiyaç duyan hırslı yatırımcılar için. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -4427,7 +4447,7 @@ E-posta ve Sohbet Desteği apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -4435,7 +4455,7 @@ Aboneliği Yenile apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -4443,7 +4463,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -4451,7 +4471,7 @@ Tek seferlik ödeme, otomatik yenileme yok. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -4467,7 +4487,7 @@ Ücretsiz. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -4919,7 +4939,7 @@ Lütfen kupon kodunuzu girin: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -4927,7 +4947,7 @@ Kupon kodu kullanılamadı apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -4935,7 +4955,7 @@ Kupon kodu kullanıldı apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -4943,7 +4963,7 @@ Yeniden Yükle apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -4979,7 +4999,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -4987,7 +5007,7 @@ Premium’u Deneyin apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -4995,7 +5015,7 @@ Kupon Kullan apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -5343,7 +5363,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -5870,28 +5894,20 @@ 10 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray, portföyünüzdeki potansiyel sorunlar ve riskleri belirlemek için statik analiz yöntemleri uygulamaktadır. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks Kur Kümelenme Riskleri (Currency Cluster Risks) - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks Hesap Kümelenme Riski (Account Cluster Risks) - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -5983,7 +5999,7 @@ Sahip olunan varlıkları bul... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -6351,7 +6367,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6359,7 +6375,7 @@ WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6367,7 +6383,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6375,7 +6391,7 @@ MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6383,7 +6399,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6419,7 +6435,7 @@ Reset Filters libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6427,7 +6443,7 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6435,7 +6451,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6443,7 +6459,7 @@ Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6451,7 +6467,7 @@ Apply Filters libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6623,7 +6639,7 @@ Internationalization apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6687,7 +6703,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6727,7 +6743,7 @@ Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6735,7 +6751,7 @@ Chart apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7030,8 +7046,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7095,7 +7111,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7103,7 +7119,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7111,7 +7127,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7127,7 +7143,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7303,7 +7319,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7319,15 +7335,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7338,14 +7354,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7378,14 +7386,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7436,6 +7436,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index fe58f08f..51a7c32e 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -7,27 +7,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -95,7 +95,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -127,15 +127,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -173,13 +173,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -191,7 +195,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -207,15 +211,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -247,19 +251,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -267,7 +271,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -305,6 +309,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -319,7 +327,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -335,11 +343,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -363,7 +371,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -371,15 +379,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -456,18 +464,18 @@ Personal Finance apps/client/src/app/app.component.html - 56 + 57 Markets apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -482,7 +490,7 @@ Resources apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -490,7 +498,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -501,22 +509,22 @@ About apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 Blog apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -598,6 +606,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -607,7 +619,7 @@ Changelog apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -618,11 +630,11 @@ Features apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -633,7 +645,7 @@ Frequently Asked Questions (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -644,7 +656,7 @@ License apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -655,19 +667,19 @@ Pricing apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -678,7 +690,7 @@ Privacy Policy apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -689,7 +701,7 @@ Community apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -736,7 +748,7 @@ The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. apps/client/src/app/app.component.html - 199 + 200 @@ -939,7 +951,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -1040,7 +1056,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -1336,7 +1356,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -1865,7 +1885,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1905,14 +1925,14 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1928,7 +1948,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -2041,7 +2061,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2070,7 +2090,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -2081,7 +2101,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -2092,14 +2112,14 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 Me apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -2110,21 +2130,21 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 My Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 About Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -2135,7 +2155,7 @@ Sign in apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -2146,25 +2166,25 @@ Get started apps/client/src/app/components/header/header.component.html - 407 + 422 Sign in apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 Oops! Incorrect Security Token. apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -2175,7 +2195,7 @@ Manage Activities apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -2319,6 +2339,10 @@ or + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2415,8 +2439,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -2458,8 +2482,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -2628,7 +2652,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -2647,7 +2671,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -2662,7 +2686,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -2677,7 +2701,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -2688,7 +2712,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -2703,7 +2727,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -2724,7 +2748,7 @@ Upgrade Plan apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -2736,7 +2760,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -2747,7 +2771,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -2758,7 +2782,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -2769,7 +2793,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -2780,7 +2804,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -2791,7 +2815,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -2819,28 +2843,28 @@ Please enter your coupon code: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 Could not redeem coupon code apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 Coupon code has been redeemed apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 Reload apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -2851,21 +2875,21 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 Try Premium apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 Redeem Coupon apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -3314,7 +3338,7 @@ Features apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -3522,7 +3546,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -4034,6 +4058,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -4215,7 +4243,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4338,13 +4366,6 @@ 351 - - FIRE - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE @@ -4366,25 +4387,18 @@ 40 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -4449,11 +4463,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -4464,11 +4478,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -4479,11 +4493,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -4494,11 +4508,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -4523,46 +4537,46 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 For new investors who are just getting started with trading. apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 Fully managed Ghostfolio cloud offering. apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 For ambitious investors who need the full picture of their financial assets. apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 Email and Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 Renew Plan apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -4570,14 +4584,14 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 One-time payment, no auto-renewal. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -4591,7 +4605,7 @@ It’s free. apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -5111,7 +5125,7 @@ Find holding... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -5235,7 +5249,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -5774,35 +5792,35 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 Week to date libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 Month to date libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 MTD libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 WTD libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -5827,7 +5845,7 @@ Reset Filters libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -5841,28 +5859,28 @@ year libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 years libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 Apply Filters libs/ui/src/lib/assistant/assistant.html - 167 + 195 Asset Classes libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6014,7 +6032,7 @@ Internationalization apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6070,7 +6088,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6105,14 +6123,14 @@ Chart apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6370,8 +6388,8 @@ Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -6399,7 +6417,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -6420,7 +6438,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -6448,14 +6466,14 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -6609,7 +6627,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -6619,13 +6637,6 @@ 23 - - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Ukraine @@ -6633,11 +6644,11 @@ 92 - - Set API Key + + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -6651,7 +6662,7 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 @@ -6714,13 +6725,6 @@ 28 - - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Skip @@ -6728,6 +6732,76 @@ 83 + + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + + + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 876bcd84..d6b9d7bf 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -8,27 +8,27 @@ snake-case apps/client/src/app/app.component.ts - 63 + 64 apps/client/src/app/app.component.ts - 65 + 66 apps/client/src/app/app.component.ts - 69 + 70 apps/client/src/app/app.component.ts - 73 + 74 apps/client/src/app/components/header/header.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 85 + 86 apps/client/src/app/core/paths.ts @@ -97,7 +97,7 @@ snake-case apps/client/src/app/app.component.ts - 76 + 77 apps/client/src/app/core/paths.ts @@ -130,15 +130,15 @@ snake-case apps/client/src/app/app.component.ts - 77 + 78 apps/client/src/app/components/header/header.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 86 + 87 apps/client/src/app/core/paths.ts @@ -176,13 +176,17 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 14 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 15 + apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts 14 apps/client/src/app/pages/pricing/pricing-page.component.ts - 39 + 41 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -195,7 +199,7 @@ snake-case apps/client/src/app/app.component.ts - 70 + 71 apps/client/src/app/core/paths.ts @@ -212,15 +216,15 @@ snake-case apps/client/src/app/app.component.ts - 78 + 79 apps/client/src/app/components/header/header.component.ts - 82 + 83 apps/client/src/app/components/header/header.component.ts - 87 + 88 apps/client/src/app/core/paths.ts @@ -253,19 +257,19 @@ snake-case apps/client/src/app/app.component.ts - 79 + 80 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 48 + 61 apps/client/src/app/components/header/header.component.ts - 83 + 84 apps/client/src/app/components/header/header.component.ts - 88 + 89 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -273,7 +277,7 @@ apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 38 + 40 apps/client/src/app/core/http-response.interceptor.ts @@ -311,6 +315,10 @@ apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts 16 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts + 16 + apps/client/src/app/pages/faq/saas/saas-page.component.ts 15 @@ -326,7 +334,7 @@ snake-case apps/client/src/app/app.component.ts - 74 + 75 apps/client/src/app/core/paths.ts @@ -343,11 +351,11 @@ snake-case apps/client/src/app/app.component.ts - 80 + 81 apps/client/src/app/components/header/header.component.ts - 89 + 90 apps/client/src/app/core/auth.guard.ts @@ -371,7 +379,7 @@ apps/client/src/app/pages/pricing/pricing-page.component.ts - 40 + 42 @@ -380,15 +388,15 @@ snake-case apps/client/src/app/app.component.ts - 81 + 82 apps/client/src/app/components/header/header.component.ts - 84 + 85 apps/client/src/app/components/header/header.component.ts - 90 + 91 apps/client/src/app/core/paths.ts @@ -468,7 +476,7 @@ 个人财务 apps/client/src/app/app.component.html - 56 + 57 @@ -476,11 +484,11 @@ 市场 apps/client/src/app/app.component.html - 60 + 61 apps/client/src/app/components/header/header.component.html - 383 + 398 apps/client/src/app/components/home-market/home-market.html @@ -496,7 +504,7 @@ 资源 apps/client/src/app/app.component.html - 63 + 64 apps/client/src/app/components/header/header.component.html @@ -504,7 +512,7 @@ apps/client/src/app/components/header/header.component.html - 286 + 291 apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -516,15 +524,15 @@ 关于 apps/client/src/app/app.component.html - 69 + 70 apps/client/src/app/components/header/header.component.html - 112 + 117 apps/client/src/app/components/header/header.component.html - 354 + 364 @@ -532,7 +540,7 @@ 博客 apps/client/src/app/app.component.html - 72 + 73 apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html @@ -614,6 +622,10 @@ apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html 187 + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 167 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -624,7 +636,7 @@ 变更日志 apps/client/src/app/app.component.html - 76 + 77 apps/client/src/app/pages/about/changelog/changelog-page.html @@ -636,11 +648,11 @@ 功能 apps/client/src/app/app.component.html - 78 + 79 apps/client/src/app/components/header/header.component.html - 341 + 351 apps/client/src/app/pages/features/features-page.html @@ -652,7 +664,7 @@ 常见问题 (FAQ) apps/client/src/app/app.component.html - 82 + 83 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -664,7 +676,7 @@ 许可 apps/client/src/app/app.component.html - 87 + 88 apps/client/src/app/pages/about/license/license-page.html @@ -676,19 +688,19 @@ 价钱 apps/client/src/app/app.component.html - 96 + 97 apps/client/src/app/components/header/header.component.html - 98 + 99 apps/client/src/app/components/header/header.component.html - 297 + 303 apps/client/src/app/components/header/header.component.html - 368 + 379 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -700,7 +712,7 @@ 隐私政策 apps/client/src/app/app.component.html - 102 + 103 apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html @@ -712,7 +724,7 @@ 社区 apps/client/src/app/app.component.html - 120 + 121 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -760,7 +772,7 @@ 交易损失的风险可能很大。不建议将短期内可能需要的资金进行投资。 apps/client/src/app/app.component.html - 199 + 200 @@ -976,7 +988,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 12 + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 @@ -1080,7 +1096,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 26 + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 @@ -1396,7 +1416,7 @@ apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 83 + 135 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -1980,7 +2000,7 @@ apps/client/src/app/components/header/header.component.html - 258 + 263 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2024,7 +2044,7 @@ 平台 apps/client/src/app/components/admin-settings/admin-settings.component.html - 39 + 59 @@ -2032,7 +2052,7 @@ 标签 apps/client/src/app/components/admin-settings/admin-settings.component.html - 45 + 65 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2048,7 +2068,7 @@ libs/ui/src/lib/assistant/assistant.html - 127 + 155 @@ -2176,7 +2196,7 @@ apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts - 41 + 46 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -2208,7 +2228,7 @@ apps/client/src/app/components/header/header.component.html - 240 + 245 @@ -2220,7 +2240,7 @@ apps/client/src/app/components/header/header.component.html - 250 + 255 @@ -2232,7 +2252,7 @@ apps/client/src/app/components/header/header.component.html - 274 + 279 @@ -2240,7 +2260,7 @@ apps/client/src/app/components/header/header.component.html - 206 + 211 @@ -2252,7 +2272,7 @@ apps/client/src/app/components/header/header.component.html - 224 + 229 @@ -2260,7 +2280,7 @@ 我的 Ghostfolio apps/client/src/app/components/header/header.component.html - 265 + 270 @@ -2268,7 +2288,7 @@ 关于 Ghostfolio apps/client/src/app/components/header/header.component.html - 306 + 316 apps/client/src/app/pages/about/overview/about-overview-page.html @@ -2280,7 +2300,7 @@ 登入 apps/client/src/app/components/header/header.component.html - 397 + 412 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -2292,7 +2312,7 @@ 开始使用 apps/client/src/app/components/header/header.component.html - 407 + 422 @@ -2300,11 +2320,11 @@ 登入 apps/client/src/app/app-routing.module.ts - 141 + 150 apps/client/src/app/components/header/header.component.ts - 229 + 230 @@ -2312,7 +2332,7 @@ 哎呀!安全令牌不正确。 apps/client/src/app/components/header/header.component.ts - 244 + 245 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -2324,7 +2344,7 @@ 管理活动 apps/client/src/app/components/home-holdings/home-holdings.html - 65 + 63 @@ -2486,6 +2506,10 @@ or + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 35 + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2591,8 +2615,8 @@ 84 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 198 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 @@ -2639,8 +2663,8 @@ 89 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 122 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 12 @@ -2828,7 +2852,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 203 + 213 @@ -2848,7 +2872,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 217 @@ -2864,7 +2888,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 221 @@ -2880,7 +2904,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 225 @@ -2892,7 +2916,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 230 + 240 @@ -2908,7 +2932,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 242 + 252 @@ -2932,7 +2956,7 @@ 升级计划 apps/client/src/app/components/header/header.component.html - 180 + 185 apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -2944,7 +2968,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 278 + 288 @@ -2956,7 +2980,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 210 + 223 @@ -2968,7 +2992,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -2980,7 +3004,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -2992,7 +3016,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -3004,7 +3028,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 249 + 262 @@ -3036,7 +3060,7 @@ 请输入您的优惠券代码: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 115 + 124 @@ -3044,7 +3068,7 @@ 无法兑换优惠券代码 apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 125 + 134 @@ -3052,7 +3076,7 @@ 优惠券代码已兑换 apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 137 + 146 @@ -3060,7 +3084,7 @@ 重新加载 apps/client/src/app/components/user-account-membership/user-account-membership.component.ts - 138 + 147 @@ -3072,7 +3096,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 264 + 274 @@ -3080,7 +3104,7 @@ 尝试高级版 apps/client/src/app/components/user-account-membership/user-account-membership.html - 41 + 51 @@ -3088,7 +3112,7 @@ 兑换优惠券 apps/client/src/app/components/user-account-membership/user-account-membership.html - 55 + 65 @@ -3588,7 +3612,7 @@ 功能 apps/client/src/app/app-routing.module.ts - 65 + 74 @@ -3820,7 +3844,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 306 + 324 @@ -4398,6 +4422,10 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 + + libs/ui/src/lib/assistant/assistant.html + 127 + Load Dividends @@ -4600,7 +4628,7 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 88 + 181 @@ -4739,14 +4767,6 @@ 351 - - FIRE - 财务独立 - - apps/client/src/app/pages/portfolio/fire/fire-page-routing.module.ts - 13 - - FIRE 财务独立 @@ -4771,28 +4791,20 @@ 40 - - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray 使用静态分析来识别您的投资组合中的潜在问题和风险。 - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 111 - - Currency Cluster Risks 货币集群风险 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 141 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 31 Account Cluster Risks 账户集群风险 - apps/client/src/app/pages/portfolio/fire/fire-page.html - 160 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 50 @@ -4864,11 +4876,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 129 + 134 apps/client/src/app/pages/pricing/pricing-page.html - 191 + 201 @@ -4880,11 +4892,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 133 + 138 apps/client/src/app/pages/pricing/pricing-page.html - 195 + 205 @@ -4896,11 +4908,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 137 + 142 apps/client/src/app/pages/pricing/pricing-page.html - 199 + 209 @@ -4912,11 +4924,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 141 + 146 apps/client/src/app/pages/pricing/pricing-page.html - 219 + 229 @@ -4944,7 +4956,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 153 + 158 @@ -4952,7 +4964,7 @@ 适合刚开始交易的新投资者。 apps/client/src/app/pages/pricing/pricing-page.html - 123 + 128 @@ -4960,11 +4972,11 @@ 完全托管的 Ghostfolio 云产品。 apps/client/src/app/pages/pricing/pricing-page.html - 152 + 157 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 261 @@ -4972,7 +4984,7 @@ 适合需要全面了解其金融资产的雄心勃勃的投资者。 apps/client/src/app/pages/pricing/pricing-page.html - 184 + 194 @@ -4980,7 +4992,7 @@ 电子邮件和聊天支持 apps/client/src/app/pages/pricing/pricing-page.html - 247 + 257 @@ -4988,7 +5000,7 @@ 更新计划 apps/client/src/app/components/header/header.component.html - 186 + 191 apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -4996,7 +5008,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 294 @@ -5004,7 +5016,7 @@ 一次性付款,无自动续订。 apps/client/src/app/pages/pricing/pricing-page.html - 288 + 298 @@ -5020,7 +5032,7 @@ 免费。 apps/client/src/app/pages/pricing/pricing-page.html - 309 + 327 @@ -5600,7 +5612,7 @@ 查找持有... libs/ui/src/lib/assistant/assistant.component.ts - 139 + 144 @@ -5740,7 +5752,11 @@ libs/ui/src/lib/top-holdings/top-holdings.component.html - 46 + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 @@ -6352,7 +6368,7 @@ 今年迄今为止 libs/ui/src/lib/assistant/assistant.component.ts - 220 + 233 @@ -6360,7 +6376,7 @@ 本周至今 libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6368,7 +6384,7 @@ 本月至今 libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6376,7 +6392,7 @@ 最大输运量 libs/ui/src/lib/assistant/assistant.component.ts - 216 + 229 @@ -6384,7 +6400,7 @@ 世界贸易组织 libs/ui/src/lib/assistant/assistant.component.ts - 212 + 225 @@ -6412,7 +6428,7 @@ 重置过滤器 libs/ui/src/lib/assistant/assistant.html - 157 + 185 @@ -6428,7 +6444,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 224 + 237 @@ -6436,7 +6452,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 246 + 259 @@ -6444,7 +6460,7 @@ 应用过滤器 libs/ui/src/lib/assistant/assistant.html - 167 + 195 @@ -6452,7 +6468,7 @@ 资产类别 libs/ui/src/lib/assistant/assistant.html - 138 + 166 @@ -6624,7 +6640,7 @@ Internationalization apps/client/src/app/app-routing.module.ts - 79 + 88 @@ -6688,7 +6704,7 @@ Show more libs/ui/src/lib/top-holdings/top-holdings.component.html - 81 + 174 @@ -6728,7 +6744,7 @@ Table apps/client/src/app/components/home-holdings/home-holdings.html - 17 + 16 @@ -6736,7 +6752,7 @@ Chart apps/client/src/app/components/home-holdings/home-holdings.html - 20 + 19 @@ -7031,8 +7047,8 @@ Inactive Inactive - apps/client/src/app/pages/portfolio/fire/fire-page.html - 217 + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 107 @@ -7096,7 +7112,7 @@ Threshold Min apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 9 + 54 @@ -7104,7 +7120,7 @@ Threshold Max apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 44 + 92 @@ -7112,7 +7128,7 @@ Close apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html - 77 + 129 @@ -7128,7 +7144,7 @@ No auto-renewal. apps/client/src/app/components/user-account-membership/user-account-membership.html - 62 + 72 @@ -7304,7 +7320,7 @@ Oops! Could not find any assets. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html - 37 + 40 @@ -7320,15 +7336,15 @@ NEW apps/client/src/app/components/admin-settings/admin-settings.component.html - 14 + 15 - - Set API Key - Set API Key + + Set API key + Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 29 + 48 @@ -7339,14 +7355,6 @@ 23 - - Notify me - Notify me - - apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html - 32 - - Get access to 100’000+ tickers from over 50 exchanges Get access to 100’000+ tickers from over 50 exchanges @@ -7379,14 +7387,6 @@ 93 - - Allocation Cluster Risks - Allocation Cluster Risks - - apps/client/src/app/pages/portfolio/fire/fire-page.html - 179 - - Glossary Glossary @@ -7437,6 +7437,86 @@ 21 + + Threshold range + Threshold range + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 5 + + + + Economic Market Cluster Risks + Economic Market Cluster Risks + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 69 + + + + of + of + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 29 + + + + daily requests + daily requests + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 31 + + + + Remove API key + Remove API key + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Do you really want to delete the API key? + Do you really want to delete the API key? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 80 + + + + Please enter your Ghostfolio API key: + Please enter your Ghostfolio API key: + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts + 45 + + + + Notify me + Notify me + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 32 + + + + I have an API key + I have an API key + + apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html + 42 + + diff --git a/docker/docker-compose.build.yml b/docker/docker-compose.build.yml index 02442c0c..96829ad3 100644 --- a/docker/docker-compose.build.yml +++ b/docker/docker-compose.build.yml @@ -1,6 +1,8 @@ +name: ghostfolio_build services: ghostfolio: build: ../ + container_name: ghostfolio-build init: true env_file: - ../.env @@ -23,6 +25,7 @@ services: postgres: image: docker.io/library/postgres:15 + container_name: gf-postgres-build env_file: - ../.env healthcheck: @@ -35,6 +38,7 @@ services: redis: image: docker.io/library/redis:alpine + container_name: gf-redis-build env_file: - ../.env command: ['redis-server', '--requirepass', $REDIS_PASSWORD] diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 91f8f2c0..39a1d56e 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -1,7 +1,8 @@ +name: ghostfolio_dev services: postgres: image: docker.io/library/postgres:15 - container_name: postgres + container_name: gf-postgres-dev restart: unless-stopped env_file: - ../.env @@ -12,7 +13,7 @@ services: redis: image: docker.io/library/redis:alpine - container_name: redis + container_name: gf-redis-dev restart: unless-stopped env_file: - ../.env diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 642912b7..c6ec5b3d 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,6 +1,8 @@ +name: ghostfolio services: ghostfolio: image: docker.io/ghostfolio/ghostfolio:latest + container_name: ghostfolio init: true cap_drop: - ALL @@ -27,6 +29,7 @@ services: postgres: image: docker.io/library/postgres:15 + container_name: gf-postgres cap_drop: - ALL cap_add: @@ -49,6 +52,7 @@ services: redis: image: docker.io/library/redis:alpine + container_name: gf-redis user: '999:1000' cap_drop: - ALL diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index fbd416bb..7608e43a 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -106,17 +106,21 @@ export const PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS: JobOptions = { export const HEADER_KEY_IMPERSONATION = 'Impersonation-Id'; export const HEADER_KEY_TIMEZONE = 'Timezone'; export const HEADER_KEY_TOKEN = 'Authorization'; +export const HEADER_KEY_SKIP_INTERCEPTOR = 'X-Skip-Interceptor'; export const MAX_TOP_HOLDINGS = 50; export const NUMERICAL_PRECISION_THRESHOLD = 100000; +export const PROPERTY_API_KEY_GHOSTFOLIO = 'API_KEY_GHOSTFOLIO'; export const PROPERTY_BENCHMARKS = 'BENCHMARKS'; export const PROPERTY_BETTER_UPTIME_MONITOR_ID = 'BETTER_UPTIME_MONITOR_ID'; export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS'; export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; export const PROPERTY_DATA_SOURCE_MAPPING = 'DATA_SOURCE_MAPPING'; +export const PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS = + 'DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS'; export const PROPERTY_DEMO_USER_ID = 'DEMO_USER_ID'; export const PROPERTY_IS_DATA_GATHERING_ENABLED = 'IS_DATA_GATHERING_ENABLED'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; diff --git a/libs/common/src/lib/interfaces/admin-users.interface.ts b/libs/common/src/lib/interfaces/admin-users.interface.ts index 24eb45c8..89e16575 100644 --- a/libs/common/src/lib/interfaces/admin-users.interface.ts +++ b/libs/common/src/lib/interfaces/admin-users.interface.ts @@ -1,10 +1,12 @@ import { Role } from '@prisma/client'; export interface AdminUsers { + count: number; users: { accountCount: number; country: string; createdAt: Date; + dailyApiRequests: number; engagement: number; id: string; lastActivity: Date; diff --git a/libs/common/src/lib/interfaces/holding-with-parents.interface.ts b/libs/common/src/lib/interfaces/holding-with-parents.interface.ts new file mode 100644 index 00000000..df3f3296 --- /dev/null +++ b/libs/common/src/lib/interfaces/holding-with-parents.interface.ts @@ -0,0 +1,5 @@ +import { Holding } from './holding.interface'; + +export interface HoldingWithParents extends Holding { + parents?: Holding[]; +} diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index 0ec04594..4d5ce66d 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -19,10 +19,12 @@ import type { Export } from './export.interface'; import type { FilterGroup } from './filter-group.interface'; import type { Filter } from './filter.interface'; import type { HistoricalDataItem } from './historical-data-item.interface'; +import type { HoldingWithParents } from './holding-with-parents.interface'; import type { Holding } from './holding.interface'; import type { InfoItem } from './info-item.interface'; import type { InvestmentItem } from './investment-item.interface'; import type { LineChartItem } from './line-chart-item.interface'; +import type { LookupItem } from './lookup-item.interface'; import type { PortfolioChart } from './portfolio-chart.interface'; import type { PortfolioDetails } from './portfolio-details.interface'; import type { PortfolioDividends } from './portfolio-dividends.interface'; @@ -38,15 +40,20 @@ import type { Position } from './position.interface'; import type { Product } from './product'; import type { AccountBalancesResponse } from './responses/account-balances-response.interface'; import type { BenchmarkResponse } from './responses/benchmark-response.interface'; +import type { DataProviderGhostfolioStatusResponse } from './responses/data-provider-ghostfolio-status-response.interface'; +import type { DividendsResponse } from './responses/dividends-response.interface'; import type { ResponseError } from './responses/errors.interface'; +import type { HistoricalResponse } from './responses/historical-response.interface'; import type { ImportResponse } from './responses/import-response.interface'; +import type { LookupResponse } from './responses/lookup-response.interface'; import type { OAuthResponse } from './responses/oauth-response.interface'; import type { PortfolioHoldingsResponse } from './responses/portfolio-holdings-response.interface'; import type { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface'; import type { PublicPortfolioResponse } from './responses/public-portfolio-response.interface'; +import type { QuotesResponse } from './responses/quotes-response.interface'; import type { ScraperConfiguration } from './scraper-configuration.interface'; import type { Statistics } from './statistics.interface'; -import type { Subscription } from './subscription.interface'; +import type { SubscriptionOffer } from './subscription-offer.interface'; import type { SymbolMetrics } from './symbol-metrics.interface'; import type { SystemMessage } from './system-message.interface'; import type { TabConfiguration } from './tab-configuration.interface'; @@ -71,17 +78,23 @@ export { BenchmarkProperty, BenchmarkResponse, Coupon, + DataProviderGhostfolioStatusResponse, DataProviderInfo, + DividendsResponse, EnhancedSymbolProfile, Export, Filter, FilterGroup, HistoricalDataItem, + HistoricalResponse, Holding, + HoldingWithParents, ImportResponse, InfoItem, InvestmentItem, LineChartItem, + LookupItem, + LookupResponse, OAuthResponse, PortfolioChart, PortfolioDetails, @@ -99,11 +112,12 @@ export { Position, Product, PublicPortfolioResponse, + QuotesResponse, ResponseError, ScraperConfiguration, Statistics, + SubscriptionOffer, SystemMessage, - Subscription, SymbolMetrics, TabConfiguration, ToggleOption, diff --git a/libs/common/src/lib/interfaces/info-item.interface.ts b/libs/common/src/lib/interfaces/info-item.interface.ts index 1b392633..bd3eb1f9 100644 --- a/libs/common/src/lib/interfaces/info-item.interface.ts +++ b/libs/common/src/lib/interfaces/info-item.interface.ts @@ -1,9 +1,9 @@ -import { SubscriptionOffer } from '@ghostfolio/common/types'; +import { SubscriptionOfferKey } from '@ghostfolio/common/types'; import { Platform, SymbolProfile } from '@prisma/client'; import { Statistics } from './statistics.interface'; -import { Subscription } from './subscription.interface'; +import { SubscriptionOffer } from './subscription-offer.interface'; export interface InfoItem { baseCurrency: string; @@ -18,5 +18,5 @@ export interface InfoItem { platforms: Platform[]; statistics: Statistics; stripePublicKey?: string; - subscriptions: { [offer in SubscriptionOffer]: Subscription }; + subscriptionOffers: { [offer in SubscriptionOfferKey]: SubscriptionOffer }; } diff --git a/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts b/libs/common/src/lib/interfaces/lookup-item.interface.ts similarity index 80% rename from apps/api/src/app/symbol/interfaces/lookup-item.interface.ts rename to libs/common/src/lib/interfaces/lookup-item.interface.ts index 89b47639..fa91ed69 100644 --- a/apps/api/src/app/symbol/interfaces/lookup-item.interface.ts +++ b/libs/common/src/lib/interfaces/lookup-item.interface.ts @@ -1,7 +1,7 @@ -import { DataProviderInfo } from '@ghostfolio/common/interfaces'; - import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; +import { DataProviderInfo } from './data-provider-info.interface'; + export interface LookupItem { assetClass: AssetClass; assetSubClass: AssetSubClass; diff --git a/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-status-response.interface.ts b/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-status-response.interface.ts new file mode 100644 index 00000000..9330adaa --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/data-provider-ghostfolio-status-response.interface.ts @@ -0,0 +1,7 @@ +import { UserWithSettings } from '@ghostfolio/common/types'; + +export interface DataProviderGhostfolioStatusResponse { + dailyRequests: number; + dailyRequestsMax: number; + subscription: UserWithSettings['subscription']; +} diff --git a/libs/common/src/lib/interfaces/responses/dividends-response.interface.ts b/libs/common/src/lib/interfaces/responses/dividends-response.interface.ts new file mode 100644 index 00000000..f7cacf89 --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/dividends-response.interface.ts @@ -0,0 +1,7 @@ +import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; + +export interface DividendsResponse { + dividends: { + [date: string]: IDataProviderHistoricalResponse; + }; +} diff --git a/libs/common/src/lib/interfaces/responses/historical-response.interface.ts b/libs/common/src/lib/interfaces/responses/historical-response.interface.ts new file mode 100644 index 00000000..12309a35 --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/historical-response.interface.ts @@ -0,0 +1,7 @@ +import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; + +export interface HistoricalResponse { + historicalData: { + [date: string]: IDataProviderHistoricalResponse; + }; +} diff --git a/libs/common/src/lib/interfaces/responses/lookup-response.interface.ts b/libs/common/src/lib/interfaces/responses/lookup-response.interface.ts new file mode 100644 index 00000000..579be9d0 --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/lookup-response.interface.ts @@ -0,0 +1,5 @@ +import { LookupItem } from '../lookup-item.interface'; + +export interface LookupResponse { + items: LookupItem[]; +} diff --git a/libs/common/src/lib/interfaces/responses/quotes-response.interface.ts b/libs/common/src/lib/interfaces/responses/quotes-response.interface.ts new file mode 100644 index 00000000..79c9d302 --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/quotes-response.interface.ts @@ -0,0 +1,5 @@ +import { IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; + +export interface QuotesResponse { + quotes: { [symbol: string]: IDataProviderResponse }; +} diff --git a/libs/common/src/lib/interfaces/subscription-offer.interface.ts b/libs/common/src/lib/interfaces/subscription-offer.interface.ts new file mode 100644 index 00000000..8db91da6 --- /dev/null +++ b/libs/common/src/lib/interfaces/subscription-offer.interface.ts @@ -0,0 +1,9 @@ +import { StringValue } from 'ms'; + +export interface SubscriptionOffer { + coupon?: number; + couponId?: string; + durationExtension?: StringValue; + price: number; + priceId: string; +} diff --git a/libs/common/src/lib/interfaces/subscription.interface.ts b/libs/common/src/lib/interfaces/subscription.interface.ts deleted file mode 100644 index 29f5d3ab..00000000 --- a/libs/common/src/lib/interfaces/subscription.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Subscription { - coupon?: number; - couponId?: string; - price: number; - priceId: string; -} diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts index e9e90e71..d72be7c7 100644 --- a/libs/common/src/lib/interfaces/user-settings.interface.ts +++ b/libs/common/src/lib/interfaces/user-settings.interface.ts @@ -14,6 +14,8 @@ export interface UserSettings { dateRange?: DateRange; emergencyFund?: number; 'filters.accounts'?: string[]; + 'filters.dataSource'?: string; + 'filters.symbol'?: string; 'filters.tags'?: string[]; holdingsViewMode?: HoldingsViewMode; isExperimentalFeatures?: boolean; diff --git a/libs/common/src/lib/interfaces/user.interface.ts b/libs/common/src/lib/interfaces/user.interface.ts index 27cd1a61..647822d3 100644 --- a/libs/common/src/lib/interfaces/user.interface.ts +++ b/libs/common/src/lib/interfaces/user.interface.ts @@ -1,4 +1,4 @@ -import { SubscriptionOffer } from '@ghostfolio/common/types'; +import { SubscriptionOfferKey } from '@ghostfolio/common/types'; import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type'; import { Account, Tag } from '@prisma/client'; @@ -20,7 +20,7 @@ export interface User { systemMessage?: SystemMessage; subscription: { expiresAt?: Date; - offer: SubscriptionOffer; + offer: SubscriptionOfferKey; type: SubscriptionType; }; tags: (Tag & { isUsed: boolean })[]; diff --git a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts index f38a8e6a..579d589b 100644 --- a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts +++ b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts @@ -1,10 +1,10 @@ export interface XRayRulesSettings { AccountClusterRiskCurrentInvestment?: RuleSettings; AccountClusterRiskSingleAccount?: RuleSettings; - AllocationClusterRiskDevelopedMarkets?: RuleSettings; - AllocationClusterRiskEmergingMarkets?: RuleSettings; CurrencyClusterRiskBaseCurrencyCurrentInvestment?: RuleSettings; CurrencyClusterRiskCurrentInvestment?: RuleSettings; + EconomicMarketClusterRiskDevelopedMarkets?: RuleSettings; + EconomicMarketClusterRiskEmergingMarkets?: RuleSettings; EmergencyFundSetup?: RuleSettings; FeeRatioInitialInvestment?: RuleSettings; } diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index ab443ea5..1a81938b 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -22,6 +22,7 @@ export const permissions = { deletePlatform: 'deletePlatform', deleteTag: 'deleteTag', deleteUser: 'deleteUser', + enableDataProviderGhostfolio: 'enableDataProviderGhostfolio', enableFearAndGreedIndex: 'enableFearAndGreedIndex', enableImport: 'enableImport', enableBlog: 'enableBlog', diff --git a/libs/common/src/lib/types/index.ts b/libs/common/src/lib/types/index.ts index a66755ab..9e8178d3 100644 --- a/libs/common/src/lib/types/index.ts +++ b/libs/common/src/lib/types/index.ts @@ -15,7 +15,7 @@ import type { MarketState } from './market-state.type'; import type { Market } from './market.type'; import type { OrderWithAccount } from './order-with-account.type'; import type { RequestWithUser } from './request-with-user.type'; -import type { SubscriptionOffer } from './subscription-offer.type'; +import type { SubscriptionOfferKey } from './subscription-offer-key.type'; import type { UserWithSettings } from './user-with-settings.type'; import type { ViewMode } from './view-mode.type'; @@ -37,7 +37,7 @@ export type { MarketState, OrderWithAccount, RequestWithUser, - SubscriptionOffer, + SubscriptionOfferKey, UserWithSettings, ViewMode }; diff --git a/libs/common/src/lib/types/subscription-offer.type.ts b/libs/common/src/lib/types/subscription-offer-key.type.ts similarity index 71% rename from libs/common/src/lib/types/subscription-offer.type.ts rename to libs/common/src/lib/types/subscription-offer-key.type.ts index 98977da4..f6d898a0 100644 --- a/libs/common/src/lib/types/subscription-offer.type.ts +++ b/libs/common/src/lib/types/subscription-offer-key.type.ts @@ -1,4 +1,4 @@ -export type SubscriptionOffer = +export type SubscriptionOfferKey = | 'default' | 'renewal' | 'renewal-early-bird-2023' diff --git a/libs/common/src/lib/types/user-with-settings.type.ts b/libs/common/src/lib/types/user-with-settings.type.ts index 59e9f142..5f983517 100644 --- a/libs/common/src/lib/types/user-with-settings.type.ts +++ b/libs/common/src/lib/types/user-with-settings.type.ts @@ -1,5 +1,5 @@ import { UserSettings } from '@ghostfolio/common/interfaces'; -import { SubscriptionOffer } from '@ghostfolio/common/types'; +import { SubscriptionOfferKey } from '@ghostfolio/common/types'; import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type'; import { Access, Account, Settings, User } from '@prisma/client'; @@ -9,11 +9,12 @@ export type UserWithSettings = User & { Access: Access[]; Account: Account[]; activityCount: number; + dataProviderGhostfolioDailyRequests: number; permissions?: string[]; Settings: Settings & { settings: UserSettings }; subscription?: { expiresAt?: Date; - offer: SubscriptionOffer; + offer: SubscriptionOfferKey; type: SubscriptionType; }; }; diff --git a/libs/ui/src/lib/assistant/assistant.component.ts b/libs/ui/src/lib/assistant/assistant.component.ts index d73cdb41..3a5e6a2f 100644 --- a/libs/ui/src/lib/assistant/assistant.component.ts +++ b/libs/ui/src/lib/assistant/assistant.component.ts @@ -1,7 +1,9 @@ import { GfAssetProfileIconComponent } from '@ghostfolio/client/components/asset-profile-icon/asset-profile-icon.component'; +import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { Filter, User } from '@ghostfolio/common/interfaces'; +import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; +import { Filter, PortfolioPosition, User } from '@ghostfolio/common/interfaces'; import { DateRange } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; @@ -35,7 +37,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatMenuTrigger } from '@angular/material/menu'; import { MatSelectModule } from '@angular/material/select'; import { RouterModule } from '@angular/router'; -import { Account, AssetClass } from '@prisma/client'; +import { Account, AssetClass, DataSource } from '@prisma/client'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs'; import { @@ -61,6 +63,7 @@ import { FormsModule, GfAssetProfileIconComponent, GfAssistantListItemComponent, + GfSymbolModule, MatButtonModule, MatFormFieldModule, MatSelectModule, @@ -132,8 +135,10 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { public filterForm = this.formBuilder.group({ account: new FormControl(undefined), assetClass: new FormControl(undefined), + holding: new FormControl(undefined), tag: new FormControl(undefined) }); + public holdings: PortfolioPosition[] = []; public isLoading = false; public isOpen = false; public placeholder = $localize`Find holding...`; @@ -144,7 +149,13 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { }; public tags: Filter[] = []; - private filterTypes: Filter['type'][] = ['ACCOUNT', 'ASSET_CLASS', 'TAG']; + private filterTypes: Filter['type'][] = [ + 'ACCOUNT', + 'ASSET_CLASS', + 'DATA_SOURCE', + 'SYMBOL', + 'TAG' + ]; private keyManager: FocusKeyManager; private unsubscribeSubject = new Subject(); @@ -156,6 +167,8 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { ) {} public ngOnInit() { + this.initializeFilterForm(); + this.assetClasses = Object.keys(AssetClass).map((assetClass) => { return { id: assetClass, @@ -263,16 +276,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { this.filterForm.enable({ emitEvent: false }); } - this.filterForm.setValue( - { - account: this.user?.settings?.['filters.accounts']?.[0] ?? null, - assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null, - tag: this.user?.settings?.['filters.tags']?.[0] ?? null - }, - { - emitEvent: false - } - ); + this.initializeFilterForm(); this.tags = this.user?.tags @@ -298,6 +302,19 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { }); } + public holdingComparisonFunction( + option: PortfolioPosition, + value: PortfolioPosition + ): boolean { + if (value === null) { + return false; + } + + return ( + getAssetProfileIdentifier(option) === getAssetProfileIdentifier(value) + ); + } + public async initialize() { this.isLoading = true; this.keyManager = new FocusKeyManager(this.assistantListItems).withWrap(); @@ -331,6 +348,14 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { id: this.filterForm.get('assetClass').value, type: 'ASSET_CLASS' }, + { + id: this.filterForm.get('holding').value?.dataSource, + type: 'DATA_SOURCE' + }, + { + id: this.filterForm.get('holding').value?.symbol, + type: 'SYMBOL' + }, { id: this.filterForm.get('tag').value, type: 'TAG' @@ -473,4 +498,47 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { takeUntil(this.unsubscribeSubject) ); } + + private initializeFilterForm() { + this.dataService + .fetchPortfolioHoldings() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ holdings }) => { + this.holdings = holdings + .filter(({ assetSubClass }) => { + return !['CASH'].includes(assetSubClass); + }) + .sort((a, b) => { + return a.name?.localeCompare(b.name); + }); + this.setFilterFormValues(); + }); + } + + private setFilterFormValues() { + const dataSource = this.user?.settings?.[ + 'filters.dataSource' + ] as DataSource; + const symbol = this.user?.settings?.['filters.symbol']; + const selectedHolding = this.holdings.find((holding) => { + return ( + getAssetProfileIdentifier({ + dataSource: holding.dataSource, + symbol: holding.symbol + }) === getAssetProfileIdentifier({ dataSource, symbol }) + ); + }); + + this.filterForm.setValue( + { + account: this.user?.settings?.['filters.accounts']?.[0] ?? null, + assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null, + holding: selectedHolding ?? null, + tag: this.user?.settings?.['filters.tags']?.[0] ?? null + }, + { + emitEvent: false + } + ); + } } diff --git a/libs/ui/src/lib/assistant/assistant.html b/libs/ui/src/lib/assistant/assistant.html index 648c791a..18c2145a 100644 --- a/libs/ui/src/lib/assistant/assistant.html +++ b/libs/ui/src/lib/assistant/assistant.html @@ -122,6 +122,34 @@ +
    + + Holding + + {{ + filterForm.get('holding')?.value?.name + }} + + @for (holding of holdings; track holding.name) { + +
    + {{ holding.name }} +
    + {{ holding.symbol | gfSymbol }} · + {{ holding.currency }} +
    +
    + } +
    +
    +
    Tags diff --git a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.component.ts b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts similarity index 60% rename from apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.component.ts rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts index 6a44d0df..434266e1 100644 --- a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.component.ts +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.component.ts @@ -1,34 +1,58 @@ import { AdminService } from '@ghostfolio/client/services/admin.service'; +import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + CUSTOM_ELEMENTS_SCHEMA, Inject, OnDestroy } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef +} from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; import { Subject, takeUntil } from 'rxjs'; -import { MarketDataDetailDialogParams } from './interfaces/interfaces'; +import { HistoricalMarketDataEditorDialogParams } from './interfaces/interfaces'; @Component({ - host: { class: 'h-100' }, - selector: 'gf-market-data-detail-dialog', changeDetection: ChangeDetectionStrategy.OnPush, - styleUrls: ['./market-data-detail-dialog.scss'], - templateUrl: 'market-data-detail-dialog.html' + host: { class: 'h-100' }, + imports: [ + CommonModule, + FormsModule, + MatButtonModule, + MatDatepickerModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule + ], + selector: 'gf-historical-market-data-editor-dialog', + schemas: [CUSTOM_ELEMENTS_SCHEMA], + standalone: true, + styleUrls: ['./historical-market-data-editor-dialog.scss'], + templateUrl: 'historical-market-data-editor-dialog.html' }) -export class MarketDataDetailDialog implements OnDestroy { +export class GfHistoricalMarketDataEditorDialogComponent implements OnDestroy { private unsubscribeSubject = new Subject(); public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, - @Inject(MAT_DIALOG_DATA) public data: MarketDataDetailDialogParams, + @Inject(MAT_DIALOG_DATA) + public data: HistoricalMarketDataEditorDialogParams, private dateAdapter: DateAdapter, - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DATE_LOCALE) private locale: string ) {} diff --git a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html similarity index 100% rename from apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html diff --git a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.scss b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.scss similarity index 100% rename from apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.scss rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.scss diff --git a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/interfaces/interfaces.ts b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/interfaces/interfaces.ts similarity index 79% rename from apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/interfaces/interfaces.ts rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/interfaces/interfaces.ts index 81188cd1..4248b3fd 100644 --- a/apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/interfaces/interfaces.ts +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/interfaces/interfaces.ts @@ -2,7 +2,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { DataSource } from '@prisma/client'; -export interface MarketDataDetailDialogParams { +export interface HistoricalMarketDataEditorDialogParams { currency: string; dataSource: DataSource; dateString: string; diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html similarity index 51% rename from apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html index 617dd696..b35e1d81 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html @@ -1,14 +1,4 @@
    - @for (itemByMonth of marketDataByMonth | keyvalue; track itemByMonth) {
    {{ itemByMonth.key }}
    @@ -43,4 +33,42 @@
    } +
    +
    + + + Historical Data (CSV) + + + +
    + +
    + +
    +
    diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.scss b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.scss similarity index 90% rename from apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.scss rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.scss index a0353358..cc835a90 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.scss +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.scss @@ -2,10 +2,6 @@ display: block; font-size: 0.9rem; - gf-line-chart { - aspect-ratio: 16/9; - } - .date { font-feature-settings: 'tnum'; font-variant-numeric: tabular-nums; diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts similarity index 55% rename from apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts rename to libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts index 1742d830..0fce7862 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts +++ b/libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts @@ -1,4 +1,5 @@ -import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { UpdateMarketDataDto } from '@ghostfolio/api/app/admin/update-market-data.dto'; +import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DATE_FORMAT, getDateFormatString, @@ -6,15 +7,22 @@ import { } from '@ghostfolio/common/helper'; import { LineChartItem, User } from '@ghostfolio/common/interfaces'; +import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, + OnDestroy, + OnInit, Output } from '@angular/core'; +import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; +import { MatInputModule } from '@angular/material/input'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { DataSource, MarketData } from '@prisma/client'; import { addDays, @@ -29,55 +37,70 @@ import { parseISO } from 'date-fns'; import { first, last } from 'lodash'; +import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; +import { parse as csvToJson } from 'papaparse'; +import { EMPTY, Subject, takeUntil } from 'rxjs'; +import { catchError } from 'rxjs/operators'; -import { MarketDataDetailDialogParams } from './market-data-detail-dialog/interfaces/interfaces'; -import { MarketDataDetailDialog } from './market-data-detail-dialog/market-data-detail-dialog.component'; +import { GfHistoricalMarketDataEditorDialogComponent } from './historical-market-data-editor-dialog/historical-market-data-editor-dialog.component'; +import { HistoricalMarketDataEditorDialogParams } from './historical-market-data-editor-dialog/interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - selector: 'gf-admin-market-data-detail', - styleUrls: ['./admin-market-data-detail.component.scss'], - templateUrl: './admin-market-data-detail.component.html' + imports: [CommonModule, MatButtonModule, MatInputModule, ReactiveFormsModule], + selector: 'gf-historical-market-data-editor', + standalone: true, + styleUrls: ['./historical-market-data-editor.component.scss'], + templateUrl: './historical-market-data-editor.component.html' }) -export class AdminMarketDataDetailComponent implements OnChanges { +export class GfHistoricalMarketDataEditorComponent + implements OnChanges, OnDestroy, OnInit +{ @Input() currency: string; @Input() dataSource: DataSource; @Input() dateOfFirstActivity: string; @Input() locale = getLocale(); @Input() marketData: MarketData[]; @Input() symbol: string; + @Input() user: User; @Output() marketDataChanged = new EventEmitter(); public days = Array(31); public defaultDateFormat: string; public deviceType: string; + public historicalDataForm = this.formBuilder.group({ + historicalData: this.formBuilder.group({ + csvString: '' + }) + }); public historicalDataItems: LineChartItem[]; public marketDataByMonth: { [yearMonth: string]: { [day: string]: Pick & { day: number }; }; } = {}; - public user: User; + + private static readonly HISTORICAL_DATA_TEMPLATE = `date;marketPrice\n${format( + new Date(), + DATE_FORMAT + )};123.45`; private unsubscribeSubject = new Subject(); public constructor( + private adminService: AdminService, private deviceService: DeviceDetectorService, private dialog: MatDialog, - private userService: UserService + private formBuilder: FormBuilder, + private snackBar: MatSnackBar ) { this.deviceType = this.deviceService.getDeviceInfo().deviceType; + } - this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((state) => { - if (state?.user) { - this.user = state.user; - } - }); + public ngOnInit() { + this.initializeHistoricalDataForm(); } public ngOnChanges() { @@ -177,29 +200,84 @@ export class AdminMarketDataDetailComponent implements OnChanges { }) { const marketPrice = this.marketDataByMonth[yearMonth]?.[day]?.marketPrice; - const dialogRef = this.dialog.open(MarketDataDetailDialog, { - data: { - marketPrice, - currency: this.currency, - dataSource: this.dataSource, - dateString: `${yearMonth}-${day}`, - symbol: this.symbol, - user: this.user - } as MarketDataDetailDialogParams, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - }); + const dialogRef = this.dialog.open( + GfHistoricalMarketDataEditorDialogComponent, + { + data: { + marketPrice, + currency: this.currency, + dataSource: this.dataSource, + dateString: `${yearMonth}-${day}`, + symbol: this.symbol, + user: this.user + } as HistoricalMarketDataEditorDialogParams, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + } + ); dialogRef .afterClosed() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ withRefresh } = { withRefresh: false }) => { - this.marketDataChanged.next(withRefresh); + this.marketDataChanged.emit(withRefresh); }); } + public onImportHistoricalData() { + try { + const marketData = csvToJson( + this.historicalDataForm.controls['historicalData'].controls['csvString'] + .value, + { + dynamicTyping: true, + header: true, + skipEmptyLines: true + } + ).data as UpdateMarketDataDto[]; + + this.adminService + .postMarketData({ + dataSource: this.dataSource, + marketData: { + marketData + }, + symbol: this.symbol + }) + .pipe( + catchError(({ error, message }) => { + this.snackBar.open(`${error}: ${message[0]}`, undefined, { + duration: ms('3 seconds') + }); + return EMPTY; + }), + takeUntil(this.unsubscribeSubject) + ) + .subscribe(() => { + this.initializeHistoricalDataForm(); + + this.marketDataChanged.emit(true); + }); + } catch { + this.snackBar.open( + $localize`Oops! Could not parse historical data.`, + undefined, + { duration: ms('3 seconds') } + ); + } + } + public ngOnDestroy() { this.unsubscribeSubject.next(); this.unsubscribeSubject.complete(); } + + private initializeHistoricalDataForm() { + this.historicalDataForm.setValue({ + historicalData: { + csvString: + GfHistoricalMarketDataEditorComponent.HISTORICAL_DATA_TEMPLATE + } + }); + } } diff --git a/libs/ui/src/lib/historical-market-data-editor/index.ts b/libs/ui/src/lib/historical-market-data-editor/index.ts new file mode 100644 index 00000000..6c7004ce --- /dev/null +++ b/libs/ui/src/lib/historical-market-data-editor/index.ts @@ -0,0 +1 @@ +export * from './historical-market-data-editor.component'; diff --git a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html index d055a618..c6327c31 100644 --- a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html +++ b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html @@ -19,7 +19,7 @@ [value]="lookupItem" > {{ lookupItem.name }} + >{{ lookupItem.name }} @if (lookupItem.dataProviderInfo.isPremium) { } @@ -29,6 +29,9 @@ @if (lookupItem.assetSubClass) { · {{ lookupItem.assetSubClassString }} } + @if (lookupItem.dataProviderInfo.name) { + · {{ lookupItem.dataProviderInfo.name }} + } } @empty { diff --git a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts index da97aac0..a537c50a 100644 --- a/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts +++ b/libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts @@ -1,6 +1,6 @@ -import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { DataService } from '@ghostfolio/client/services/data.service'; +import { LookupItem } from '@ghostfolio/common/interfaces'; import { translate } from '@ghostfolio/ui/i18n'; import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field'; diff --git a/libs/ui/src/lib/top-holdings/top-holdings.component.html b/libs/ui/src/lib/top-holdings/top-holdings.component.html index 72463da4..d42d742b 100644 --- a/libs/ui/src/lib/top-holdings/top-holdings.component.html +++ b/libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1,14 +1,18 @@
    + + + + + + - @@ -57,8 +51,107 @@ + + + + - + +
    + Name @@ -17,12 +21,7 @@ - + Value @@ -37,12 +36,7 @@ - + Allocation % +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    {{ parentHolding?.name }}
    +
    +
    + {{ + parentHolding?.symbol | gfSymbol + }} +
    +
    + Name + +
    + +
    +
    + Value + +
    + +
    +
    + Allocation + % +
    +
    +
    +
    diff --git a/libs/ui/src/lib/top-holdings/top-holdings.component.scss b/libs/ui/src/lib/top-holdings/top-holdings.component.scss index 990b8b29..b3e811a2 100644 --- a/libs/ui/src/lib/top-holdings/top-holdings.component.scss +++ b/libs/ui/src/lib/top-holdings/top-holdings.component.scss @@ -1,11 +1,33 @@ :host { display: block; - .gf-table { - th { - ::ng-deep { - .mat-sort-header-container { - justify-content: inherit; + .holdings-table { + table-layout: auto; + + tr { + &:not(.expanded) + tr.holding-detail td { + border-bottom: 0; + } + + &.expanded { + > td { + font-weight: bold; + } + } + + &.holding-detail { + height: 0; + } + + .holding-parents-table { + --table-padding: 0.5em; + + tr { + height: auto; + + td { + padding: var(--table-padding); + } } } } diff --git a/libs/ui/src/lib/top-holdings/top-holdings.component.ts b/libs/ui/src/lib/top-holdings/top-holdings.component.ts index 0a3f0e97..3d3712bc 100644 --- a/libs/ui/src/lib/top-holdings/top-holdings.component.ts +++ b/libs/ui/src/lib/top-holdings/top-holdings.component.ts @@ -1,33 +1,56 @@ +import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { getLocale } from '@ghostfolio/common/helper'; -import { Holding } from '@ghostfolio/common/interfaces'; +import { + AssetProfileIdentifier, + HoldingWithParents, + PortfolioPosition +} from '@ghostfolio/common/interfaces'; import { GfValueComponent } from '@ghostfolio/ui/value'; +import { + animate, + state, + style, + transition, + trigger +} from '@angular/animations'; import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, + EventEmitter, Input, OnChanges, OnDestroy, + Output, ViewChild } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; -import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; -import { get } from 'lodash'; +import { DataSource } from '@prisma/client'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; @Component({ + animations: [ + trigger('detailExpand', [ + state('collapsed,void', style({ height: '0px', minHeight: '0' })), + state('expanded', style({ height: '*' })), + transition( + 'expanded <=> collapsed', + animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)') + ) + ]) + ], changeDetection: ChangeDetectionStrategy.OnPush, imports: [ CommonModule, + GfSymbolModule, GfValueComponent, MatButtonModule, MatPaginatorModule, - MatSortModule, MatTableModule, NgxSkeletonLoaderModule ], @@ -41,12 +64,20 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy { @Input() baseCurrency: string; @Input() locale = getLocale(); @Input() pageSize = Number.MAX_SAFE_INTEGER; - @Input() topHoldings: Holding[]; + @Input() topHoldings: HoldingWithParents[]; + @Input() positions: { + [symbol: string]: Pick & { + dataSource?: DataSource; + name: string; + value: number; + }; + } = {}; + + @Output() holdingClicked = new EventEmitter(); @ViewChild(MatPaginator) paginator: MatPaginator; - @ViewChild(MatSort) sort: MatSort; - public dataSource = new MatTableDataSource(); + public dataSource = new MatTableDataSource(); public displayedColumns: string[] = [ 'name', 'valueInBaseCurrency', @@ -61,14 +92,16 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy { this.dataSource = new MatTableDataSource(this.topHoldings); this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = get; if (this.topHoldings) { this.isLoading = false; } } + public onClickHolding(assetProfileIdentifier: AssetProfileIdentifier) { + this.holdingClicked.emit(assetProfileIdentifier); + } + public onShowAllHoldings() { this.pageSize = Number.MAX_SAFE_INTEGER; diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts index 1acc2c92..9a8594ad 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -261,12 +261,21 @@ export class GfTreemapChartComponent display: true, font: [{ size: 16 }, { lineHeight: 1.5, size: 14 }], formatter: (ctx) => { - const netPerformancePercentWithCurrencyEffect = - ctx.raw._data.netPerformancePercentWithCurrencyEffect; + // Round to 4 decimal places + let netPerformancePercentWithCurrencyEffect = + Math.round( + ctx.raw._data.netPerformancePercentWithCurrencyEffect * 10000 + ) / 10000; + + if (Math.abs(netPerformancePercentWithCurrencyEffect) === 0) { + netPerformancePercentWithCurrencyEffect = Math.abs( + netPerformancePercentWithCurrencyEffect + ); + } return [ ctx.raw._data.symbol, - `${netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''}${(ctx.raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%` + `${netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''}${(netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%` ]; }, hoverColor: undefined, diff --git a/package-lock.json b/package-lock.json index 49260020..ae7b60a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.118.0", + "version": "2.125.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.118.0", + "version": "2.125.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -40,10 +40,10 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.21.1", + "@prisma/client": "6.0.0", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", - "@stripe/stripe-js": "3.5.0", + "@stripe/stripe-js": "4.9.0", "alphavantage": "2.2.0", "big.js": "6.2.1", "body-parser": "1.20.2", @@ -56,12 +56,12 @@ "chartjs-chart-treemap": "2.3.1", "chartjs-plugin-annotation": "2.1.2", "chartjs-plugin-datalabels": "2.2.0", - "cheerio": "1.0.0-rc.12", + "cheerio": "1.0.0", "class-transformer": "0.5.1", "class-validator": "0.14.1", "color": "4.2.3", - "countries-and-timezones": "3.4.1", - "countries-list": "3.1.0", + "countries-and-timezones": "3.7.2", + "countries-list": "3.1.1", "countup.js": "2.8.0", "date-fns": "3.6.0", "envalid": "7.3.1", @@ -77,8 +77,8 @@ "ng-extract-i18n-merge": "2.12.0", "ngx-device-detector": "8.0.0", "ngx-markdown": "18.0.0", - "ngx-skeleton-loader": "7.0.0", - "ngx-stripe": "18.0.0", + "ngx-skeleton-loader": "9.0.0", + "ngx-stripe": "18.1.0", "open-color": "1.9.1", "papaparse": "5.3.1", "passport": "0.7.0", @@ -86,10 +86,10 @@ "passport-jwt": "4.0.1", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", - "stripe": "15.11.0", + "stripe": "17.3.0", "svgmap": "2.6.0", "twitter-api-v2": "1.14.2", - "uuid": "9.0.1", + "uuid": "11.0.2", "yahoo-finance2": "2.11.3", "zone.js": "0.14.10" }, @@ -107,16 +107,16 @@ "@angular/pwa": "18.2.9", "@nestjs/schematics": "10.0.1", "@nestjs/testing": "10.1.3", - "@nx/angular": "20.0.3", - "@nx/cypress": "20.0.3", - "@nx/eslint-plugin": "20.0.3", - "@nx/jest": "20.0.3", - "@nx/js": "20.0.3", - "@nx/nest": "20.0.3", - "@nx/node": "20.0.3", - "@nx/storybook": "20.0.3", - "@nx/web": "20.0.3", - "@nx/workspace": "20.0.3", + "@nx/angular": "20.1.2", + "@nx/cypress": "20.1.2", + "@nx/eslint-plugin": "20.1.2", + "@nx/jest": "20.1.2", + "@nx/js": "20.1.2", + "@nx/nest": "20.1.2", + "@nx/node": "20.1.2", + "@nx/storybook": "20.1.2", + "@nx/web": "20.1.2", + "@nx/workspace": "20.1.2", "@schematics/angular": "18.2.9", "@simplewebauthn/types": "9.0.1", "@storybook/addon-essentials": "8.3.6", @@ -147,10 +147,10 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-preset-angular": "14.1.0", - "nx": "20.0.3", + "nx": "20.1.2", "prettier": "3.3.3", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "5.21.1", + "prisma": "6.0.0", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "7.0.1", @@ -170,7 +170,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@ampproject/remapping": { @@ -3688,63 +3688,6 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@eslint/eslintrc": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", @@ -3869,67 +3812,12 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz", - "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/@hexagon/base64": { "version": "1.1.28", "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz", "integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==", "license": "MIT" }, - "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@humanfs/core": "^0.19.0", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3992,22 +3880,6 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@inquirer/checkbox": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", @@ -5327,25 +5199,25 @@ } }, "node_modules/@module-federation/bridge-react-webpack-plugin": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-0.6.6.tgz", - "integrity": "sha512-NANaSOKem+1t/Fbd1GjXnStJRe7O33ya+FR/yYkTUd1H5hmlzVDNo/lYxYuUl3O/gH9Lnlr2Gf9unyWoIW0wHw==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-0.6.9.tgz", + "integrity": "sha512-KXTPO0vkrtHEIcthU3TIQEkPxoytcmdyNXRwOojZEVQhqEefykAek48ndFiVTmyOu2LW2EuzP49Le8zY7nESWQ==", "dev": true, "dependencies": { - "@module-federation/sdk": "0.6.6", + "@module-federation/sdk": "0.6.9", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "node_modules/@module-federation/data-prefetch": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/data-prefetch/-/data-prefetch-0.6.6.tgz", - "integrity": "sha512-rakEHrg2pqbOqJ3uWT2p3kgTCOxBQdEIqmew3XBAXTZ0NblZtkXeMHupcW/W6+ccvbPdn/T/PSICx9HHSvfEVg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/data-prefetch/-/data-prefetch-0.6.9.tgz", + "integrity": "sha512-rpHxfHNkIiPA441GzXI6TMYjSrUjRWDwxJTvRQopX/P0jK5vKtNwT1UBTNF2DJkbtO1idljfhbrIufEg0OY72w==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.6.6", - "@module-federation/sdk": "0.6.6", + "@module-federation/runtime": "0.6.9", + "@module-federation/sdk": "0.6.9", "fs-extra": "9.1.0" }, "peerDependencies": { @@ -5354,15 +5226,15 @@ } }, "node_modules/@module-federation/dts-plugin": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-0.6.6.tgz", - "integrity": "sha512-sNCghGgrpCOOVk2xpzgAGAFeo2ONcv6eAnEfe7Q2gD7R6NrGgOrB5KVhN/uWIzFJG8tqNfSSjam+woTyrrayfg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-0.6.9.tgz", + "integrity": "sha512-uiMjjEFcMlOvRtNu8/tt7sJ5y7WTosTVym0V7lMQjgoeX0QesvZqRhgzw5gQcPcFvbk54RwTUI2rS8OEGScCFw==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/managers": "0.6.6", - "@module-federation/sdk": "0.6.6", - "@module-federation/third-party-dts-extractor": "0.6.6", + "@module-federation/managers": "0.6.9", + "@module-federation/sdk": "0.6.9", + "@module-federation/third-party-dts-extractor": "0.6.9", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.7.4", @@ -5440,20 +5312,20 @@ } }, "node_modules/@module-federation/enhanced": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-0.6.6.tgz", - "integrity": "sha512-gGU1tjaksk5Q5X2zpVb/OmlwvKwVVjTXreuFwkK0Z+9QKM9jbu0B/tPSh6sqibPFeu1yM2HOFlOHJhvFs1PmsA==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-0.6.9.tgz", + "integrity": "sha512-4bEGQSE6zJ2FMdBTOrRiVjNNzWhUqzWEJGWbsr0bpLNAl4BVx2ah5MyKTrSYqaW//BRA2qc8rmrIreaIawr3kQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "0.6.6", - "@module-federation/data-prefetch": "0.6.6", - "@module-federation/dts-plugin": "0.6.6", - "@module-federation/managers": "0.6.6", - "@module-federation/manifest": "0.6.6", - "@module-federation/rspack": "0.6.6", - "@module-federation/runtime-tools": "0.6.6", - "@module-federation/sdk": "0.6.6", + "@module-federation/bridge-react-webpack-plugin": "0.6.9", + "@module-federation/data-prefetch": "0.6.9", + "@module-federation/dts-plugin": "0.6.9", + "@module-federation/managers": "0.6.9", + "@module-federation/manifest": "0.6.9", + "@module-federation/rspack": "0.6.9", + "@module-federation/runtime-tools": "0.6.9", + "@module-federation/sdk": "0.6.9", "btoa": "^1.2.1", "upath": "2.0.1" }, @@ -5475,27 +5347,27 @@ } }, "node_modules/@module-federation/managers": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-0.6.6.tgz", - "integrity": "sha512-ryj2twbQmo2KhwKn1xYivpaW94l5wfplDU9FwVvW0wc8hC2lJnuGhoiZqXKL7lNaBrZXge3b43Zlgx5OnFfr6A==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-0.6.9.tgz", + "integrity": "sha512-q3AOQXcWWpdUZI1gDIi9j/UqcP+FJBYXj/e4pNp3QAteJwS/Ve9UP3y0hW27bIbAWZSSajWsYbf/+YLnktA/kQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/sdk": "0.6.6", + "@module-federation/sdk": "0.6.9", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "node_modules/@module-federation/manifest": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-0.6.6.tgz", - "integrity": "sha512-45ol0fC8RS2d+0iEt5zdp0vctE2CiOfA2kCmOFz79K33occi8sKmyevfSeZGckZy54NiMnLFteIYBsyIa+g7gg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-0.6.9.tgz", + "integrity": "sha512-JMSPDpHODXOmTyJes8GJ950mbN7tqjQzqgFVUubDOVFOmlC0/MYaRzRPmkApz6d8nUfMbLZYzxNSaBHx8GP0/Q==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/dts-plugin": "0.6.6", - "@module-federation/managers": "0.6.6", - "@module-federation/sdk": "0.6.6", + "@module-federation/dts-plugin": "0.6.9", + "@module-federation/managers": "0.6.9", + "@module-federation/sdk": "0.6.9", "chalk": "3.0.0", "find-pkg": "2.0.0" } @@ -5554,18 +5426,18 @@ } }, "node_modules/@module-federation/rspack": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-0.6.6.tgz", - "integrity": "sha512-30X6QPrJ/eCcmUL4GQ06Z9bQwURBnJI0607Fw2ufmAbhDA0PJFtg7NFFfXzsdChms1ACVbgvgfBH8SJg8j3wBg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-0.6.9.tgz", + "integrity": "sha512-N5yBqN8ijSRZKd0kbIvpZNil0y8rFa8cREKI1QsW1+EYUKwOUBFwF55tFdTmNCKmpZqSEBtcNjRGZXknsYPQxg==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "0.6.6", - "@module-federation/dts-plugin": "0.6.6", - "@module-federation/managers": "0.6.6", - "@module-federation/manifest": "0.6.6", - "@module-federation/runtime-tools": "0.6.6", - "@module-federation/sdk": "0.6.6" + "@module-federation/bridge-react-webpack-plugin": "0.6.9", + "@module-federation/dts-plugin": "0.6.9", + "@module-federation/managers": "0.6.9", + "@module-federation/manifest": "0.6.9", + "@module-federation/runtime-tools": "0.6.9", + "@module-federation/sdk": "0.6.9" }, "peerDependencies": { "typescript": "^4.9.0 || ^5.0.0", @@ -5581,37 +5453,37 @@ } }, "node_modules/@module-federation/runtime": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.6.6.tgz", - "integrity": "sha512-QsKHUV2HALRzL6mPCdJEZTDuPReKC8MMXf+/VMCtQPp6JhLEjZIO06bfEZqXMbTbTYlMzntIwu1tGCbtJRZDOQ==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.6.9.tgz", + "integrity": "sha512-G1x+6jyW5sW1X+TtWaKigGhwqiHE8MESvi3ntE9ICxwELAGBonmsqDqnLSrdEy6poBKslvPANPJr0Nn9pvW9lg==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/sdk": "0.6.6" + "@module-federation/sdk": "0.6.9" } }, "node_modules/@module-federation/runtime-tools": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.6.6.tgz", - "integrity": "sha512-w2qHa41p6rADWMS1yBjpqNhaLZ4R5oRy9OYGPe6ywjh+8oqbiBl1CfQglcgEBIpHktEjV/upsgsnjHSdJBdeZw==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.6.9.tgz", + "integrity": "sha512-AhsEBXo8IW1ATMKS1xfJaxBiHu9n5z6WUOAIWdPpWXXBJhTFgOs0K1xAod0xLJY4YH/B5cwEcHRPN3FEs2/0Ww==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.6.6", - "@module-federation/webpack-bundler-runtime": "0.6.6" + "@module-federation/runtime": "0.6.9", + "@module-federation/webpack-bundler-runtime": "0.6.9" } }, "node_modules/@module-federation/sdk": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.6.6.tgz", - "integrity": "sha512-tUv2kPi0FvplcpGi/g4nITAYVAR1RUZ6QvP71T8inmRZSrfcvk1QpGJiL36IjuS67SM3VAoXS0iJ2WX1Rgjvhg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.6.9.tgz", + "integrity": "sha512-xmTxb9LgncxPGsBrN6AT/+aHnFGv8swbeNl0PcSeVbXTGLu3Gp7j+5J+AhJoWNB++SLguRwBd8LjB1d8mNKLDg==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/third-party-dts-extractor": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-0.6.6.tgz", - "integrity": "sha512-xX9p17PpElzATNEulwlJJT731xST7T7OUIDSkkIghp/ICDmZd6WhYJvNBto7xbpaj5SIB7Ocdj4chNGv0xdYPw==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-0.6.9.tgz", + "integrity": "sha512-im00IQyX/siJz+SaAmJo6vGmMBig7UYzcrPD1N5NeiZonxdT1RZk9iXUP419UESgovYy4hM6w4qdCq6PMMl2bw==", "dev": true, "license": "MIT", "dependencies": { @@ -5621,14 +5493,14 @@ } }, "node_modules/@module-federation/webpack-bundler-runtime": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.6.6.tgz", - "integrity": "sha512-0UnY9m1fBgHwTpacYWbht1jB5X4Iqspiu1q8kfjUrv6y+R224//ydUFYYO8xfWx4V9SGQFKlU8XFH0FP/r0Hng==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.6.9.tgz", + "integrity": "sha512-ME1MjNT/a4MFI3HaJDM06olJ+/+H8lk4oDOdwwEZI2JSH3UoqCDrMcjSKCjBNMGzza57AowGobo1LHQeY8yZ8Q==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "0.6.6", - "@module-federation/sdk": "0.6.6" + "@module-federation/runtime": "0.6.9", + "@module-federation/sdk": "0.6.9" } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { @@ -6557,19 +6429,19 @@ } }, "node_modules/@nx/angular": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/angular/-/angular-20.0.3.tgz", - "integrity": "sha512-d9xekjP9onlRzW0Vz1My4USkiOuihZU3nM/SgGj7i2ZL7W/Fu81H7CAxlmsH93/XPresHaAnZSCSx0ofq5YyCA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/angular/-/angular-20.1.2.tgz", + "integrity": "sha512-brGmrT6DDPCV7liN69N5T0rHqkn2FO7zceAum++h/s65++g4CscZTIS0CyKr8ZBRG9wvDBuOWkKbnwtV9297HA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/enhanced": "0.6.6", - "@nx/devkit": "20.0.3", - "@nx/eslint": "20.0.3", - "@nx/js": "20.0.3", - "@nx/web": "20.0.3", - "@nx/webpack": "20.0.3", - "@nx/workspace": "20.0.3", + "@module-federation/enhanced": "0.6.9", + "@nx/devkit": "20.1.2", + "@nx/eslint": "20.1.2", + "@nx/js": "20.1.2", + "@nx/web": "20.1.2", + "@nx/webpack": "20.1.2", + "@nx/workspace": "20.1.2", "@phenomnomnominal/tsquery": "~5.0.1", "@typescript-eslint/type-utils": "^8.0.0", "chalk": "^4.1.0", @@ -6662,15 +6534,15 @@ } }, "node_modules/@nx/cypress": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-20.0.3.tgz", - "integrity": "sha512-Bnm3Soa3aEIzmbJMtjmgGko5FVvBWh2I0stV+eMmLC8y9mCOQ3W4i+pXjpD6zVLAfZBF80W9e1ON7kdlfpM2Rw==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-20.1.2.tgz", + "integrity": "sha512-kT/vXWqD4DxYawtVBA3E1EYlFi6ba6XvEnh+Ac5A1EX0PmVqBxhtBxpDlLjJxDOEgpIWbZDFdkJ41twYQgYDGA==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "20.0.3", - "@nx/eslint": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/eslint": "20.1.2", + "@nx/js": "20.1.2", "@phenomnomnominal/tsquery": "~5.0.1", "detect-port": "^1.5.1", "tslib": "^2.3.0" @@ -6685,9 +6557,9 @@ } }, "node_modules/@nx/devkit": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-20.0.3.tgz", - "integrity": "sha512-tB6iQ2opvipyy+4J0eImW/Nl8SoILPpDodwnThDJ2U2mflHG6/+3Wl6Q1hXieOnjT+ZE++ve91aYDEAi9OMwvA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-20.1.2.tgz", + "integrity": "sha512-MTEWiEST7DhzZ2QmrixLnHfYVDZk7QN9omLL8m+5Etcn/3ZKa1aAo9Amd2MkUM+0MPoTKnxoGdw0fQUpAy21Mg==", "dev": true, "license": "MIT", "dependencies": { @@ -6705,14 +6577,14 @@ } }, "node_modules/@nx/eslint": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-20.0.3.tgz", - "integrity": "sha512-uWS1jvGj5T2GOMRit8HqC0LOo1BxEzQejxEioIfLVaoO8bd67FdZQh2Tz3Qon9V05VXm8pEHQv/1NVNqanzgBQ==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-20.1.2.tgz", + "integrity": "sha512-VMJ65E0jUEjup8hxz6LtqYbYnk2TUoLCM7ZV4rZdPqm0rLvlHDmb7BfdY2u2sZa3dwRDtupeDMlbyPX/Eb8Rcw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/js": "20.1.2", "semver": "^7.5.3", "tslib": "^2.3.0", "typescript": "~5.4.2" @@ -6728,15 +6600,14 @@ } }, "node_modules/@nx/eslint-plugin": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-20.0.3.tgz", - "integrity": "sha512-KQi2rHwRQjQDqt7g4666LdKVBUNcHubX1MlXCB/f0ejCJunlybqK4aA+LiM0KIQpieevvIlAHJuTdZQ2M7q2HQ==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-20.1.2.tgz", + "integrity": "sha512-eLOVzaBPwS71Bb07jhJFZYtkvD33fZb3ObwLDXG5DmfpNpYBGOD4XX0qj6eq/5cfsIck6n8n7RKVm+7ZyqYowg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint/compat": "^1.1.1", - "@nx/devkit": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/js": "20.1.2", "@typescript-eslint/type-utils": "^8.0.0", "@typescript-eslint/utils": "^8.0.0", "chalk": "^4.1.0", @@ -6756,105 +6627,6 @@ } } }, - "node_modules/@nx/eslint-plugin/node_modules/@eslint/compat": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.1.tgz", - "integrity": "sha512-JbHG2TWuCeNzh87fXo+/46Z1LEo9DBA9T188d0fZgGxAD+cNyS6sx9fdiyxjGPBMyQVRlCutTByZ6a5+YMkF7g==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": "^9.10.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/@nx/eslint-plugin/node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@nx/eslint-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@nx/eslint-plugin/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6871,19 +6643,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@nx/eslint-plugin/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/@nx/eslint-plugin/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6901,150 +6660,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@nx/eslint-plugin/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/eslint": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", - "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.13.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/@nx/eslint-plugin/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@nx/eslint-plugin/node_modules/globals": { "version": "15.11.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", @@ -7068,45 +6683,6 @@ "node": ">=8" } }, - "node_modules/@nx/eslint-plugin/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@nx/eslint-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@nx/eslint-plugin/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@nx/eslint-plugin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7135,16 +6711,16 @@ } }, "node_modules/@nx/jest": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-20.0.3.tgz", - "integrity": "sha512-ZC9OPSh1htpYEh+kGZAew5r1pLtOCZo3odqW7/DalCti2XOTVit8yuw1DahIqrzZ3BzcTq+q9W9Ng17mMVCaCA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-20.1.2.tgz", + "integrity": "sha512-KUHm+NcH4Iq/Pk6GpaRhACEHd8Gt28dbXUAErxo/T9b+a3ir/6uUb4Sr+aXf63uYSePDhUmYbrYxGf/KzS2I8w==", "dev": true, "license": "MIT", "dependencies": { "@jest/reporters": "^29.4.1", "@jest/test-result": "^29.4.1", - "@nx/devkit": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/js": "20.1.2", "@phenomnomnominal/tsquery": "~5.0.1", "chalk": "^4.1.0", "identity-obj-proxy": "3.0.0", @@ -7215,9 +6791,9 @@ } }, "node_modules/@nx/js": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-20.0.3.tgz", - "integrity": "sha512-UbltxJyfEXL586kk7yxOTNHtigd7rq7atmcOmMphcxbeWk9HzeowVh6j6OA4MAKwYauomjCqsJbvWURI8qf+pg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/js/-/js-20.1.2.tgz", + "integrity": "sha512-+ULLy0vuAUyRicQqjMsG3JmgEylZdciJJOuOanwrmmG/+jv64nUJYycZbwPmGsioViHk/0WB1d5SWWfH7cZ+Ww==", "dev": true, "license": "MIT", "dependencies": { @@ -7228,8 +6804,8 @@ "@babel/preset-env": "^7.23.2", "@babel/preset-typescript": "^7.22.5", "@babel/runtime": "^7.22.6", - "@nx/devkit": "20.0.3", - "@nx/workspace": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/workspace": "20.1.2", "@zkochan/js-yaml": "0.0.7", "babel-plugin-const-enum": "^1.0.1", "babel-plugin-macros": "^2.8.0", @@ -7503,17 +7079,17 @@ } }, "node_modules/@nx/nest": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nest/-/nest-20.0.3.tgz", - "integrity": "sha512-8Il3BcyiJfj5vAXszlX+QqRlvAU9eudoc59q8GIXzU9vyrjrYcazpxkQr+qJ2q8mLdvJYJYMpA4ilbE6y6PQPw==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nest/-/nest-20.1.2.tgz", + "integrity": "sha512-pNQTI30KMnvCh39aBIX7LFY1hgolN4xH7K2Oc/49Hm87cbySg18nYHnTnotz0Yyy3CR5Q6/smL0uZXfBPJ3WTw==", "dev": true, "license": "MIT", "dependencies": { "@nestjs/schematics": "^9.1.0", - "@nx/devkit": "20.0.3", - "@nx/eslint": "20.0.3", - "@nx/js": "20.0.3", - "@nx/node": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/eslint": "20.1.2", + "@nx/js": "20.1.2", + "@nx/node": "20.1.2", "tslib": "^2.3.0" } }, @@ -7645,23 +7221,23 @@ } }, "node_modules/@nx/node": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/node/-/node-20.0.3.tgz", - "integrity": "sha512-50JqKEVRmh2g9bxBxB0hDVzNae6rf9d5Iu8bTxpF55h6kivdoiYF793/awpxCpE6XPCij9IafeoaT77Ug8dQYA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/node/-/node-20.1.2.tgz", + "integrity": "sha512-PGPSXkzTJc97GnsRNSBcekH5L5BM/SCSWA8lH/bBV/N8HBFUWppsv0Nj+UUcGGH3O3kjEMrhtbG9iJijX7+9kw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "20.0.3", - "@nx/eslint": "20.0.3", - "@nx/jest": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/eslint": "20.1.2", + "@nx/jest": "20.1.2", + "@nx/js": "20.1.2", "tslib": "^2.3.0" } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.0.3.tgz", - "integrity": "sha512-/wjxSuQZOHwDopNAfuh2BTsaDtDECjTDrKHJdTknrSVjdsB2b1hwSdL7Ct0PXBiSnf+0gfYBR2fuPmLZYb3AXA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-20.1.2.tgz", + "integrity": "sha512-PJ91TQhd28kitDBubKUOXMYvrtSDrG+rr8MsIe9cHo1CvU9smcGVBwuHBxniq0DXsyOX/5GL6ngq7hjN2nQ3XQ==", "cpu": [ "arm64" ], @@ -7676,9 +7252,9 @@ } }, "node_modules/@nx/nx-darwin-x64": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.0.3.tgz", - "integrity": "sha512-Gobgkvsx61P5TI0uuDQTI/D2AXJt3xnBuAWQ4V/NW/OpkvL8j/q8zk81uK0tumVvIc4p5kSlGmQ46/ytSrdqvg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-20.1.2.tgz", + "integrity": "sha512-1fopau7nxIhTF26vDTIzMxl15AtW4FvUSdy+r1mNRKrKyjjpqnlu00SQBW7JzGV0agDD1B/61yYei5Q2aMOt7Q==", "cpu": [ "x64" ], @@ -7693,9 +7269,9 @@ } }, "node_modules/@nx/nx-freebsd-x64": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.0.3.tgz", - "integrity": "sha512-nbYp89BP0z0DzuaUH/yVVhCbL96vUUaKmCVmmdlvQRgiaX89BChAMuEdLNSeaDHFrhgTYB87ku3Ok6DRCAIOcg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-20.1.2.tgz", + "integrity": "sha512-55YgIp3v4zz7xMzJO93dtglbOTER2XdS6jrCt8GbKaWGFl5drRrBoNGONtiGNU7C3hLx1VsorbynCkJT18PjKQ==", "cpu": [ "x64" ], @@ -7710,9 +7286,9 @@ } }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.0.3.tgz", - "integrity": "sha512-eKIYJPvXO/N1FjteZHC4DLV0u+2h70RmrDQODPztfl3mI5AjCwFdLf9RPN1D+SuNdfK1WwZIszY+FiVxrpK19A==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-20.1.2.tgz", + "integrity": "sha512-sMhNA8uAV43UYVEXEa8TZ8Fjpom4CGq1umTptEGOF4TTtdNn2AUBreg+0bVODM8MMSzRWGI1VbkZzHESnAPwqw==", "cpu": [ "arm" ], @@ -7727,9 +7303,9 @@ } }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.0.3.tgz", - "integrity": "sha512-CDFy2WNsMZvxshtGdFV/yCux1XkLtcqh0FiitNvGdgNugXXp3CLVEUx6dI3VBuIBNGbfozdr7n+fuXN6F2S4MQ==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-20.1.2.tgz", + "integrity": "sha512-bsevarNHglaYLmIvPNQOdHrBnBgaW3EOUM0flwaXdWuZbL1bWx8GoVwHp9yJpZOAOfIF/Nhq5iTpaZB2nYFrAA==", "cpu": [ "arm64" ], @@ -7744,9 +7320,9 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.0.3.tgz", - "integrity": "sha512-BGrSRNPuDyj0yeP2MyzF1MMij1KO4Q/2YSgBbYzVSc8JdrUqf+3rqI8VXNTr3FcAKMTPgFjkFZ3XD3s/62gsdg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-20.1.2.tgz", + "integrity": "sha512-GFZTptkhZPL/iZ3tYDmspIcPEaXyy/L/o59gyp33GoFAAyDhiXIF7J1Lz81Xn8VKrX6TvEY8/9qSh86pb7qzDQ==", "cpu": [ "arm64" ], @@ -7761,9 +7337,9 @@ } }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.0.3.tgz", - "integrity": "sha512-xGGjQ8q5XuF0/432APvAi/OSMdR3LZ1yQ9hYh+JGvM5wh44I3UbgBXRCJlsHp+t2hdlilF6kpaeMSiP1Z9CEbg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-20.1.2.tgz", + "integrity": "sha512-yqEW/iglKT4d9lgfnwSNhmDzPxCkRhtdmZqOYpGDM0eZFwYwJF+WRGjW8xIqMj8PA1yrGItzXZOmyFjJqHAF2w==", "cpu": [ "x64" ], @@ -7778,9 +7354,9 @@ } }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.0.3.tgz", - "integrity": "sha512-fTmZNbq3QQF5BLGPB8PGuFuNo3s2F86IQDOUYWpjXiuKjoI1Y5yM14RQpHLwYOGnUNoKYOhlv/JAyFrDX6ALZA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-20.1.2.tgz", + "integrity": "sha512-SP6PpWT4cQVrC4WJQdpfADrYJQzkbhgmcGleWbpr7II1HJgOsAcvoDwQGpPQX+3Wo+VBiNecvUAOzacMQkXPGw==", "cpu": [ "x64" ], @@ -7795,9 +7371,9 @@ } }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.0.3.tgz", - "integrity": "sha512-hdtfg9pIzhtLqqGvsTemQYwe+kqqL1JGNgrlf3V59HSbbAADYZbHnliujoRybJo7dpeS/DDTNMNeblg99tFQLA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-20.1.2.tgz", + "integrity": "sha512-JZQx9gr39LY3D7uleiXlpxUsavuOrOQNBocwKHkAMnykaT/e1VCxTnm/hk+2b4foWwfURTqoRiFEba70iiCdYg==", "cpu": [ "arm64" ], @@ -7812,9 +7388,9 @@ } }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.0.3.tgz", - "integrity": "sha512-HcqE8AlWuwcsIOj0OnKDQ3q7L0RZsOrBRhDRKbJeUnIFz/t2R3q8Y6trrqTyFAafgW6JNLBp+tgcUyfHPUy/eQ==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-20.1.2.tgz", + "integrity": "sha512-6GmT8iswDiCvJaCtW9DpWeAQmLS/kfAuRLYBisfzlONuLPaDdjhgVIxZBqqUSFfclwcVz+NhIOGvdr0aGFZCtQ==", "cpu": [ "x64" ], @@ -7829,30 +7405,30 @@ } }, "node_modules/@nx/storybook": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/storybook/-/storybook-20.0.3.tgz", - "integrity": "sha512-Nt5iWUYDEvA+S8I9aFnF5fhODV+H74XR+lS8kza+o0K4kRqhdvzp7WB3SanEuY/k3kbhP7M99dbBRZXJi3Sgdg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/storybook/-/storybook-20.1.2.tgz", + "integrity": "sha512-M3ymcFuMYgZ2GT6hPjvVbtSCyfVPGmDy7DY1oHOYBkLqywkjzTcpjmN6Kqm5ZQUZfKYFWgIkNs2J5VL9Knn3cg==", "dev": true, "license": "MIT", "dependencies": { - "@nx/cypress": "20.0.3", - "@nx/devkit": "20.0.3", - "@nx/eslint": "20.0.3", - "@nx/js": "20.0.3", + "@nx/cypress": "20.1.2", + "@nx/devkit": "20.1.2", + "@nx/eslint": "20.1.2", + "@nx/js": "20.1.2", "@phenomnomnominal/tsquery": "~5.0.1", "semver": "^7.5.3", "tslib": "^2.3.0" } }, "node_modules/@nx/web": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/web/-/web-20.0.3.tgz", - "integrity": "sha512-b3KpUeA0cI9JIpRBYEk/4sIs9nCI6RcXCmxFoyW60vYsr2VtPZjtLKbo3bBT7HLOk3iwAYYWzCY1cu0Xzig3Lg==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/web/-/web-20.1.2.tgz", + "integrity": "sha512-CRMAJXwj375J+/GI9hRfOt2SJ0DQ5prCzOcmXJvQIfHy3CT5chrkSj2qc7IgKkkMiqZojr4VCTUHmJ2WAR3sCw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/js": "20.1.2", "detect-port": "^1.5.1", "http-server": "^14.1.0", "picocolors": "^1.1.0", @@ -7860,35 +7436,35 @@ } }, "node_modules/@nx/webpack": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-20.0.3.tgz", - "integrity": "sha512-r9oBx1BV3zm6292TZnQd+6dwSx9Gixl5AgneJmAVQvT65moLfg2bL8t0G6sSodxYChcXVB7mJriXDAJjMbb48w==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-20.1.2.tgz", + "integrity": "sha512-H67DkdpaGnUwYbz4u31+2/TSRmkvBQHX742FNKJAc1/D0uzHH6GI3am0h0QF9wrJyc/fXGVNfRZLEh9ScU70Jw==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", "@module-federation/enhanced": "^0.6.0", "@module-federation/sdk": "^0.6.0", - "@nx/devkit": "20.0.3", - "@nx/js": "20.0.3", + "@nx/devkit": "20.1.2", + "@nx/js": "20.1.2", "@phenomnomnominal/tsquery": "~5.0.1", "ajv": "^8.12.0", "autoprefixer": "^10.4.9", "babel-loader": "^9.1.2", "browserslist": "^4.21.4", - "chalk": "^4.1.0", "copy-webpack-plugin": "^10.2.4", "css-loader": "^6.4.0", "css-minimizer-webpack-plugin": "^5.0.0", "express": "^4.19.2", "fork-ts-checker-webpack-plugin": "7.2.13", - "http-proxy-middleware": "^3.0.0", + "http-proxy-middleware": "^3.0.3", "less": "4.1.3", "less-loader": "11.1.0", "license-webpack-plugin": "^4.0.2", "loader-utils": "^2.0.3", "mini-css-extract-plugin": "~2.4.7", "parse5": "4.0.0", + "picocolors": "^1.1.0", "postcss": "^8.4.38", "postcss-import": "~14.1.0", "postcss-loader": "^6.1.1", @@ -7897,7 +7473,7 @@ "sass-loader": "^12.2.0", "source-map-loader": "^5.0.0", "style-loader": "^3.3.0", - "stylus": "^0.59.0", + "stylus": "^0.64.0", "stylus-loader": "^7.1.0", "terser-webpack-plugin": "^5.3.3", "ts-loader": "^9.3.1", @@ -7909,22 +7485,6 @@ "webpack-subresource-integrity": "^5.1.0" } }, - "node_modules/@nx/webpack/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@nx/webpack/node_modules/array-union": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", @@ -7973,23 +7533,23 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/@nx/webpack/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@nx/webpack/node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "ms": "2.0.0" } }, + "node_modules/@nx/webpack/node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/@nx/webpack/node_modules/cookie": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", @@ -8078,16 +7638,6 @@ } } }, - "node_modules/@nx/webpack/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/@nx/webpack/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -8141,6 +7691,23 @@ "node": ">= 0.10.0" } }, + "node_modules/@nx/webpack/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@nx/webpack/node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/@nx/webpack/node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", @@ -8160,6 +7727,23 @@ "node": ">= 0.8" } }, + "node_modules/@nx/webpack/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@nx/webpack/node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/@nx/webpack/node_modules/globby": { "version": "12.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", @@ -8181,14 +7765,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nx/webpack/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@nx/webpack/node_modules/http-proxy-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@nx/webpack/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/@nx/webpack/node_modules/less": { @@ -8311,9 +7913,9 @@ } }, "node_modules/@nx/webpack/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -8455,6 +8057,23 @@ "node": ">= 0.8.0" } }, + "node_modules/@nx/webpack/node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@nx/webpack/node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/@nx/webpack/node_modules/send/node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -8465,13 +8084,6 @@ "node": ">= 0.8" } }, - "node_modules/@nx/webpack/node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@nx/webpack/node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -8512,30 +8124,17 @@ "node": ">=0.10.0" } }, - "node_modules/@nx/webpack/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@nx/workspace": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-20.0.3.tgz", - "integrity": "sha512-ctStDr9UlXt63v9wC1qS9lqLABSDfcfCH/FtQ6ZF5RjWIkzZS672g29gkT83L9B87dfRJYCH8yGGbvMJzq0qRA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-20.1.2.tgz", + "integrity": "sha512-YZiBwHU+NsJvJ7e7AZnyk5cP523AIHmHFf28nEpBY3zhxLghx/s9C99Swbw+uUyWlUf7JtTO9jB6OsEfMc38Uw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "20.0.3", + "@nx/devkit": "20.1.2", "chalk": "^4.1.0", "enquirer": "~2.3.6", - "nx": "20.0.3", + "nx": "20.1.2", "tslib": "^2.3.0", "yargs-parser": "21.1.1" } @@ -8753,13 +8352,13 @@ "license": "MIT" }, "node_modules/@prisma/client": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.21.1.tgz", - "integrity": "sha512-3n+GgbAZYjaS/k0M03yQsQfR1APbr411r74foknnsGpmhNKBG49VuUkxIU6jORgvJPChoD4WC4PqoHImN1FP0w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.0.0.tgz", + "integrity": "sha512-tOBhG35ozqZ/5Y6B0TNOa6cwULUW8ijXqBXcgb12bfozqf6eGMyGs+jphywCsj6uojv5lAZZnxVSoLMVebIP+g==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { - "node": ">=16.13" + "node": ">=18.18" }, "peerDependencies": { "prisma": "*" @@ -8771,53 +8370,53 @@ } }, "node_modules/@prisma/debug": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.21.1.tgz", - "integrity": "sha512-uY8SAhcnORhvgtOrNdvWS98Aq/nkQ9QDUxrWAgW8XrCZaI3j2X7zb7Xe6GQSh6xSesKffFbFlkw0c2luHQviZA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.0.0.tgz", + "integrity": "sha512-eUjoNThlDXdyJ1iQ2d7U6aTVwm59EwvODb5zFVNJEokNoSiQmiYWNzZIwZyDmZ+j51j42/0iTaHIJ4/aZPKFRg==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.21.1.tgz", - "integrity": "sha512-hGVTldUkIkTwoV8//hmnAAiAchi4oMEKD3aW5H2RrnI50tTdwza7VQbTTAyN3OIHWlK5DVg6xV7X8N/9dtOydA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.0.0.tgz", + "integrity": "sha512-ZZCVP3q22ifN6Ex6C8RIcTDBlRtMJS2H1ljV0knCiWNGArvvkEbE88W3uDdq/l4+UvyvHpGzdf9ZsCWSQR7ZQQ==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.21.1", - "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", - "@prisma/fetch-engine": "5.21.1", - "@prisma/get-platform": "5.21.1" + "@prisma/debug": "6.0.0", + "@prisma/engines-version": "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e", + "@prisma/fetch-engine": "6.0.0", + "@prisma/get-platform": "6.0.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36.tgz", - "integrity": "sha512-qvnEflL0//lh44S/T9NcvTMxfyowNeUxTunPcDfKPjyJNrCNf2F1zQLcUv5UHAruECpX+zz21CzsC7V2xAeM7Q==", + "version": "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e.tgz", + "integrity": "sha512-JmIds0Q2/vsOmnuTJYxY4LE+sajqjYKhLtdOT6y4imojqv5d/aeVEfbBGC74t8Be1uSp0OP8lxIj2OqoKbLsfQ==", "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.21.1.tgz", - "integrity": "sha512-70S31vgpCGcp9J+mh/wHtLCkVezLUqe/fGWk3J3JWZIN7prdYSlr1C0niaWUyNK2VflLXYi8kMjAmSxUVq6WGQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.0.0.tgz", + "integrity": "sha512-j2m+iO5RDPRI7SUc7sHo8wX7SA4iTkJ+18Sxch8KinQM46YiCQD1iXKN6qU79C1Fliw5Bw/qDyTHaTsa3JMerA==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.21.1", - "@prisma/engines-version": "5.21.1-1.bf0e5e8a04cada8225617067eaa03d041e2bba36", - "@prisma/get-platform": "5.21.1" + "@prisma/debug": "6.0.0", + "@prisma/engines-version": "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e", + "@prisma/get-platform": "6.0.0" } }, "node_modules/@prisma/get-platform": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.21.1.tgz", - "integrity": "sha512-sRxjL3Igst3ct+e8ya/x//cDXmpLbZQ5vfps2N4tWl4VGKQAmym77C/IG/psSMsQKszc8uFC/q1dgmKFLUgXZQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.0.0.tgz", + "integrity": "sha512-PS6nYyIm9g8C03E4y7LknOfdCw/t2KyEJxntMPQHQZCOUgOpF82Ma60mdlOD08w90I3fjLiZZ0+MadenR3naDQ==", "devOptional": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.21.1" + "@prisma/debug": "6.0.0" } }, "node_modules/@redis/bloom": { @@ -9324,6 +8923,20 @@ "storybook": "^8.3.6" } }, + "node_modules/@storybook/addon-actions/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@storybook/addon-backgrounds": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-8.3.6.tgz", @@ -10758,9 +10371,9 @@ } }, "node_modules/@stripe/stripe-js": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-3.5.0.tgz", - "integrity": "sha512-pKS3wZnJoL1iTyGBXAvCwduNNeghJHY6QSRSNNvpYnrrQrLZ6Owsazjyynu0e0ObRgks0i7Rv+pe2M7/MBTZpQ==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-4.9.0.tgz", + "integrity": "sha512-tMPZQZZXGWyNX7hbgenq+1xEj2oigJ54XddbtSX36VedoKsPBq7dxwRXu4Xd5FdpT3JDyyDtnmvYkaSnH1yHTQ==", "license": "MIT", "engines": { "node": ">=12.16" @@ -12560,9 +12173,9 @@ "license": "BSD-2-Clause" }, "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.2.tgz", + "integrity": "sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12570,7 +12183,7 @@ "tslib": "^2.4.0" }, "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" } }, "node_modules/@zkochan/js-yaml": { @@ -14668,21 +14281,25 @@ } }, "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">= 6" + "node": ">=18.17" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -14705,6 +14322,34 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cheerio/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/cheerio/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -15657,9 +15302,9 @@ } }, "node_modules/countries-and-timezones": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.4.1.tgz", - "integrity": "sha512-INeHGCony4XUUR8iGL/lmt9s1Oi+n+gFHeJAMfbV5hJfYeDOB8JG1oxz5xFQu5oBZoRCJe/87k1Vzue9DoIauA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.7.2.tgz", + "integrity": "sha512-BHAMt4pKb3U3r/mRfiIlVnDhRd8m6VC20gwCWtpZGZkSsjZmnMDKFnnjWYGWhBmypQAqcQILFJwmEhIgWGVTmw==", "license": "MIT", "engines": { "node": ">=8.x", @@ -15667,9 +15312,9 @@ } }, "node_modules/countries-list": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.1.0.tgz", - "integrity": "sha512-HpTBLZba1VPTZSjUnUwR7SykxV7Z/7/+ZM5x5wi5tO99Qvom6bE2SC+AQ18016ujg3jSlYBbMITrHNnPAHSM9Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.1.1.tgz", + "integrity": "sha512-nPklKJ5qtmY5MdBKw1NiBAoyx5Sa7p2yPpljZyQ7gyCN1m+eMFs9I6CT37Mxt8zvR5L3VzD3DJBE4WQzX3WF4A==", "license": "MIT" }, "node_modules/countup.js": { @@ -17678,6 +17323,43 @@ "iconv-lite": "^0.6.2" } }, + "node_modules/encoding-sniffer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz", + "integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/encoding-sniffer/node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/encoding/node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -26195,6 +25877,20 @@ "web-worker": "^1.2.0" } }, + "node_modules/mermaid/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -27282,23 +26978,22 @@ } }, "node_modules/ngx-skeleton-loader": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ngx-skeleton-loader/-/ngx-skeleton-loader-7.0.0.tgz", - "integrity": "sha512-myc6GNcNhyksZrimIFkCxeihi0kQ8JhQVZiGbtiIv4gYrnnRk5nXbs3kYitK8E8OstHG+jlsmRofqGBxuIsYTA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ngx-skeleton-loader/-/ngx-skeleton-loader-9.0.0.tgz", + "integrity": "sha512-aO4/V6oGdZGNcTjasTg/fwzJJYl/ZmNKgCukOEQdUK3GSFOZtB/3GGULMJuZ939hk3Hzqh1OBiLfIM1SqTfhqg==", "license": "MIT", "dependencies": { - "perf-marks": "^1.13.4", "tslib": "^2.0.0" }, "peerDependencies": { - "@angular/common": ">=8.0.0", - "@angular/core": ">=8.0.0" + "@angular/common": ">=16.0.0", + "@angular/core": ">=16.0.0" } }, "node_modules/ngx-stripe": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/ngx-stripe/-/ngx-stripe-18.0.0.tgz", - "integrity": "sha512-AT67vLeqEUDMnK5TfEaorumYJyOWqecbrh/1UWNtN8vF6Yzb0L/Dty3ANAa/QQi0OvBg6gXrudrhEnT8pT5lng==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/ngx-stripe/-/ngx-stripe-18.1.0.tgz", + "integrity": "sha512-fNWmFaCWWzfsr8GU9Bmi6fwgHZHMI9UwpV5M0HMvkANnz9n7JWjP2Uck6zk0lXdu9q989aIbqj4awbLCZk/TUw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -27306,7 +27001,7 @@ "peerDependencies": { "@angular/common": ">=18.0.0 <19.0.0", "@angular/core": ">=18.0.0 <19.0.0", - "@stripe/stripe-js": ">=3.0.0 <4.0.0" + "@stripe/stripe-js": ">=4.0.0 <5.0.0" } }, "node_modules/nice-napi": { @@ -27766,16 +27461,16 @@ "license": "MIT" }, "node_modules/nx": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/nx/-/nx-20.0.3.tgz", - "integrity": "sha512-6ZuZ09IdMIwbklKqEwUAHspuVMsDr7TIcCyeytmdDC1XbA+Tbb93wriyJyiI9EBQw4StrlJF9vSXAZsuDiOKeA==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/nx/-/nx-20.1.2.tgz", + "integrity": "sha512-CvjmuQmI0RWLYZxRSIgQZmzsQv6dPp9oI0YZE3L1dagBPfTf5Cun65I0GLt7bdkDnVx2PGYkDbIoJSv2/V+83Q==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", + "@yarnpkg/parsers": "3.0.2", "@zkochan/js-yaml": "0.0.7", "axios": "^1.7.4", "chalk": "^4.1.0", @@ -27811,16 +27506,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "20.0.3", - "@nx/nx-darwin-x64": "20.0.3", - "@nx/nx-freebsd-x64": "20.0.3", - "@nx/nx-linux-arm-gnueabihf": "20.0.3", - "@nx/nx-linux-arm64-gnu": "20.0.3", - "@nx/nx-linux-arm64-musl": "20.0.3", - "@nx/nx-linux-x64-gnu": "20.0.3", - "@nx/nx-linux-x64-musl": "20.0.3", - "@nx/nx-win32-arm64-msvc": "20.0.3", - "@nx/nx-win32-x64-msvc": "20.0.3" + "@nx/nx-darwin-arm64": "20.1.2", + "@nx/nx-darwin-x64": "20.1.2", + "@nx/nx-freebsd-x64": "20.1.2", + "@nx/nx-linux-arm-gnueabihf": "20.1.2", + "@nx/nx-linux-arm64-gnu": "20.1.2", + "@nx/nx-linux-arm64-musl": "20.1.2", + "@nx/nx-linux-x64-gnu": "20.1.2", + "@nx/nx-linux-x64-musl": "20.1.2", + "@nx/nx-win32-arm64-msvc": "20.1.2", + "@nx/nx-win32-x64-msvc": "20.1.2" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -27905,13 +27600,13 @@ } }, "node_modules/nx/node_modules/dotenv-expand": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz", - "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==", + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "dotenv": "^16.4.4" + "dotenv": "^16.4.5" }, "engines": { "node": ">=12" @@ -28645,6 +28340,18 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parse5-sax-parser": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", @@ -28847,18 +28554,6 @@ "dev": true, "license": "MIT" }, - "node_modules/perf-marks": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/perf-marks/-/perf-marks-1.14.2.tgz", - "integrity": "sha512-N0/bQcuTlETpgox/DsXS1voGjqaoamMoiyhncgeW3rSHy/qw8URVgmPRYfFDQns/+C6yFUHDbeSBGL7ixT6Y4A==", - "license": "MIT", - "dependencies": { - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -29794,20 +29489,20 @@ } }, "node_modules/prisma": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.21.1.tgz", - "integrity": "sha512-PB+Iqzld/uQBPaaw2UVIk84kb0ITsLajzsxzsadxxl54eaU5Gyl2/L02ysivHxK89t7YrfQJm+Ggk37uvM70oQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.0.0.tgz", + "integrity": "sha512-RX7KtbW7IoEByf7MR32JK1PkVYLVYFqeODTtiIX3cqekq1aKdsF3Eud4zp2sUShMLjvdb5Jow0LbUjRq5LVxPw==", "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.21.1" + "@prisma/engines": "6.0.0" }, "bin": { "prisma": "build/index.js" }, "engines": { - "node": ">=16.13" + "node": ">=18.18" }, "optionalDependencies": { "fsevents": "2.3.3" @@ -30049,9 +29744,9 @@ } }, "node_modules/rambda": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/rambda/-/rambda-9.3.0.tgz", - "integrity": "sha512-cl/7DCCKNxmsbc0dXZTJTY08rvDdzLhVfE6kPBson1fWzDapLzv0RKSzjpmAqP53fkQqAvq05gpUVHTrUNsuxg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-9.4.0.tgz", + "integrity": "sha512-B7y7goUd+g0hNl5ODGUejNNERQL5gD8uANJ5Y5aHly8v0jKesFlwIe7prPfuJxttDpe3otQzHJ4NXMpTmL9ELA==", "dev": true, "license": "MIT" }, @@ -32307,9 +32002,9 @@ } }, "node_modules/stripe": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-15.11.0.tgz", - "integrity": "sha512-qmZF0PN1jRVpiQrXL8eTb9Jy/6S+aUlcDquKBFT2h3PkaD7RZ444FIojVXUg67FK2zFIUNXgMv02c7csdL5qHg==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-17.3.0.tgz", + "integrity": "sha512-WACmytj1MssbIwGwPfAomo61jgldb2B/cB6A3W/Bqs9zId1olVcAa8X7HERkqpw4190GSsbvrD7KnkZogatyvw==", "license": "MIT", "dependencies": { "@types/node": ">=8.1.0", @@ -32361,23 +32056,23 @@ "optional": true }, "node_modules/stylus": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", - "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.64.0.tgz", + "integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==", "devOptional": true, "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.0.1", + "@adobe/css-tools": "~4.3.3", "debug": "^4.3.2", - "glob": "^7.1.6", - "sax": "~1.2.4", + "glob": "^10.4.5", + "sax": "~1.4.1", "source-map": "^0.7.3" }, "bin": { "stylus": "bin/stylus" }, "engines": { - "node": "*" + "node": ">=16" }, "funding": { "url": "https://opencollective.com/stylus" @@ -32405,12 +32100,49 @@ "webpack": "^5.0.0" } }, - "node_modules/stylus/node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "node_modules/stylus/node_modules/@adobe/css-tools": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz", + "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==", "devOptional": true, - "license": "ISC" + "license": "MIT" + }, + "node_modules/stylus/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylus/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/supports-color": { "version": "5.5.0", @@ -33621,6 +33353,15 @@ "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", "license": "MIT" }, + "node_modules/undici": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -33989,16 +33730,16 @@ } }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/uvu": { diff --git a/package.json b/package.json index b83ce5c5..7f124ea2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.119.0", + "version": "2.125.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", @@ -86,10 +86,10 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.21.1", + "@prisma/client": "6.0.0", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", - "@stripe/stripe-js": "3.5.0", + "@stripe/stripe-js": "4.9.0", "alphavantage": "2.2.0", "big.js": "6.2.1", "body-parser": "1.20.2", @@ -102,12 +102,12 @@ "chartjs-chart-treemap": "2.3.1", "chartjs-plugin-annotation": "2.1.2", "chartjs-plugin-datalabels": "2.2.0", - "cheerio": "1.0.0-rc.12", + "cheerio": "1.0.0", "class-transformer": "0.5.1", "class-validator": "0.14.1", "color": "4.2.3", - "countries-and-timezones": "3.4.1", - "countries-list": "3.1.0", + "countries-and-timezones": "3.7.2", + "countries-list": "3.1.1", "countup.js": "2.8.0", "date-fns": "3.6.0", "envalid": "7.3.1", @@ -123,8 +123,8 @@ "ng-extract-i18n-merge": "2.12.0", "ngx-device-detector": "8.0.0", "ngx-markdown": "18.0.0", - "ngx-skeleton-loader": "7.0.0", - "ngx-stripe": "18.0.0", + "ngx-skeleton-loader": "9.0.0", + "ngx-stripe": "18.1.0", "open-color": "1.9.1", "papaparse": "5.3.1", "passport": "0.7.0", @@ -132,10 +132,10 @@ "passport-jwt": "4.0.1", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", - "stripe": "15.11.0", + "stripe": "17.3.0", "svgmap": "2.6.0", "twitter-api-v2": "1.14.2", - "uuid": "9.0.1", + "uuid": "11.0.2", "yahoo-finance2": "2.11.3", "zone.js": "0.14.10" }, @@ -153,16 +153,16 @@ "@angular/pwa": "18.2.9", "@nestjs/schematics": "10.0.1", "@nestjs/testing": "10.1.3", - "@nx/angular": "20.0.3", - "@nx/cypress": "20.0.3", - "@nx/eslint-plugin": "20.0.3", - "@nx/jest": "20.0.3", - "@nx/js": "20.0.3", - "@nx/nest": "20.0.3", - "@nx/node": "20.0.3", - "@nx/storybook": "20.0.3", - "@nx/web": "20.0.3", - "@nx/workspace": "20.0.3", + "@nx/angular": "20.1.2", + "@nx/cypress": "20.1.2", + "@nx/eslint-plugin": "20.1.2", + "@nx/jest": "20.1.2", + "@nx/js": "20.1.2", + "@nx/nest": "20.1.2", + "@nx/node": "20.1.2", + "@nx/storybook": "20.1.2", + "@nx/web": "20.1.2", + "@nx/workspace": "20.1.2", "@schematics/angular": "18.2.9", "@simplewebauthn/types": "9.0.1", "@storybook/addon-essentials": "8.3.6", @@ -193,10 +193,10 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "jest-preset-angular": "14.1.0", - "nx": "20.0.3", + "nx": "20.1.2", "prettier": "3.3.3", "prettier-plugin-organize-attributes": "1.0.0", - "prisma": "5.21.1", + "prisma": "6.0.0", "react": "18.2.0", "react-dom": "18.2.0", "replace-in-file": "7.0.1", diff --git a/prisma/migrations/20241029190323_added_data_provider_ghostfolio_daily_requests_to_analytics/migration.sql b/prisma/migrations/20241029190323_added_data_provider_ghostfolio_daily_requests_to_analytics/migration.sql new file mode 100644 index 00000000..a9566dd8 --- /dev/null +++ b/prisma/migrations/20241029190323_added_data_provider_ghostfolio_daily_requests_to_analytics/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Analytics" ADD COLUMN "dataProviderGhostfolioDailyRequests" INTEGER NOT NULL DEFAULT 0; diff --git a/prisma/migrations/20241102121004_added_last_request_at_to_analytics/migration.sql b/prisma/migrations/20241102121004_added_last_request_at_to_analytics/migration.sql new file mode 100644 index 00000000..b7af3103 --- /dev/null +++ b/prisma/migrations/20241102121004_added_last_request_at_to_analytics/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Analytics" ADD COLUMN "lastRequestAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- CreateIndex +CREATE INDEX "Analytics_lastRequestAt_idx" ON "Analytics"("lastRequestAt"); diff --git a/prisma/migrations/20241103110114_added_ghostfolio_to_data_source/migration.sql b/prisma/migrations/20241103110114_added_ghostfolio_to_data_source/migration.sql new file mode 100644 index 00000000..9687a87b --- /dev/null +++ b/prisma/migrations/20241103110114_added_ghostfolio_to_data_source/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "DataSource" ADD VALUE 'GHOSTFOLIO'; diff --git a/prisma/migrations/20241130164334_upgraded_to_prisma_6/migration.sql b/prisma/migrations/20241130164334_upgraded_to_prisma_6/migration.sql new file mode 100644 index 00000000..5fb7cc10 --- /dev/null +++ b/prisma/migrations/20241130164334_upgraded_to_prisma_6/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "_OrderToTag" ADD CONSTRAINT "_OrderToTag_AB_pkey" PRIMARY KEY ("A", "B"); + +-- DropIndex +DROP INDEX "_OrderToTag_AB_unique"; diff --git a/prisma/migrations/20241130164335_added_api_keys_to_user copy/migration.sql b/prisma/migrations/20241130164335_added_api_keys_to_user copy/migration.sql new file mode 100644 index 00000000..c538fd11 --- /dev/null +++ b/prisma/migrations/20241130164335_added_api_keys_to_user copy/migration.sql @@ -0,0 +1,19 @@ +-- CreateTable +CREATE TABLE "ApiKey" ( + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "hashedKey" TEXT NOT NULL, + "id" TEXT NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL, + "userId" TEXT NOT NULL, + + CONSTRAINT "ApiKey_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "ApiKey_hashedKey_idx" ON "ApiKey"("hashedKey"); + +-- CreateIndex +CREATE INDEX "ApiKey_userId_idx" ON "ApiKey"("userId"); + +-- AddForeignKey +ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9fa55076..e2587acf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -65,15 +65,30 @@ model AccountBalance { } model Analytics { - activityCount Int @default(0) - country String? - updatedAt DateTime @updatedAt - userId String @id - User User @relation(fields: [userId], onDelete: Cascade, references: [id]) + activityCount Int @default(0) + country String? + dataProviderGhostfolioDailyRequests Int @default(0) + lastRequestAt DateTime @default(now()) + updatedAt DateTime @updatedAt + userId String @id + User User @relation(fields: [userId], onDelete: Cascade, references: [id]) + @@index([lastRequestAt]) @@index([updatedAt]) } +model ApiKey { + createdAt DateTime @default(now()) + hashedKey String + id String @id @default(uuid()) + updatedAt DateTime @updatedAt + userId String + user User @relation(fields: [userId], onDelete: Cascade, references: [id]) + + @@index([hashedKey]) + @@index([userId]) +} + model AuthDevice { createdAt DateTime @default(now()) credentialId Bytes @@ -235,6 +250,7 @@ model User { AccessGive Access[] @relation("accessGive") Account Account[] Analytics Analytics? + ApiKey ApiKey[] AuthDevice AuthDevice[] Order Order[] Settings Settings? @@ -278,6 +294,7 @@ enum DataSource { COINGECKO EOD_HISTORICAL_DATA FINANCIAL_MODELING_PREP + GHOSTFOLIO GOOGLE_SHEETS MANUAL RAPID_API diff --git a/test/import/ok-derived-currency.json b/test/import/ok-derived-currency.json index b43be395..fe5554be 100644 --- a/test/import/ok-derived-currency.json +++ b/test/import/ok-derived-currency.json @@ -23,7 +23,7 @@ "unitPrice": 10875.00, "currency": "ZAc", "dataSource": "YAHOO", - "date": "2024-06-27T22:00:00.000Z", + "date": "2024-06-28T00:00:00.000Z", "symbol": "JSE.JO" } ] diff --git a/test/import/ok-vti-buy-long-history.json b/test/import/ok-vti-buy-long-history.json index e6020e40..1586cff7 100644 --- a/test/import/ok-vti-buy-long-history.json +++ b/test/import/ok-vti-buy-long-history.json @@ -11,7 +11,7 @@ "unitPrice": 65.31, "currency": "USD", "dataSource": "YAHOO", - "date": "2012-01-02T22:00:00.000Z", + "date": "2012-01-03T00:00:00.000Z", "symbol": "VTI" }, { @@ -21,7 +21,7 @@ "unitPrice": 65.40, "currency": "USD", "dataSource": "YAHOO", - "date": "2011-01-02T22:00:00.000Z", + "date": "2011-01-03T00:00:00.000Z", "symbol": "VTI" }, { @@ -31,7 +31,7 @@ "unitPrice": 57.05, "currency": "USD", "dataSource": "YAHOO", - "date": "2010-01-03T22:00:00.000Z", + "date": "2010-01-04T00:00:00.000Z", "symbol": "VTI" } ] diff --git a/test/import/ok-without-accounts.json b/test/import/ok-without-accounts.json index 63961be7..2ba0925b 100644 --- a/test/import/ok-without-accounts.json +++ b/test/import/ok-without-accounts.json @@ -11,7 +11,7 @@ "unitPrice": 0, "currency": "USD", "dataSource": "YAHOO", - "date": "2050-06-05T22:00:00.000Z", + "date": "2050-06-06T00:00:00.000Z", "symbol": "MSFT" }, { @@ -21,7 +21,7 @@ "unitPrice": 500000, "currency": "USD", "dataSource": "MANUAL", - "date": "2021-12-31T22:00:00.000Z", + "date": "2022-01-01T00:00:00.000Z", "symbol": "Penthouse Apartment" }, { @@ -31,7 +31,7 @@ "unitPrice": 0.62, "currency": "USD", "dataSource": "YAHOO", - "date": "2021-11-16T22:00:00.000Z", + "date": "2021-11-17T00:00:00.000Z", "symbol": "MSFT" }, { @@ -41,7 +41,7 @@ "unitPrice": 298.58, "currency": "USD", "dataSource": "YAHOO", - "date": "2021-09-15T22:00:00.000Z", + "date": "2021-09-16T00:00:00.000Z", "symbol": "MSFT" } ] diff --git a/test/import/ok.json b/test/import/ok.json index 0af28550..4bce98ba 100644 --- a/test/import/ok.json +++ b/test/import/ok.json @@ -23,7 +23,7 @@ "unitPrice": 0, "currency": "USD", "dataSource": "YAHOO", - "date": "2050-06-05T22:00:00.000Z", + "date": "2050-06-06T00:00:00.000Z", "symbol": "US5949181045" }, { @@ -35,7 +35,7 @@ "unitPrice": 500000, "currency": "USD", "dataSource": "MANUAL", - "date": "2021-12-31T22:00:00.000Z", + "date": "2022-01-01T00:00:00.000Z", "symbol": "Penthouse Apartment" }, { @@ -47,7 +47,7 @@ "unitPrice": 0.62, "currency": "USD", "dataSource": "YAHOO", - "date": "2021-11-16T22:00:00.000Z", + "date": "2021-11-17T00:00:00.000Z", "symbol": "MSFT" }, { @@ -59,7 +59,7 @@ "unitPrice": 298.58, "currency": "USD", "dataSource": "YAHOO", - "date": "2021-09-15T22:00:00.000Z", + "date": "2021-09-16T00:00:00.000Z", "symbol": "MSFT" }, { @@ -71,7 +71,7 @@ "unitPrice": 0, "currency": "USD", "dataSource": "MANUAL", - "date": "2021-08-31T22:00:00.000Z", + "date": "2021-09-01T00:00:00.000Z", "symbol": "Account Opening Fee" } ] diff --git a/test/import/unavailable-exchange-rate.json b/test/import/unavailable-exchange-rate.json index 2d21a76c..4d8be156 100644 --- a/test/import/unavailable-exchange-rate.json +++ b/test/import/unavailable-exchange-rate.json @@ -12,7 +12,7 @@ "unitPrice": 0, "currency": "EUR", "dataSource": "YAHOO", - "date": "1990-01-01T22:00:00.000Z", + "date": "1990-01-01T00:00:00.000Z", "symbol": "MSFT" } ]