305 lines
13 KiB
Dart
305 lines
13 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import 'ticker_model.dart';
|
|
import 'company_officer_model.dart';
|
|
import 'financial_statement_model.dart';
|
|
import 'forward_estimate_model.dart';
|
|
|
|
export 'ticker_model.dart';
|
|
export 'company_officer_model.dart';
|
|
export 'financial_statement_model.dart';
|
|
export 'forward_estimate_model.dart';
|
|
|
|
class FundamentalDataModel extends Equatable {
|
|
final String isin;
|
|
final String primaryTicker;
|
|
final String ticker;
|
|
final String companyName;
|
|
final String? exchange;
|
|
final String? tradingCurrency;
|
|
final String? businessSummary;
|
|
final String? sector;
|
|
final String? industry;
|
|
final String? country;
|
|
final int? employees;
|
|
|
|
final double currentPrice;
|
|
final double dayChangeAbsolute;
|
|
final double dayChangePercent;
|
|
final double? fiftyTwoWeekHigh;
|
|
final double? fiftyTwoWeekLow;
|
|
final double? marketCapitalization;
|
|
final double? enterpriseValue;
|
|
|
|
final double? peRatioTrailing;
|
|
final double? peRatioForward;
|
|
final double? pegRatio;
|
|
final double? pbRatio;
|
|
final double? psRatio;
|
|
final double? evToEbitda;
|
|
final double? evToRevenue;
|
|
|
|
final double? totalRevenue;
|
|
final double? revenueGrowthYoY;
|
|
final double? grossProfit;
|
|
final double? ebitda;
|
|
final double? dilutedEps;
|
|
final double? totalCash;
|
|
final double? totalDebt;
|
|
final double? operatingCashFlow;
|
|
final double? freeCashFlow;
|
|
|
|
final double? grossMargin;
|
|
final double? operatingMargin;
|
|
final double? netProfitMargin;
|
|
final double? returnOnEquity;
|
|
final double? returnOnAssets;
|
|
final double? returnOnInvestedCapital;
|
|
final double? debtToEquity;
|
|
final double? currentRatio;
|
|
final double? quickRatio;
|
|
final double? interestCoverage;
|
|
|
|
final double? dividendYield;
|
|
final double? payoutRatio;
|
|
final String? exDividendDate;
|
|
final String? nextEarningsDate;
|
|
final double? percentHeldByInstitutions;
|
|
final double? percentHeldByInsiders;
|
|
final double? shortRatio;
|
|
final double? shortPercentOfFloat;
|
|
|
|
final String? consensusRating;
|
|
final double? priceTargetLow;
|
|
final double? priceTargetHigh;
|
|
final double? priceTargetMedian;
|
|
final double? priceTargetMean;
|
|
|
|
final List<CompanyExecutiveModel> executives;
|
|
final List<FinancialStatementModel> financialStatements;
|
|
final List<ForwardEstimateModel> estimates;
|
|
final List<TickerModel> availableTickers;
|
|
|
|
const FundamentalDataModel({
|
|
required this.isin,
|
|
required this.primaryTicker,
|
|
required this.ticker,
|
|
required this.companyName,
|
|
this.exchange,
|
|
this.tradingCurrency,
|
|
this.businessSummary,
|
|
this.sector,
|
|
this.industry,
|
|
this.country,
|
|
this.employees,
|
|
required this.currentPrice,
|
|
required this.dayChangeAbsolute,
|
|
required this.dayChangePercent,
|
|
this.fiftyTwoWeekHigh,
|
|
this.fiftyTwoWeekLow,
|
|
this.marketCapitalization,
|
|
this.enterpriseValue,
|
|
this.peRatioTrailing,
|
|
this.peRatioForward,
|
|
this.pegRatio,
|
|
this.pbRatio,
|
|
this.psRatio,
|
|
this.evToEbitda,
|
|
this.evToRevenue,
|
|
this.totalRevenue,
|
|
this.revenueGrowthYoY,
|
|
this.grossProfit,
|
|
this.ebitda,
|
|
this.dilutedEps,
|
|
this.totalCash,
|
|
this.totalDebt,
|
|
this.operatingCashFlow,
|
|
this.freeCashFlow,
|
|
this.grossMargin,
|
|
this.operatingMargin,
|
|
this.netProfitMargin,
|
|
this.returnOnEquity,
|
|
this.returnOnAssets,
|
|
this.returnOnInvestedCapital,
|
|
this.debtToEquity,
|
|
this.currentRatio,
|
|
this.quickRatio,
|
|
this.interestCoverage,
|
|
this.dividendYield,
|
|
this.payoutRatio,
|
|
this.exDividendDate,
|
|
this.nextEarningsDate,
|
|
this.percentHeldByInstitutions,
|
|
this.percentHeldByInsiders,
|
|
this.shortRatio,
|
|
this.shortPercentOfFloat,
|
|
this.consensusRating,
|
|
this.priceTargetLow,
|
|
this.priceTargetHigh,
|
|
this.priceTargetMedian,
|
|
this.priceTargetMean,
|
|
required this.executives,
|
|
required this.financialStatements,
|
|
required this.estimates,
|
|
this.availableTickers = const [],
|
|
});
|
|
|
|
factory FundamentalDataModel.fromJson(Map<String, dynamic> json) {
|
|
double? parseNullableDouble(dynamic val) {
|
|
if (val == null) return null;
|
|
if (val is num) return val.toDouble();
|
|
return double.tryParse(val.toString());
|
|
}
|
|
|
|
final assetMap = json['asset'] is Map<String, dynamic> ? json['asset'] as Map<String, dynamic> : null;
|
|
final fundMap = json['fundamentals'] is Map<String, dynamic> ? json['fundamentals'] as Map<String, dynamic> : null;
|
|
|
|
String extractTickerStr(dynamic val) {
|
|
if (val == null) return '';
|
|
if (val is Map<String, dynamic>) {
|
|
return val['ticker']?.toString() ?? '';
|
|
}
|
|
return val.toString();
|
|
}
|
|
|
|
String? extractExchangeStr(dynamic val) {
|
|
if (val == null) return null;
|
|
if (val is Map<String, dynamic>) {
|
|
return val['exchange']?.toString();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
final isinVal = assetMap?['isin']?.toString() ?? json['isin']?.toString() ?? '';
|
|
final primaryTickerVal = extractTickerStr(assetMap?['primaryTicker'] ?? json['primaryTicker']);
|
|
final tickerVal = extractTickerStr(fundMap?['ticker'] ?? json['ticker']).isNotEmpty
|
|
? extractTickerStr(fundMap?['ticker'] ?? json['ticker'])
|
|
: primaryTickerVal;
|
|
final companyNameVal = assetMap?['name']?.toString() ?? json['companyName']?.toString() ?? tickerVal;
|
|
final businessSummaryVal = assetMap?['description']?.toString() ?? json['businessSummary']?.toString();
|
|
|
|
final exchangeVal = extractExchangeStr(fundMap?['ticker']) ??
|
|
extractExchangeStr(assetMap?['primaryTicker']) ??
|
|
json['exchange']?.toString();
|
|
|
|
final rawTickers = assetMap?['availableTickers'] ?? json['availableTickers'];
|
|
List<TickerModel> availableTickersList = [];
|
|
if (rawTickers is List) {
|
|
availableTickersList = rawTickers
|
|
.whereType<Map<String, dynamic>>()
|
|
.map((t) => TickerModel.fromJson(t))
|
|
.toList();
|
|
}
|
|
|
|
final totalRev = parseNullableDouble(fundMap?['totalRevenue'] ?? json['totalRevenue']);
|
|
final grossProf = parseNullableDouble(fundMap?['grossProfit'] ?? json['grossProfit']);
|
|
double? grossMarginVal = parseNullableDouble(fundMap?['grossMargin'] ?? json['grossMargin']);
|
|
if (grossMarginVal == null && grossProf != null) {
|
|
if (grossProf <= 1.0 && grossProf >= 0.0) {
|
|
grossMarginVal = grossProf;
|
|
} else if (totalRev != null && totalRev > 0) {
|
|
grossMarginVal = grossProf / totalRev;
|
|
}
|
|
}
|
|
|
|
final evVal = parseNullableDouble(fundMap?['enterpriseValue'] ?? json['enterpriseValue']);
|
|
double? evToRevVal = parseNullableDouble(fundMap?['evToRevenue'] ?? fundMap?['enterpriseValueToRevenue'] ?? json['evToRevenue']);
|
|
if (evToRevVal == null && evVal != null && totalRev != null && totalRev > 0) {
|
|
evToRevVal = evVal / totalRev;
|
|
}
|
|
|
|
return FundamentalDataModel(
|
|
isin: isinVal,
|
|
primaryTicker: primaryTickerVal,
|
|
ticker: tickerVal,
|
|
companyName: companyNameVal,
|
|
exchange: exchangeVal,
|
|
tradingCurrency: fundMap?['currency']?.toString() ?? json['tradingCurrency']?.toString(),
|
|
businessSummary: businessSummaryVal,
|
|
sector: assetMap?['sector']?.toString() ?? json['sector']?.toString(),
|
|
industry: assetMap?['industry']?.toString() ?? json['industry']?.toString(),
|
|
country: assetMap?['country']?.toString() ?? json['country']?.toString(),
|
|
employees: (assetMap?['employees'] ?? json['employees']) is int
|
|
? (assetMap?['employees'] ?? json['employees']) as int
|
|
: int.tryParse((assetMap?['employees'] ?? json['employees'])?.toString() ?? ''),
|
|
currentPrice: parseNullableDouble(fundMap?['currentPrice'] ?? json['currentPrice']) ?? 0.0,
|
|
dayChangeAbsolute: parseNullableDouble(fundMap?['dayChangeAbsolute'] ?? json['dayChangeAbsolute']) ?? 0.0,
|
|
dayChangePercent: parseNullableDouble(fundMap?['dayChangePercent'] ?? json['dayChangePercent']) ?? 0.0,
|
|
fiftyTwoWeekHigh: parseNullableDouble(fundMap?['fiftyTwoWeekHigh'] ?? json['fiftyTwoWeekHigh']),
|
|
fiftyTwoWeekLow: parseNullableDouble(fundMap?['fiftyTwoWeekLow'] ?? json['fiftyTwoWeekLow']),
|
|
marketCapitalization: parseNullableDouble(fundMap?['marketCap'] ?? fundMap?['marketCapitalization'] ?? json['marketCapitalization']),
|
|
enterpriseValue: evVal,
|
|
peRatioTrailing: parseNullableDouble(fundMap?['trailingPE'] ?? fundMap?['peRatioTrailing'] ?? json['peRatioTrailing']),
|
|
peRatioForward: parseNullableDouble(fundMap?['forwardPE'] ?? fundMap?['peRatioForward'] ?? json['peRatioForward']),
|
|
pegRatio: parseNullableDouble(fundMap?['pegRatio'] ?? json['pegRatio']),
|
|
pbRatio: parseNullableDouble(fundMap?['priceToBook'] ?? fundMap?['pbRatio'] ?? json['pbRatio']),
|
|
psRatio: parseNullableDouble(fundMap?['priceToSalesTrailing12Months'] ?? fundMap?['psRatio'] ?? json['psRatio']),
|
|
evToEbitda: parseNullableDouble(fundMap?['enterpriseToEbitda'] ?? fundMap?['evToEbitda'] ?? json['evToEbitda']),
|
|
evToRevenue: evToRevVal,
|
|
totalRevenue: totalRev,
|
|
revenueGrowthYoY: parseNullableDouble(fundMap?['revenueGrowth'] ?? fundMap?['revenueGrowthYoY'] ?? json['revenueGrowthYoY']),
|
|
grossProfit: grossProf,
|
|
ebitda: parseNullableDouble(fundMap?['ebitda'] ?? json['ebitda']),
|
|
dilutedEps: parseNullableDouble(fundMap?['trailingEps'] ?? fundMap?['dilutedEps'] ?? json['dilutedEps']),
|
|
totalCash: parseNullableDouble(fundMap?['totalCash'] ?? json['totalCash']),
|
|
totalDebt: parseNullableDouble(fundMap?['totalDebt'] ?? json['totalDebt']),
|
|
operatingCashFlow: parseNullableDouble(fundMap?['operatingCashflow'] ?? fundMap?['operatingCashFlow'] ?? json['operatingCashFlow']),
|
|
freeCashFlow: parseNullableDouble(fundMap?['freeCashflow'] ?? fundMap?['freeCashFlow'] ?? json['freeCashFlow']),
|
|
grossMargin: grossMarginVal,
|
|
operatingMargin: parseNullableDouble(fundMap?['operatingMargins'] ?? fundMap?['operatingMargin'] ?? json['operatingMargin']),
|
|
netProfitMargin: parseNullableDouble(fundMap?['profitMargins'] ?? fundMap?['netProfitMargin'] ?? json['netProfitMargin']),
|
|
returnOnEquity: parseNullableDouble(fundMap?['returnOnEquity'] ?? json['returnOnEquity']),
|
|
returnOnAssets: parseNullableDouble(fundMap?['returnOnAssets'] ?? json['returnOnAssets']),
|
|
returnOnInvestedCapital: parseNullableDouble(fundMap?['returnOnInvestedCapital'] ?? json['returnOnInvestedCapital']),
|
|
debtToEquity: parseNullableDouble(fundMap?['debtToEquity'] ?? json['debtToEquity']),
|
|
currentRatio: parseNullableDouble(fundMap?['currentRatio'] ?? json['currentRatio']),
|
|
quickRatio: parseNullableDouble(fundMap?['quickRatio'] ?? json['quickRatio']),
|
|
interestCoverage: parseNullableDouble(fundMap?['interestCoverage'] ?? json['interestCoverage']),
|
|
dividendYield: parseNullableDouble(fundMap?['dividendYield'] ?? json['dividendYield']),
|
|
payoutRatio: parseNullableDouble(fundMap?['payoutRatio'] ?? json['payoutRatio']),
|
|
exDividendDate: fundMap?['exDividendDate']?.toString() ?? json['exDividendDate']?.toString(),
|
|
nextEarningsDate: fundMap?['nextEarningsDate']?.toString() ?? json['nextEarningsDate']?.toString(),
|
|
percentHeldByInstitutions: parseNullableDouble(fundMap?['percentHeldByInstitutions'] ?? json['percentHeldByInstitutions']),
|
|
percentHeldByInsiders: parseNullableDouble(fundMap?['percentHeldByInsiders'] ?? json['percentHeldByInsiders']),
|
|
shortRatio: parseNullableDouble(fundMap?['shortRatio'] ?? json['shortRatio']),
|
|
shortPercentOfFloat: parseNullableDouble(fundMap?['shortPercentOfFloat'] ?? json['shortPercentOfFloat']),
|
|
consensusRating: fundMap?['consensusRating']?.toString() ?? json['consensusRating']?.toString(),
|
|
priceTargetLow: parseNullableDouble(fundMap?['priceTargetLow'] ?? json['priceTargetLow']),
|
|
priceTargetHigh: parseNullableDouble(fundMap?['priceTargetHigh'] ?? json['priceTargetHigh']),
|
|
priceTargetMedian: parseNullableDouble(fundMap?['priceTargetMedian'] ?? json['priceTargetMedian']),
|
|
priceTargetMean: parseNullableDouble(fundMap?['priceTargetMean'] ?? json['priceTargetMean']),
|
|
executives: (json['executives'] as List?)
|
|
?.whereType<Map<String, dynamic>>()
|
|
.map((e) => CompanyExecutiveModel.fromJson(e))
|
|
.toList() ??
|
|
[],
|
|
financialStatements: (json['financialStatements'] as List?)
|
|
?.whereType<Map<String, dynamic>>()
|
|
.map((e) => FinancialStatementModel.fromJson(e))
|
|
.toList() ??
|
|
[],
|
|
estimates: (json['estimates'] as List?)
|
|
?.whereType<Map<String, dynamic>>()
|
|
.map((e) => ForwardEstimateModel.fromJson(e))
|
|
.toList() ??
|
|
[],
|
|
availableTickers: availableTickersList,
|
|
);
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
isin, primaryTicker, ticker, companyName, exchange, tradingCurrency,
|
|
businessSummary, sector, industry, country, employees, currentPrice,
|
|
dayChangeAbsolute, dayChangePercent, fiftyTwoWeekHigh, fiftyTwoWeekLow,
|
|
marketCapitalization, enterpriseValue, peRatioTrailing, peRatioForward,
|
|
pegRatio, pbRatio, psRatio, evToEbitda, evToRevenue, grossMargin,
|
|
operatingMargin, netProfitMargin, returnOnEquity, returnOnAssets,
|
|
returnOnInvestedCapital, debtToEquity, currentRatio, quickRatio,
|
|
dividendYield, payoutRatio, exDividendDate, nextEarningsDate,
|
|
percentHeldByInstitutions, percentHeldByInsiders, shortRatio,
|
|
shortPercentOfFloat, consensusRating, priceTargetLow, priceTargetHigh,
|
|
priceTargetMedian, priceTargetMean, executives, financialStatements,
|
|
estimates, availableTickers,
|
|
];
|
|
}
|