Files
Finlytic/FinlyticApp/lib/features/asset_detail/models/fundamental_data_model.dart
T

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];
}