306 lines
10 KiB
Dart
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
|
|
];
|
|
}
|