98 lines
2.9 KiB
Dart
98 lines
2.9 KiB
Dart
import 'package:cyberhybridhub_server/trading/market_history_query.dart';
|
|
import 'package:cyberhybridhub_server/trading/rule_engine.dart';
|
|
import 'package:cyberhybridhub_server/trading/trading_config.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
void main() {
|
|
late TradingRuleConfig guessRule;
|
|
late DateTime now;
|
|
|
|
setUp(() {
|
|
guessRule = TradingRuleConfig.fromJson(<String, dynamic>{
|
|
'id': 'guess_weekly_move',
|
|
'type': 'guess_weekly_move',
|
|
'symbol': '*',
|
|
'question_template':
|
|
'{{token}} was {{ref_price}} {{ref_days_ago}} days ago. +10 up, -10 down.',
|
|
});
|
|
now = DateTime.utc(2026, 5, 26, 12);
|
|
});
|
|
|
|
WeeklyMover mover({
|
|
required num openClose,
|
|
required num currentClose,
|
|
int days = 5,
|
|
}) {
|
|
return WeeklyMover(
|
|
symbol: 'SPY',
|
|
openClose: openClose,
|
|
currentClose: currentClose,
|
|
days: days,
|
|
);
|
|
}
|
|
|
|
group('RuleEngine.evaluateGuessWeeklyMove', () {
|
|
test('up move produces ASSET_A token and correct_answer 10', () {
|
|
final RuleEngine engine = RuleEngine();
|
|
final RuleEvaluation result = engine.evaluateGuessWeeklyMove(
|
|
rule: guessRule,
|
|
mover: mover(openClose: 500, currentClose: 510),
|
|
symbolToken: 'ASSET_A',
|
|
now: now,
|
|
);
|
|
|
|
expect(result.fired, isTrue);
|
|
expect(result.symbolToken, 'ASSET_A');
|
|
expect(result.guessSymbol, 'SPY');
|
|
expect(result.correctAnswer, 10);
|
|
expect(result.refPrice, 500);
|
|
expect(result.observedPrice, 510);
|
|
expect(result.refDaysAgo, 5);
|
|
expect(
|
|
result.questionText,
|
|
'ASSET_A was 500.00 5 days ago. +10 up, -10 down.',
|
|
);
|
|
expect(result.questionText, isNot(contains('SPY')));
|
|
expect(result.questionText, isNot(contains('{{symbol}}')));
|
|
});
|
|
|
|
test('down move produces correct_answer -10', () {
|
|
final RuleEngine engine = RuleEngine();
|
|
final RuleEvaluation result = engine.evaluateGuessWeeklyMove(
|
|
rule: guessRule,
|
|
mover: mover(openClose: 510, currentClose: 500),
|
|
symbolToken: 'ASSET_A',
|
|
now: now,
|
|
);
|
|
|
|
expect(result.fired, isTrue);
|
|
expect(result.correctAnswer, -10);
|
|
});
|
|
|
|
test('insufficient bars (no mover) does not fire', () {
|
|
final RuleEngine engine = RuleEngine();
|
|
final RuleEvaluation result = engine.evaluateGuessWeeklyMove(
|
|
rule: guessRule,
|
|
mover: null,
|
|
symbolToken: null,
|
|
now: now,
|
|
);
|
|
|
|
expect(result.fired, isFalse);
|
|
expect(result.skipReason, RuleSkipReason.insufficientBars);
|
|
});
|
|
|
|
test('guessSymbol is exposed for pipeline metadata', () {
|
|
final RuleEngine engine = RuleEngine();
|
|
final RuleEvaluation result = engine.evaluateGuessWeeklyMove(
|
|
rule: guessRule,
|
|
mover: mover(openClose: 500, currentClose: 510),
|
|
symbolToken: 'ASSET_A',
|
|
now: now,
|
|
);
|
|
|
|
expect(result.guessSymbol, 'SPY');
|
|
});
|
|
});
|
|
}
|