Files

306 lines
10 KiB
Dart

import 'package:equatable/equatable.dart';
class CandleModel extends Equatable {
final DateTime timestamp;
final double open;
final double high;
final double low;
final double close;
final double volume;
const CandleModel({
required this.timestamp,
required this.open,
required this.high,
required this.low,
required this.close,
required this.volume,
});
factory CandleModel.fromJson(Map<String, dynamic> json) {
return CandleModel(
timestamp: DateTime.tryParse(json['timestamp']?.toString() ?? '') ?? DateTime.now(),
open: (json['open'] as num?)?.toDouble() ?? 0.0,
high: (json['high'] as num?)?.toDouble() ?? 0.0,
low: (json['low'] as num?)?.toDouble() ?? 0.0,
close: (json['close'] as num?)?.toDouble() ?? 0.0,
volume: (json['volume'] as num?)?.toDouble() ?? 0.0,
);
}
@override
List<Object?> get props => [timestamp, open, high, low, close, volume];
}
class IndicatorModel extends Equatable {
final DateTime timestamp;
final double? ema20;
final double? sma50;
final double? sma200;
final double? rsi14;
final double? macdLine;
final double? macdSignal;
final double? macdHistogram;
final double? atr14;
final double? vwap;
final double? supertrendUpper;
final double? supertrendLower;
final String? supertrendDirection;
final double? recommendedStopLoss;
const IndicatorModel({
required this.timestamp,
this.ema20,
this.sma50,
this.sma200,
this.rsi14,
this.macdLine,
this.macdSignal,
this.macdHistogram,
this.atr14,
this.vwap,
this.supertrendUpper,
this.supertrendLower,
this.supertrendDirection,
this.recommendedStopLoss,
});
factory IndicatorModel.fromJson(Map<String, dynamic> json) {
return IndicatorModel(
timestamp: DateTime.tryParse(json['timestamp']?.toString() ?? '') ?? DateTime.now(),
ema20: (json['ema20'] as num?)?.toDouble(),
sma50: (json['sma50'] as num?)?.toDouble(),
sma200: (json['sma200'] as num?)?.toDouble(),
rsi14: (json['rsi14'] as num?)?.toDouble(),
macdLine: (json['macdLine'] as num?)?.toDouble(),
macdSignal: (json['macdSignal'] as num?)?.toDouble(),
macdHistogram: (json['macdHistogram'] as num?)?.toDouble(),
atr14: (json['atr14'] as num?)?.toDouble(),
vwap: (json['vwap'] as num?)?.toDouble(),
supertrendUpper: (json['supertrendUpper'] as num?)?.toDouble(),
supertrendLower: (json['supertrendLower'] as num?)?.toDouble(),
supertrendDirection: json['supertrendDirection']?.toString(),
recommendedStopLoss: (json['recommendedStopLoss'] as num?)?.toDouble(),
);
}
@override
List<Object?> get props => [
timestamp, ema20, sma50, sma200, rsi14, macdLine, macdSignal,
macdHistogram, atr14, vwap, supertrendUpper, supertrendLower,
supertrendDirection, recommendedStopLoss
];
}
class StrategySignalModel extends Equatable {
final String title;
final DateTime date;
final double price;
final String type; // BUY or SELL
const StrategySignalModel({
required this.title,
required this.date,
required this.price,
required this.type,
});
factory StrategySignalModel.fromJson(Map<String, dynamic> json) {
final rawDir = (json['direction'] ?? json['signalType'] ?? json['type'])?.toString().toUpperCase() ?? 'BUY';
final sigDir = (rawDir == 'BUY' || rawDir == 'SELL') ? rawDir : 'BUY';
final sigTitle = (json['title'] ?? json['type'] ?? json['description'])?.toString() ?? 'Signal';
final dateStr = (json['timestamp'] ?? json['date'] ?? json['time'])?.toString();
return StrategySignalModel(
title: sigTitle,
date: dateStr != null ? (DateTime.tryParse(dateStr) ?? DateTime.now()) : DateTime.now(),
price: (json['price'] as num?)?.toDouble() ?? 0.0,
type: sigDir,
);
}
@override
List<Object?> get props => [title, date, price, type];
}
class PatternPoint extends Equatable {
final DateTime time;
final double price;
const PatternPoint(this.time, this.price);
factory PatternPoint.fromJson(Map<String, dynamic> json) => PatternPoint(DateTime.tryParse(json['time']?.toString() ?? '') ?? DateTime.now(), (json['price'] as num?)?.toDouble() ?? 0.0);
@override
List<Object?> get props => [time, price];
}
class BreakoutSignalModel extends Equatable {
final String direction; // "UP", "DOWN"
final double targetPrice;
final double potentialPercent;
const BreakoutSignalModel({
required this.direction,
required this.targetPrice,
required this.potentialPercent,
});
factory BreakoutSignalModel.fromJson(Map<String, dynamic> json) {
return BreakoutSignalModel(
direction: (json['direction'] ?? json['Direction'])?.toString() ?? 'UP',
targetPrice: (json['targetPrice'] ?? json['TargetPrice'] as num?)?.toDouble() ?? 0.0,
potentialPercent: (json['potentialPercent'] ?? json['PotentialPercent'] as num?)?.toDouble() ?? 0.0,
);
}
@override
List<Object?> get props => [direction, targetPrice, potentialPercent];
}
class ChartPatternModel extends Equatable {
final String type;
final String description;
final double confidencePercent;
final BreakoutSignalModel? breakoutSignal;
final List<PatternPoint> upperLine;
final List<PatternPoint> lowerLine;
const ChartPatternModel({
required this.type,
this.description = '',
this.confidencePercent = 0.0,
this.breakoutSignal,
required this.upperLine,
required this.lowerLine,
});
factory ChartPatternModel.fromJson(Map<String, dynamic> json) {
BreakoutSignalModel? breakout;
final bJson = json['breakoutSignal'] ?? json['BreakoutSignal'];
if (bJson != null && bJson is Map<String, dynamic>) {
breakout = BreakoutSignalModel.fromJson(bJson);
}
return ChartPatternModel(
type: json['type']?.toString() ?? json['Type']?.toString() ?? 'Pattern',
description: json['description']?.toString() ?? json['Description']?.toString() ?? '',
confidencePercent: (json['confidencePercent'] ?? json['ConfidencePercent'] as num?)?.toDouble() ?? 0.0,
breakoutSignal: breakout,
upperLine: (json['upperLine'] as List<dynamic>? ?? []).map((e) => PatternPoint.fromJson(e as Map<String, dynamic>)).toList(),
lowerLine: (json['lowerLine'] as List<dynamic>? ?? []).map((e) => PatternPoint.fromJson(e as Map<String, dynamic>)).toList(),
);
}
@override
List<Object?> get props => [type, description, confidencePercent, breakoutSignal, upperLine, lowerLine];
}
class TechnicalAnalysisModel extends Equatable {
final String symbol;
final String currency;
final double? currentPrice;
final String trend;
final String rsi;
final String macd;
final String overallSignal;
final String sma50;
final String sma200;
final double? vix;
final String? sp500Trend;
final double? dxy;
final double? stopLossAtr;
final List<CandleModel> candles;
final List<IndicatorModel> indicators;
final List<ChartPatternModel> patterns;
final List<StrategySignalModel> signals;
const TechnicalAnalysisModel({
required this.symbol,
this.currency = 'EUR',
this.currentPrice,
required this.trend,
required this.rsi,
required this.macd,
required this.overallSignal,
required this.sma50,
required this.sma200,
this.vix,
this.sp500Trend,
this.dxy,
this.stopLossAtr,
this.candles = const [],
this.indicators = const [],
this.patterns = const [],
this.signals = const [],
});
factory TechnicalAnalysisModel.fromJson(Map<String, dynamic> json) {
var rawCandles = json['candles'] as List<dynamic>? ?? [];
var candlesList = rawCandles.map((c) => CandleModel.fromJson(c as Map<String, dynamic>)).toList();
var rawIndicators = json['indicators'] as List<dynamic>? ?? [];
var indicatorsList = rawIndicators.map((i) => IndicatorModel.fromJson(i as Map<String, dynamic>)).toList();
var rawSignals = json['signals'] as List<dynamic>? ?? [];
var signalsList = rawSignals.map((s) => StrategySignalModel.fromJson(s as Map<String, dynamic>)).toList();
var rawPatterns = json['patterns'] as List<dynamic>? ?? [];
var patternsList = rawPatterns.map((p) => ChartPatternModel.fromJson(p as Map<String, dynamic>)).toList();
final lastInd = indicatorsList.isNotEmpty ? indicatorsList.last : null;
final regime = json['marketRegime'] as Map<String, dynamic>?;
String parsedTrend = lastInd?.supertrendDirection ?? 'Neutral';
if (parsedTrend.toUpperCase() == 'BUY') parsedTrend = 'Bullisch ▲';
if (parsedTrend.toUpperCase() == 'SELL') parsedTrend = 'Bearisch ▼';
String parsedSignal = 'HOLD';
if (signalsList.isNotEmpty) {
parsedSignal = signalsList.last.type.toUpperCase();
}
return TechnicalAnalysisModel(
symbol: json['symbol']?.toString() ?? '',
currency: json['currency']?.toString() ?? 'EUR',
currentPrice: (json['currentPrice'] as num?)?.toDouble(),
trend: parsedTrend,
rsi: lastInd?.rsi14?.toStringAsFixed(1) ?? 'N/A',
macd: lastInd?.macdHistogram?.toStringAsFixed(2) ?? lastInd?.macdLine?.toStringAsFixed(2) ?? 'N/A',
overallSignal: parsedSignal,
sma50: lastInd?.sma50?.toStringAsFixed(2) ?? 'N/A',
sma200: lastInd?.sma200?.toStringAsFixed(2) ?? 'N/A',
vix: (regime?['vixValue'] as num?)?.toDouble(),
sp500Trend: regime?['marketTrend']?.toString(),
dxy: (regime?['dxyValue'] as num?)?.toDouble(),
stopLossAtr: lastInd?.recommendedStopLoss,
candles: candlesList,
indicators: indicatorsList,
patterns: patternsList,
signals: signalsList,
);
}
Map<String, dynamic> toJson() {
return {
'symbol': symbol,
'currency': currency,
'trend': trend,
'rsi': rsi,
'macd': macd,
'overallSignal': overallSignal,
'sma50': sma50,
'sma200': sma200,
'vix': vix,
'sp500Trend': sp500Trend,
'dxy': dxy,
'stopLossAtr': stopLossAtr,
};
}
@override
List<Object?> get props => [
symbol, currency, trend, rsi, macd, overallSignal, sma50, sma200, vix,
sp500Trend, dxy, stopLossAtr, candles, indicators, patterns, signals
];
}