723 lines
26 KiB
Dart
723 lines
26 KiB
Dart
import 'package:equatable/equatable.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,
|
|
required this.fiftyTwoWeekHigh,
|
|
required this.fiftyTwoWeekLow,
|
|
required this.marketCapitalization,
|
|
required 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 parseDouble(dynamic val) {
|
|
if (val == null) return 0.0;
|
|
if (val is num) return val.toDouble();
|
|
return double.tryParse(val.toString()) ?? 0.0;
|
|
}
|
|
|
|
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() ?? json['name']?.toString() ?? tickerVal;
|
|
final businessSummaryVal = assetMap?['description']?.toString() ?? json['businessSummary']?.toString() ?? json['description']?.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.map((t) {
|
|
if (t is Map<String, dynamic>) {
|
|
return TickerModel.fromJson(t);
|
|
} else {
|
|
return TickerModel(ticker: t.toString());
|
|
}
|
|
}).toList();
|
|
}
|
|
|
|
// Revenue & Margins Derivation
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Enterprise Value to Revenue
|
|
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;
|
|
}
|
|
|
|
// Event Dates (Ex-Dividend & Next Earnings)
|
|
String? exDividendDateVal = json['exDividendDate']?.toString() ?? fundMap?['exDividendDate']?.toString();
|
|
String? nextEarningsDateVal = json['nextEarningsDate']?.toString() ?? fundMap?['nextEarningsDate']?.toString();
|
|
|
|
final rawEvents = json['events'];
|
|
if (rawEvents is List && rawEvents.isNotEmpty) {
|
|
final now = DateTime.now();
|
|
final parsedEvents = <Map<String, dynamic>>[];
|
|
for (final ev in rawEvents) {
|
|
if (ev is Map<String, dynamic>) {
|
|
final dtStr = ev['date']?.toString();
|
|
final dt = dtStr != null ? DateTime.tryParse(dtStr) : null;
|
|
if (dt != null) {
|
|
parsedEvents.add({
|
|
'type': ev['type']?.toString().toUpperCase() ?? '',
|
|
'date': dt,
|
|
'dateStr': dtStr,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (exDividendDateVal == null) {
|
|
final dividendEvents = parsedEvents.where((e) => e['type'] == 'DIVIDEND').toList()
|
|
..sort((a, b) => (a['date'] as DateTime).compareTo(b['date'] as DateTime));
|
|
final futureDividends = dividendEvents.where((e) => (e['date'] as DateTime).isAfter(now)).toList();
|
|
if (futureDividends.isNotEmpty) {
|
|
exDividendDateVal = futureDividends.first['dateStr'] as String;
|
|
} else if (dividendEvents.isNotEmpty) {
|
|
exDividendDateVal = dividendEvents.last['dateStr'] as String;
|
|
}
|
|
}
|
|
|
|
if (nextEarningsDateVal == null) {
|
|
final earningsEvents = parsedEvents.where((e) => e['type'] == 'EARNINGS_RELEASE' || e['type'] == 'EARNINGS_CALL').toList()
|
|
..sort((a, b) => (a['date'] as DateTime).compareTo(b['date'] as DateTime));
|
|
final futureEarnings = earningsEvents.where((e) => (e['date'] as DateTime).isAfter(now)).toList();
|
|
if (futureEarnings.isNotEmpty) {
|
|
nextEarningsDateVal = futureEarnings.first['dateStr'] as String;
|
|
} else if (earningsEvents.isNotEmpty) {
|
|
nextEarningsDateVal = earningsEvents.last['dateStr'] as String;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FundamentalDataModel(
|
|
isin: isinVal,
|
|
primaryTicker: primaryTickerVal,
|
|
ticker: tickerVal,
|
|
companyName: companyNameVal,
|
|
exchange: exchangeVal,
|
|
tradingCurrency: json['tradingCurrency']?.toString(),
|
|
businessSummary: businessSummaryVal,
|
|
sector: json['sector']?.toString(),
|
|
industry: json['industry']?.toString(),
|
|
country: json['country']?.toString(),
|
|
employees: json['employees'] != null ? int.tryParse(json['employees'].toString()) : null,
|
|
currentPrice: parseDouble(json['currentPrice']),
|
|
dayChangeAbsolute: parseDouble(json['dayChangeAbsolute']),
|
|
dayChangePercent: parseDouble(json['dayChangePercent']),
|
|
fiftyTwoWeekHigh: parseDouble(fundMap?['fiftyTwoWeekHigh'] ?? json['fiftyTwoWeekHigh']),
|
|
fiftyTwoWeekLow: parseDouble(fundMap?['fiftyTwoWeekLow'] ?? json['fiftyTwoWeekLow']),
|
|
marketCapitalization: parseDouble(fundMap?['marketCap'] ?? json['marketCapitalization'] ?? json['marketCap']),
|
|
enterpriseValue: parseDouble(fundMap?['enterpriseValue'] ?? json['enterpriseValue']),
|
|
peRatioTrailing: parseNullableDouble(fundMap?['trailingPe'] ?? json['peRatioTrailing'] ?? json['peRatio']),
|
|
peRatioForward: parseNullableDouble(fundMap?['forwardPe'] ?? json['peRatioForward']),
|
|
pegRatio: parseNullableDouble(fundMap?['pegRatio'] ?? json['pegRatio']),
|
|
pbRatio: parseNullableDouble(fundMap?['priceToBook'] ?? json['pbRatio']),
|
|
psRatio: parseNullableDouble(fundMap?['priceToSales'] ?? json['psRatio']),
|
|
evToEbitda: parseNullableDouble(fundMap?['evToEbitda'] ?? json['evToEbitda']),
|
|
evToRevenue: evToRevVal,
|
|
totalRevenue: totalRev,
|
|
revenueGrowthYoY: parseNullableDouble(fundMap?['revenueGrowthYoY'] ?? json['revenueGrowthYoY']),
|
|
grossProfit: grossProf,
|
|
ebitda: parseNullableDouble(fundMap?['ebitda'] ?? json['ebitda']),
|
|
dilutedEps: parseNullableDouble(fundMap?['dilutedEps'] ?? json['dilutedEps']),
|
|
totalCash: parseNullableDouble(fundMap?['totalCash'] ?? json['totalCash']),
|
|
totalDebt: parseNullableDouble(fundMap?['totalDebt'] ?? json['totalDebt']),
|
|
operatingCashFlow: parseNullableDouble(fundMap?['operatingCashFlow'] ?? json['operatingCashFlow']),
|
|
freeCashFlow: parseNullableDouble(fundMap?['freeCashFlow'] ?? json['freeCashFlow']),
|
|
grossMargin: grossMarginVal,
|
|
operatingMargin: parseNullableDouble(fundMap?['operatingMargin'] ?? fundMap?['operatingIncome'] ?? json['operatingMargin']),
|
|
netProfitMargin: parseNullableDouble(fundMap?['netProfitMargin'] ?? fundMap?['netIncome'] ?? 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?['forwardDividendYield'] ?? json['dividendYield']),
|
|
payoutRatio: parseNullableDouble(fundMap?['payoutRatio'] ?? json['payoutRatio']),
|
|
exDividendDate: exDividendDateVal,
|
|
nextEarningsDate: nextEarningsDateVal,
|
|
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'] ?? 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?)
|
|
?.map((e) => CompanyExecutiveModel.fromJson(e is Map<String, dynamic> ? e : {}))
|
|
.toList() ??
|
|
[],
|
|
financialStatements: (json['financialStatements'] as List?)
|
|
?.map((e) => FinancialStatementModel.fromJson(e is Map<String, dynamic> ? e : {}))
|
|
.toList() ??
|
|
[],
|
|
estimates: (json['estimates'] as List?)
|
|
?.map((e) => ForwardEstimateModel.fromJson(e is Map<String, dynamic> ? e : {}))
|
|
.toList() ??
|
|
[],
|
|
availableTickers: availableTickersList,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'isin': isin,
|
|
'primaryTicker': primaryTicker,
|
|
'ticker': ticker,
|
|
'companyName': companyName,
|
|
'exchange': exchange,
|
|
'tradingCurrency': tradingCurrency,
|
|
'businessSummary': businessSummary,
|
|
'sector': sector,
|
|
'industry': industry,
|
|
'country': country,
|
|
'employees': employees,
|
|
'currentPrice': currentPrice,
|
|
'dayChangeAbsolute': dayChangeAbsolute,
|
|
'dayChangePercent': dayChangePercent,
|
|
'fiftyTwoWeekHigh': fiftyTwoWeekHigh,
|
|
'fiftyTwoWeekLow': fiftyTwoWeekLow,
|
|
'marketCapitalization': marketCapitalization,
|
|
'enterpriseValue': enterpriseValue,
|
|
'peRatioTrailing': peRatioTrailing,
|
|
'peRatioForward': peRatioForward,
|
|
'pegRatio': pegRatio,
|
|
'pbRatio': pbRatio,
|
|
'psRatio': psRatio,
|
|
'evToEbitda': evToEbitda,
|
|
'evToRevenue': evToRevenue,
|
|
'grossMargin': grossMargin,
|
|
'operatingMargin': operatingMargin,
|
|
'netProfitMargin': netProfitMargin,
|
|
'returnOnEquity': returnOnEquity,
|
|
'returnOnAssets': returnOnAssets,
|
|
'returnOnInvestedCapital': returnOnInvestedCapital,
|
|
'debtToEquity': debtToEquity,
|
|
'currentRatio': currentRatio,
|
|
'quickRatio': quickRatio,
|
|
'dividendYield': dividendYield,
|
|
'payoutRatio': payoutRatio,
|
|
'exDividendDate': exDividendDate,
|
|
'nextEarningsDate': nextEarningsDate,
|
|
'percentHeldByInstitutions': percentHeldByInstitutions,
|
|
'percentHeldByInsiders': percentHeldByInsiders,
|
|
'shortRatio': shortRatio,
|
|
'shortPercentOfFloat': shortPercentOfFloat,
|
|
'consensusRating': consensusRating,
|
|
'priceTargetLow': priceTargetLow,
|
|
'priceTargetHigh': priceTargetHigh,
|
|
'priceTargetMedian': priceTargetMedian,
|
|
'priceTargetMean': priceTargetMean,
|
|
'executives': executives.map((e) => e.toJson()).toList(),
|
|
'financialStatements': financialStatements.map((e) => e.toJson()).toList(),
|
|
'estimates': estimates.map((e) => e.toJson()).toList(),
|
|
'availableTickers': availableTickers.map((e) => e.toJson()).toList(),
|
|
};
|
|
}
|
|
|
|
@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,
|
|
];
|
|
}
|
|
|
|
class CompanyExecutiveModel extends Equatable {
|
|
final String name;
|
|
final String title;
|
|
final int? age;
|
|
final double? compensation;
|
|
|
|
const CompanyExecutiveModel({
|
|
required this.name,
|
|
required this.title,
|
|
this.age,
|
|
this.compensation,
|
|
});
|
|
|
|
factory CompanyExecutiveModel.fromJson(Map<String, dynamic> json) {
|
|
double? compVal;
|
|
if (json['compensation'] != null) {
|
|
compVal = double.tryParse(json['compensation'].toString());
|
|
} else if (json['payment'] != null) {
|
|
final pStr = json['payment'].toString().trim().toUpperCase().replaceAll('\$', '').replaceAll('€', '').replaceAll('£', '').replaceAll(',', '').replaceAll(' ', '');
|
|
if (pStr.endsWith('M')) {
|
|
final numPart = double.tryParse(pStr.substring(0, pStr.length - 1));
|
|
if (numPart != null) compVal = numPart * 1e6;
|
|
} else if (pStr.endsWith('K')) {
|
|
final numPart = double.tryParse(pStr.substring(0, pStr.length - 1));
|
|
if (numPart != null) compVal = numPart * 1e3;
|
|
} else if (pStr.endsWith('B')) {
|
|
final numPart = double.tryParse(pStr.substring(0, pStr.length - 1));
|
|
if (numPart != null) compVal = numPart * 1e9;
|
|
} else {
|
|
compVal = double.tryParse(pStr);
|
|
}
|
|
}
|
|
|
|
return CompanyExecutiveModel(
|
|
name: json['name']?.toString() ?? '',
|
|
title: json['title']?.toString() ?? '',
|
|
age: json['age'] != null ? int.tryParse(json['age'].toString()) : null,
|
|
compensation: compVal,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'name': name,
|
|
'title': title,
|
|
'age': age,
|
|
'compensation': compensation,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [name, title, age, compensation];
|
|
}
|
|
|
|
class FinancialStatementModel extends Equatable {
|
|
final String periodType;
|
|
final String endDate;
|
|
|
|
// Income Statement
|
|
final double? totalRevenue;
|
|
final double? costOfRevenue;
|
|
final double? grossProfit;
|
|
final double? operatingExpenses;
|
|
final double? operatingIncome;
|
|
final double? ebitda;
|
|
final double? netIncome;
|
|
final double? epsBasic;
|
|
final double? epsDiluted;
|
|
|
|
// Balance Sheet
|
|
final double? cashAndCashEquivalents;
|
|
final double? accountsReceivable;
|
|
final double? inventory;
|
|
final double? totalCurrentAssets;
|
|
final double? totalNonCurrentAssets;
|
|
final double? currentLiabilities;
|
|
final double? longTermDebt;
|
|
final double? totalLiabilities;
|
|
final double? totalStockholdersEquity;
|
|
|
|
// Cash Flow
|
|
final double? operatingCashFlow;
|
|
final double? investingCashFlow;
|
|
final double? capitalExpenditures;
|
|
final double? financingCashFlow;
|
|
final double? freeCashFlow;
|
|
|
|
const FinancialStatementModel({
|
|
required this.periodType,
|
|
required this.endDate,
|
|
this.totalRevenue,
|
|
this.costOfRevenue,
|
|
this.grossProfit,
|
|
this.operatingExpenses,
|
|
this.operatingIncome,
|
|
this.ebitda,
|
|
this.netIncome,
|
|
this.epsBasic,
|
|
this.epsDiluted,
|
|
this.cashAndCashEquivalents,
|
|
this.accountsReceivable,
|
|
this.inventory,
|
|
this.totalCurrentAssets,
|
|
this.totalNonCurrentAssets,
|
|
this.currentLiabilities,
|
|
this.longTermDebt,
|
|
this.totalLiabilities,
|
|
this.totalStockholdersEquity,
|
|
this.operatingCashFlow,
|
|
this.investingCashFlow,
|
|
this.capitalExpenditures,
|
|
this.financingCashFlow,
|
|
this.freeCashFlow,
|
|
});
|
|
|
|
factory FinancialStatementModel.fromJson(Map<String, dynamic> json) {
|
|
double? parseD(dynamic val) {
|
|
if (val == null) return null;
|
|
if (val is num) return val.toDouble();
|
|
return double.tryParse(val.toString());
|
|
}
|
|
|
|
return FinancialStatementModel(
|
|
periodType: json['periodType']?.toString() ?? '',
|
|
endDate: json['endDate']?.toString() ?? '',
|
|
totalRevenue: parseD(json['totalRevenue']),
|
|
costOfRevenue: parseD(json['costOfRevenue']),
|
|
grossProfit: parseD(json['grossProfit']),
|
|
operatingExpenses: parseD(json['operatingExpenses']),
|
|
operatingIncome: parseD(json['operatingIncome']),
|
|
ebitda: parseD(json['ebitda']),
|
|
netIncome: parseD(json['netIncome']),
|
|
epsBasic: parseD(json['epsBasic']),
|
|
epsDiluted: parseD(json['epsDiluted']),
|
|
cashAndCashEquivalents: parseD(json['cashAndCashEquivalents']),
|
|
accountsReceivable: parseD(json['accountsReceivable']),
|
|
inventory: parseD(json['inventory']),
|
|
totalCurrentAssets: parseD(json['totalCurrentAssets']),
|
|
totalNonCurrentAssets: parseD(json['totalNonCurrentAssets']),
|
|
currentLiabilities: parseD(json['currentLiabilities']),
|
|
longTermDebt: parseD(json['longTermDebt']),
|
|
totalLiabilities: parseD(json['totalLiabilities']),
|
|
totalStockholdersEquity: parseD(json['totalStockholdersEquity']),
|
|
operatingCashFlow: parseD(json['operatingCashFlow']),
|
|
investingCashFlow: parseD(json['investingCashFlow']),
|
|
capitalExpenditures: parseD(json['capitalExpenditures']),
|
|
financingCashFlow: parseD(json['financingCashFlow']),
|
|
freeCashFlow: parseD(json['freeCashFlow']),
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'periodType': periodType,
|
|
'endDate': endDate,
|
|
'totalRevenue': totalRevenue,
|
|
'costOfRevenue': costOfRevenue,
|
|
'grossProfit': grossProfit,
|
|
'operatingExpenses': operatingExpenses,
|
|
'operatingIncome': operatingIncome,
|
|
'ebitda': ebitda,
|
|
'netIncome': netIncome,
|
|
'epsBasic': epsBasic,
|
|
'epsDiluted': epsDiluted,
|
|
'cashAndCashEquivalents': cashAndCashEquivalents,
|
|
'accountsReceivable': accountsReceivable,
|
|
'inventory': inventory,
|
|
'totalCurrentAssets': totalCurrentAssets,
|
|
'totalNonCurrentAssets': totalNonCurrentAssets,
|
|
'currentLiabilities': currentLiabilities,
|
|
'longTermDebt': longTermDebt,
|
|
'totalLiabilities': totalLiabilities,
|
|
'totalStockholdersEquity': totalStockholdersEquity,
|
|
'operatingCashFlow': operatingCashFlow,
|
|
'investingCashFlow': investingCashFlow,
|
|
'capitalExpenditures': capitalExpenditures,
|
|
'financingCashFlow': financingCashFlow,
|
|
'freeCashFlow': freeCashFlow,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
periodType,
|
|
endDate,
|
|
totalRevenue,
|
|
costOfRevenue,
|
|
grossProfit,
|
|
operatingExpenses,
|
|
operatingIncome,
|
|
ebitda,
|
|
netIncome,
|
|
epsBasic,
|
|
epsDiluted,
|
|
cashAndCashEquivalents,
|
|
accountsReceivable,
|
|
inventory,
|
|
totalCurrentAssets,
|
|
totalNonCurrentAssets,
|
|
currentLiabilities,
|
|
longTermDebt,
|
|
totalLiabilities,
|
|
totalStockholdersEquity,
|
|
operatingCashFlow,
|
|
investingCashFlow,
|
|
capitalExpenditures,
|
|
financingCashFlow,
|
|
freeCashFlow,
|
|
];
|
|
}
|
|
|
|
class ForwardEstimateModel extends Equatable {
|
|
final String period;
|
|
final double? expectedRevenue;
|
|
final double? expectedEps;
|
|
final double? expectedGrowthRate;
|
|
|
|
const ForwardEstimateModel({
|
|
required this.period,
|
|
this.expectedRevenue,
|
|
this.expectedEps,
|
|
this.expectedGrowthRate,
|
|
});
|
|
|
|
factory ForwardEstimateModel.fromJson(Map<String, dynamic> json) {
|
|
return ForwardEstimateModel(
|
|
period: json['period']?.toString() ?? '',
|
|
expectedRevenue: json['expectedRevenue'] != null ? double.tryParse(json['expectedRevenue'].toString()) : null,
|
|
expectedEps: json['expectedEps'] != null ? double.tryParse(json['expectedEps'].toString()) : null,
|
|
expectedGrowthRate: json['expectedGrowthRate'] != null ? double.tryParse(json['expectedGrowthRate'].toString()) : null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'period': period,
|
|
'expectedRevenue': expectedRevenue,
|
|
'expectedEps': expectedEps,
|
|
'expectedGrowthRate': expectedGrowthRate,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [period, expectedRevenue, expectedEps, expectedGrowthRate];
|
|
}
|
|
|
|
class TickerModel extends Equatable {
|
|
final String ticker;
|
|
final String? exchange;
|
|
final String? tradingCurrency;
|
|
final double currentPrice;
|
|
|
|
const TickerModel({
|
|
required this.ticker,
|
|
this.exchange,
|
|
this.tradingCurrency,
|
|
this.currentPrice = 0.0,
|
|
});
|
|
|
|
factory TickerModel.fromJson(Map<String, dynamic> json) {
|
|
return TickerModel(
|
|
ticker: json['ticker']?.toString() ?? '',
|
|
exchange: json['exchange']?.toString(),
|
|
tradingCurrency: json['tradingCurrency']?.toString(),
|
|
currentPrice: json['currentPrice'] != null ? double.tryParse(json['currentPrice'].toString()) ?? 0.0 : 0.0,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'ticker': ticker,
|
|
'exchange': exchange,
|
|
'tradingCurrency': tradingCurrency,
|
|
'currentPrice': currentPrice,
|
|
};
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [ticker, exchange, tradingCurrency, currentPrice];
|
|
}
|