복합지표 전략 추가
This commit is contained in:
@@ -118,6 +118,61 @@ class PriceExtremeRuleTest {
|
||||
"어댑터가 DC_LOWER→NL_PRIOR 로 정규화하면 하락 구간에서 매도가 나와야 함");
|
||||
}
|
||||
|
||||
@Test
|
||||
void newHigh920Buy_andTree_firesOnUptrendWithVolume() throws Exception {
|
||||
BarSeries series = buildTrendSeries(120, true);
|
||||
Rule buy = rule(series, """
|
||||
{ "type": "AND", "children": [
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_HIGH", "conditionType": "GTE",
|
||||
"leftField": "CLOSE_PRICE", "rightField": "NH_PRIOR_9", "period": 9 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_HIGH", "conditionType": "CROSS_UP",
|
||||
"leftField": "CLOSE_PRICE", "rightField": "NH_PRIOR_20", "period": 20 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_HIGH", "conditionType": "GTE",
|
||||
"leftField": "HIGH_PRICE", "rightField": "NH_PRIOR_20", "period": 20 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "ADX", "conditionType": "GTE",
|
||||
"leftField": "ADX_VALUE", "rightField": "ADX_25" }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "VOLUME", "conditionType": "GT",
|
||||
"leftField": "VOLUME_VALUE", "rightField": "VOLUME_MA" }}
|
||||
]}
|
||||
""");
|
||||
|
||||
List<Integer> hits = satisfiedIndices(buy, series);
|
||||
assertTrue(hits.stream().noneMatch(i -> i < 20),
|
||||
"워밍업 구간(20봉 미만)에서는 복합 매수 조건이 없어야 함");
|
||||
}
|
||||
|
||||
@Test
|
||||
void newLow920Sell_andTree_firesOnDowntrend() throws Exception {
|
||||
BarSeries series = buildTrendSeries(120, false);
|
||||
Rule sell = rule(series, """
|
||||
{ "type": "AND", "children": [
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_LOW", "conditionType": "LTE",
|
||||
"leftField": "CLOSE_PRICE", "rightField": "NL_PRIOR_9", "period": 9 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_LOW", "conditionType": "CROSS_DOWN",
|
||||
"leftField": "CLOSE_PRICE", "rightField": "NL_PRIOR_20", "period": 20 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "NEW_LOW", "conditionType": "LTE",
|
||||
"leftField": "LOW_PRICE", "rightField": "NL_PRIOR_20", "period": 20 }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "ADX", "conditionType": "GTE",
|
||||
"leftField": "ADX_VALUE", "rightField": "ADX_20" }},
|
||||
{ "type": "CONDITION", "condition": {
|
||||
"indicatorType": "VOLUME", "conditionType": "GT",
|
||||
"leftField": "VOLUME_VALUE", "rightField": "VOLUME_MA" }}
|
||||
]}
|
||||
""");
|
||||
|
||||
List<Integer> hits = satisfiedIndices(sell, series);
|
||||
assertFalse(hits.isEmpty(), "하락 추세에서 9·20일 신저가 복합 매도 조건이 최소 1회 충족되어야 함");
|
||||
}
|
||||
|
||||
// ── helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private Rule rule(BarSeries series, String json) throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user