123 lines
3.6 KiB
Dart
123 lines
3.6 KiB
Dart
class QuestionAuditBarSlot {
|
||
const QuestionAuditBarSlot({
|
||
required this.asOf,
|
||
required this.avgPrice,
|
||
required this.volume,
|
||
this.open,
|
||
this.high,
|
||
this.low,
|
||
this.close,
|
||
});
|
||
|
||
final DateTime asOf;
|
||
final num? open;
|
||
final num? high;
|
||
final num? low;
|
||
final num? close;
|
||
final num avgPrice;
|
||
final num volume;
|
||
|
||
factory QuestionAuditBarSlot.fromJson(Map<String, dynamic> json) {
|
||
return QuestionAuditBarSlot(
|
||
asOf: DateTime.parse(json['asOf']! as String).toUtc(),
|
||
open: json['open'] as num?,
|
||
high: json['high'] as num?,
|
||
low: json['low'] as num?,
|
||
close: json['close'] as num?,
|
||
avgPrice: json['avgPrice'] as num,
|
||
volume: json['volume'] as num,
|
||
);
|
||
}
|
||
}
|
||
|
||
class QuestionAuditAsset {
|
||
const QuestionAuditAsset({
|
||
required this.symbol,
|
||
required this.priceDelta,
|
||
required this.volumeDelta,
|
||
required this.olderSlot,
|
||
required this.newerSlot,
|
||
});
|
||
|
||
final String symbol;
|
||
final num priceDelta;
|
||
final num volumeDelta;
|
||
final QuestionAuditBarSlot olderSlot;
|
||
final QuestionAuditBarSlot newerSlot;
|
||
|
||
factory QuestionAuditAsset.fromJson(Map<String, dynamic> json) {
|
||
return QuestionAuditAsset(
|
||
symbol: json['symbol']! as String,
|
||
priceDelta: json['priceDelta'] as num,
|
||
volumeDelta: json['volumeDelta'] as num,
|
||
olderSlot: QuestionAuditBarSlot.fromJson(
|
||
json['olderSlot']! as Map<String, dynamic>,
|
||
),
|
||
newerSlot: QuestionAuditBarSlot.fromJson(
|
||
json['newerSlot']! as Map<String, dynamic>,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// US RTH session-half slot length (9:30–12:45 and 12:45–16:00 ET).
|
||
const Duration _sessionHalfSlotDuration = Duration(hours: 3, minutes: 15);
|
||
|
||
class QuestionAuditReport {
|
||
const QuestionAuditReport({
|
||
required this.compareUntil,
|
||
required this.newerSlotStart,
|
||
required this.olderSlotStart,
|
||
required this.windowDays,
|
||
required this.assets,
|
||
required this.canStepOlder,
|
||
required this.canStepNewer,
|
||
this.stepOlderCompareUntil,
|
||
this.stepNewerCompareUntil,
|
||
});
|
||
|
||
final DateTime compareUntil;
|
||
final DateTime newerSlotStart;
|
||
final DateTime olderSlotStart;
|
||
final int windowDays;
|
||
final List<QuestionAuditAsset> assets;
|
||
final bool canStepOlder;
|
||
final bool canStepNewer;
|
||
final DateTime? stepOlderCompareUntil;
|
||
final DateTime? stepNewerCompareUntil;
|
||
|
||
factory QuestionAuditReport.fromJson(Map<String, dynamic> json) {
|
||
final List<dynamic> raw = json['assets'] as List<dynamic>? ?? <dynamic>[];
|
||
final DateTime compareUntil = DateTime.parse(
|
||
(json['compareUntil'] ?? json['asOf'])! as String,
|
||
).toUtc();
|
||
return QuestionAuditReport(
|
||
compareUntil: compareUntil,
|
||
newerSlotStart: json['newerSlotStart'] == null
|
||
? compareUntil.subtract(_sessionHalfSlotDuration)
|
||
: DateTime.parse(json['newerSlotStart']! as String).toUtc(),
|
||
olderSlotStart: json['olderSlotStart'] == null
|
||
? compareUntil.subtract(_sessionHalfSlotDuration * 2)
|
||
: DateTime.parse(json['olderSlotStart']! as String).toUtc(),
|
||
windowDays: (json['windowDays'] as num).toInt(),
|
||
canStepOlder: json['canStepOlder'] as bool? ?? false,
|
||
canStepNewer: json['canStepNewer'] as bool? ?? false,
|
||
stepOlderCompareUntil: _parseOptionalUtc(json['stepOlderCompareUntil']),
|
||
stepNewerCompareUntil: _parseOptionalUtc(json['stepNewerCompareUntil']),
|
||
assets: raw
|
||
.map(
|
||
(dynamic item) =>
|
||
QuestionAuditAsset.fromJson(item as Map<String, dynamic>),
|
||
)
|
||
.toList(growable: false),
|
||
);
|
||
}
|
||
}
|
||
|
||
DateTime? _parseOptionalUtc(dynamic raw) {
|
||
if (raw == null) {
|
||
return null;
|
||
}
|
||
return DateTime.parse(raw as String).toUtc();
|
||
}
|