nextrade-engine 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nextrade_engine-0.5.0/nextrade_engine.egg-info → nextrade_engine-0.6.0}/PKG-INFO +2 -12
- nextrade_engine-0.6.0/nextrade/nextrade/__init__.py +194 -0
- nextrade_engine-0.6.0/nextrade/nextrade/lang.py +320 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/utils/terminal_ui.py +29 -31
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade/nextrade_engine.egg-info}/PKG-INFO +2 -12
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/SOURCES.txt +6 -6
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/pyproject.toml +5 -15
- nextrade_engine-0.5.0/nextrade/nextrade/__init__.py +0 -277
- nextrade_engine-0.5.0/nextrade/setup.py +0 -10
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/LICENSE +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/README.md +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/backtest/__init__.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/backtest/engine.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/core/__init__.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/core/brain.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/core/regime.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/data/__init__.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/data/fetcher.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/indicators/__init__.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/indicators/adaptive.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/indicators/confluence.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/indicators/pattern.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/nextrade/nextrade/utils/__init__.py +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/dependency_links.txt +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/requires.txt +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/top_level.txt +0 -0
- {nextrade_engine-0.5.0 → nextrade_engine-0.6.0}/setup.cfg +0 -0
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextrade-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: AI Trading Engine — Ringan, Multi-Market, Bisa di HP
|
|
5
5
|
Author-email: NexTrade <wafiqrazy035@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/nextrade-ai/nextrade
|
|
8
|
-
Project-URL: Issues, https://github.com/nextrade-ai/nextrade/issues
|
|
6
|
+
License-Expression: MIT
|
|
9
7
|
Keywords: trading,ai,forex,crypto,backtest,signal
|
|
10
8
|
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
9
|
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
10
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
-
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
21
11
|
Requires-Python: >=3.8
|
|
22
12
|
Description-Content-Type: text/markdown
|
|
23
13
|
License-File: LICENSE
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NexTrade — AI Trading Engine
|
|
3
|
+
import nextrade → wizard muncul otomatis di terminal
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from nextrade.lang import set_language, list_languages, get, current as _lang
|
|
7
|
+
from nextrade.utils.terminal_ui import (
|
|
8
|
+
print_welcome, print_signal, print_error,
|
|
9
|
+
print_loading, print_success, list_strategies, STRATEGIES
|
|
10
|
+
)
|
|
11
|
+
from nextrade.indicators.confluence import confluence_score
|
|
12
|
+
from nextrade.core.regime import detect_regime
|
|
13
|
+
from nextrade.core.brain import Brain
|
|
14
|
+
from nextrade.data.fetcher import fetch, fetch_multi, list_markets
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
__version__ = "0.6.0"
|
|
18
|
+
__author__ = "NexTrade"
|
|
19
|
+
|
|
20
|
+
# Tampilkan wizard saat pertama kali import
|
|
21
|
+
print_welcome()
|
|
22
|
+
|
|
23
|
+
# Instance brain global
|
|
24
|
+
_brain = Brain.__new__(Brain)
|
|
25
|
+
_brain.state = None
|
|
26
|
+
|
|
27
|
+
def _get_brain():
|
|
28
|
+
global _brain
|
|
29
|
+
if _brain.state is None:
|
|
30
|
+
_brain = Brain()
|
|
31
|
+
return _brain
|
|
32
|
+
|
|
33
|
+
# ─────────────────────────────────────────
|
|
34
|
+
# PUBLIC API
|
|
35
|
+
# ─────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
def start(strategy: str = "adaptive",
|
|
38
|
+
market: str = "BTCUSD",
|
|
39
|
+
timeframe: str = "H1",
|
|
40
|
+
data: dict = None):
|
|
41
|
+
"""
|
|
42
|
+
Jalankan NexTrade dengan strategi pilihan.
|
|
43
|
+
|
|
44
|
+
Contoh:
|
|
45
|
+
nextrade.start("momentum", market="BTCUSD")
|
|
46
|
+
nextrade.start("reversal", market="EURUSD", timeframe="H4")
|
|
47
|
+
"""
|
|
48
|
+
strategy = strategy.lower().strip()
|
|
49
|
+
|
|
50
|
+
if strategy not in STRATEGIES:
|
|
51
|
+
print_error(f"{get('error_strategy')}: {', '.join(STRATEGIES)}")
|
|
52
|
+
list_strategies()
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
print_loading(f"{get('loading_strategy')} {strategy.upper()}...")
|
|
56
|
+
|
|
57
|
+
if data is None:
|
|
58
|
+
data = fetch(market, timeframe, bars=500)
|
|
59
|
+
if data is None:
|
|
60
|
+
print_error(get('error_data'))
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
print_loading(f"{get('loading_indicators')}...")
|
|
64
|
+
|
|
65
|
+
result = confluence_score(
|
|
66
|
+
opens = data["open"],
|
|
67
|
+
highs = data["high"],
|
|
68
|
+
lows = data["low"],
|
|
69
|
+
closes = data["close"],
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
brain = _get_brain()
|
|
73
|
+
threshold = brain.get_confidence_threshold()
|
|
74
|
+
confidence = result["confidence"]
|
|
75
|
+
|
|
76
|
+
if confidence >= threshold and result["details"]["pattern"]["direction"] != "bear":
|
|
77
|
+
signal = "BUY"
|
|
78
|
+
elif confidence <= (100 - threshold) or result["details"]["pattern"]["direction"] == "bear":
|
|
79
|
+
signal = "SELL"
|
|
80
|
+
else:
|
|
81
|
+
signal = "HOLD"
|
|
82
|
+
|
|
83
|
+
print_signal(signal=signal, confidence=confidence,
|
|
84
|
+
strategy=strategy, market=market)
|
|
85
|
+
|
|
86
|
+
regime = result["details"]["regime"]["regime"]
|
|
87
|
+
rsi = result["details"]["rsi"]
|
|
88
|
+
mom = result["details"]["momentum"]
|
|
89
|
+
price = data["price_now"]
|
|
90
|
+
|
|
91
|
+
print(f" \033[2m{get('detail_analysis')}:\033[0m")
|
|
92
|
+
print(f" \033[36m{get('price_now'):<18}:\033[0m {price:,.5f}")
|
|
93
|
+
print(f" \033[36m{get('market_condition'):<18}:\033[0m {get(regime)}")
|
|
94
|
+
print(f" \033[36mRSI Adaptif :\033[0m {rsi:.1f}")
|
|
95
|
+
print(f" \033[36m{get('iq_model'):<18}:\033[0m {brain.state['iq']} / 100")
|
|
96
|
+
print(f" \033[36m{get('agresivitas'):<18}:\033[0m {brain.state['agresivitas']}%")
|
|
97
|
+
print()
|
|
98
|
+
|
|
99
|
+
return {**result, "signal": signal, "market": market,
|
|
100
|
+
"price": price, "strategy": strategy}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def train(mode: str = "hybrid", market: str = "BTCUSD",
|
|
104
|
+
timeframe: str = "D1", bars: int = 1000):
|
|
105
|
+
"""Latih brain NexTrade dengan data real market."""
|
|
106
|
+
print(f"\n \033[1m\033[37m Training NexTrade Brain\033[0m")
|
|
107
|
+
print(f" \033[36m{'─' * 40}\033[0m")
|
|
108
|
+
data = fetch(market, timeframe, bars=bars)
|
|
109
|
+
if data is None:
|
|
110
|
+
print_error(get('error_data'))
|
|
111
|
+
return
|
|
112
|
+
_get_brain().train(mode=mode, data=data)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def brain_status():
|
|
116
|
+
"""Tampilkan status otak NexTrade."""
|
|
117
|
+
_get_brain().status()
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def set_agresivitas(pct: int):
|
|
121
|
+
"""Set agresivitas sinyal (0-100)."""
|
|
122
|
+
_get_brain().set_agresivitas(pct)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def scan(markets: list = None, timeframe: str = "H1"):
|
|
126
|
+
"""Scan banyak market sekaligus."""
|
|
127
|
+
if markets is None:
|
|
128
|
+
markets = ["BTCUSD", "EURUSD", "XAUUSD", "AAPL", "TSLA"]
|
|
129
|
+
|
|
130
|
+
print(f"\n \033[1m\033[37m NexTrade Market Scanner\033[0m")
|
|
131
|
+
print(f" \033[36m{'─' * 55}\033[0m")
|
|
132
|
+
print(f" \033[2m{'MARKET':<12} {'HARGA':>14} {get('signal'):>8} "
|
|
133
|
+
f"{'CONFIDENCE':>12} {get('market_condition')}\033[0m")
|
|
134
|
+
print(f" \033[36m{'─' * 55}\033[0m")
|
|
135
|
+
|
|
136
|
+
results = []
|
|
137
|
+
for market in markets:
|
|
138
|
+
data = fetch(market, timeframe, bars=300, silent=True)
|
|
139
|
+
if data is None: continue
|
|
140
|
+
result = confluence_score(
|
|
141
|
+
opens=data["open"], highs=data["high"],
|
|
142
|
+
lows=data["low"], closes=data["close"],
|
|
143
|
+
)
|
|
144
|
+
signal = result["signal"]
|
|
145
|
+
confidence = result["confidence"]
|
|
146
|
+
regime = result["details"]["regime"]["regime"]
|
|
147
|
+
price = data["price_now"]
|
|
148
|
+
sc = "\033[32m" if signal=="BUY" else "\033[31m" if signal=="SELL" else "\033[33m"
|
|
149
|
+
print(f" {market:<12} {price:>14,.5f} {sc}{signal:>8}\033[0m "
|
|
150
|
+
f"{confidence:>10.1f}% \033[2m{regime}\033[0m")
|
|
151
|
+
results.append({**result, "market": market, "price": price})
|
|
152
|
+
|
|
153
|
+
print(f" \033[36m{'─' * 55}\033[0m\n")
|
|
154
|
+
buys = [r for r in results if r["signal"]=="BUY"]
|
|
155
|
+
sells = [r for r in results if r["signal"]=="SELL"]
|
|
156
|
+
if buys:
|
|
157
|
+
best = max(buys, key=lambda x: x["confidence"])
|
|
158
|
+
print(f" \033[32m★ BUY : {best['market']} ({best['confidence']:.1f}%)\033[0m")
|
|
159
|
+
if sells:
|
|
160
|
+
best = max(sells, key=lambda x: x["confidence"])
|
|
161
|
+
print(f" \033[31m★ SELL : {best['market']} ({best['confidence']:.1f}%)\033[0m")
|
|
162
|
+
print()
|
|
163
|
+
return results
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def backtest(strategy: str = "adaptive", market: str = "BTCUSD",
|
|
167
|
+
timeframe: str = "D1", bars: int = 500,
|
|
168
|
+
agresivitas: int = 30, sl_pct: float = 2.0, tp_pct: float = 4.0):
|
|
169
|
+
"""Backtest strategi dengan data real historis."""
|
|
170
|
+
from nextrade.backtest.engine import run as _run
|
|
171
|
+
data = fetch(market, timeframe, bars=bars)
|
|
172
|
+
if data is None:
|
|
173
|
+
print_error(get('error_data'))
|
|
174
|
+
return
|
|
175
|
+
return _run(data=data, strategy=strategy, agresivitas=agresivitas,
|
|
176
|
+
sl_pct=sl_pct, tp_pct=tp_pct)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def info():
|
|
180
|
+
"""Tampilkan semua strategi dan market."""
|
|
181
|
+
list_strategies()
|
|
182
|
+
list_markets()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def regime(market: str = "BTCUSD", timeframe: str = "H1") -> dict:
|
|
186
|
+
"""Deteksi kondisi pasar saat ini."""
|
|
187
|
+
data = fetch(market, timeframe, bars=100, silent=True)
|
|
188
|
+
if data is None: return {}
|
|
189
|
+
return detect_regime(data["close"])
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def language():
|
|
193
|
+
"""Tampilkan semua bahasa yang tersedia."""
|
|
194
|
+
list_languages()
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NexTrade — Language System
|
|
3
|
+
Support: Indonesia (id), English (en), Melayu (my), Arab (ar)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
LANGUAGES = {
|
|
7
|
+
"id": "Indonesia",
|
|
8
|
+
"en": "English",
|
|
9
|
+
"my": "Melayu",
|
|
10
|
+
"ar": "العربية",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
TRANSLATIONS = {
|
|
14
|
+
|
|
15
|
+
# ── WELCOME ───────────────────────────────────────────
|
|
16
|
+
"welcome_title": {
|
|
17
|
+
"id": "Selamat datang di NexTrade!",
|
|
18
|
+
"en": "Welcome to NexTrade!",
|
|
19
|
+
"my": "Selamat datang ke NexTrade!",
|
|
20
|
+
"ar": "!مرحباً بك في NexTrade",
|
|
21
|
+
},
|
|
22
|
+
"welcome_sub": {
|
|
23
|
+
"id": "Engine AI trading ringan yang bisa jalan di HP sekalipun.",
|
|
24
|
+
"en": "Lightweight AI trading engine that runs even on mobile.",
|
|
25
|
+
"my": "Enjin dagangan AI ringan yang boleh berjalan di telefon.",
|
|
26
|
+
"ar": ".محرك تداول ذكاء اصطناعي خفيف يعمل حتى على الهاتف",
|
|
27
|
+
},
|
|
28
|
+
"strategies_title": {
|
|
29
|
+
"id": "Strategi tersedia",
|
|
30
|
+
"en": "Available strategies",
|
|
31
|
+
"my": "Strategi tersedia",
|
|
32
|
+
"ar": "الاستراتيجيات المتاحة",
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
# ── STRATEGI ──────────────────────────────────────────
|
|
36
|
+
"momentum": {
|
|
37
|
+
"id": "Ikut tren kuat · cocok market trending",
|
|
38
|
+
"en": "Follow strong trends · best for trending markets",
|
|
39
|
+
"my": "Ikut tren kuat · sesuai pasaran trending",
|
|
40
|
+
"ar": "اتبع الاتجاهات القوية · مناسب للأسواق المتجهة",
|
|
41
|
+
},
|
|
42
|
+
"reversal": {
|
|
43
|
+
"id": "Cari pembalikan arah · counter-trend",
|
|
44
|
+
"en": "Seek reversals · counter-trend strategy",
|
|
45
|
+
"my": "Cari pembalikan arah · strategi counter-trend",
|
|
46
|
+
"ar": "ابحث عن الانعكاسات · استراتيجية معاكسة للاتجاه",
|
|
47
|
+
},
|
|
48
|
+
"scalping": {
|
|
49
|
+
"id": "Entry cepat · target kecil · frekuensi tinggi",
|
|
50
|
+
"en": "Quick entries · small targets · high frequency",
|
|
51
|
+
"my": "Masuk cepat · sasaran kecil · frekuensi tinggi",
|
|
52
|
+
"ar": "دخول سريع · أهداف صغيرة · تكرار عالي",
|
|
53
|
+
},
|
|
54
|
+
"swing": {
|
|
55
|
+
"id": "Hold beberapa jam/hari · ikut swing besar",
|
|
56
|
+
"en": "Hold hours/days · follow major swings",
|
|
57
|
+
"my": "Tahan beberapa jam/hari · ikut swing besar",
|
|
58
|
+
"ar": "احتفظ لساعات/أيام · اتبع التأرجحات الكبيرة",
|
|
59
|
+
},
|
|
60
|
+
"adaptive": {
|
|
61
|
+
"id": "AI pilih strategi otomatis sesuai kondisi pasar",
|
|
62
|
+
"en": "AI auto-selects strategy based on market conditions",
|
|
63
|
+
"my": "AI pilih strategi secara automatik mengikut pasaran",
|
|
64
|
+
"ar": "الذكاء الاصطناعي يختار الاستراتيجية تلقائياً",
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
# ── HOW TO START ──────────────────────────────────────
|
|
68
|
+
"how_to_start": {
|
|
69
|
+
"id": "Cara mulai",
|
|
70
|
+
"en": "How to start",
|
|
71
|
+
"my": "Cara untuk mulakan",
|
|
72
|
+
"ar": "كيفية البدء",
|
|
73
|
+
},
|
|
74
|
+
"cmd_start": {
|
|
75
|
+
"id": "# langsung pakai strategi",
|
|
76
|
+
"en": "# use a strategy directly",
|
|
77
|
+
"my": "# guna strategi terus",
|
|
78
|
+
"ar": "# استخدم الاستراتيجية مباشرة",
|
|
79
|
+
},
|
|
80
|
+
"cmd_backtest": {
|
|
81
|
+
"id": "# test dulu sebelum live",
|
|
82
|
+
"en": "# test before going live",
|
|
83
|
+
"my": "# uji dahulu sebelum live",
|
|
84
|
+
"ar": "# اختبر قبل التداول الحي",
|
|
85
|
+
},
|
|
86
|
+
"cmd_info": {
|
|
87
|
+
"id": "# lihat semua pilihan",
|
|
88
|
+
"en": "# view all options",
|
|
89
|
+
"my": "# lihat semua pilihan",
|
|
90
|
+
"ar": "# عرض جميع الخيارات",
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
# ── SIGNAL ────────────────────────────────────────────
|
|
94
|
+
"signal": {
|
|
95
|
+
"id": "Sinyal",
|
|
96
|
+
"en": "Signal",
|
|
97
|
+
"my": "Isyarat",
|
|
98
|
+
"ar": "إشارة",
|
|
99
|
+
},
|
|
100
|
+
"confidence": {
|
|
101
|
+
"id": "Kepercayaan",
|
|
102
|
+
"en": "Confidence",
|
|
103
|
+
"my": "Keyakinan",
|
|
104
|
+
"ar": "الثقة",
|
|
105
|
+
},
|
|
106
|
+
"strategy": {
|
|
107
|
+
"id": "Strategi",
|
|
108
|
+
"en": "Strategy",
|
|
109
|
+
"my": "Strategi",
|
|
110
|
+
"ar": "الاستراتيجية",
|
|
111
|
+
},
|
|
112
|
+
"market": {
|
|
113
|
+
"id": "Market",
|
|
114
|
+
"en": "Market",
|
|
115
|
+
"my": "Pasaran",
|
|
116
|
+
"ar": "السوق",
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
# ── DETAIL ANALISIS ───────────────────────────────────
|
|
120
|
+
"detail_analysis": {
|
|
121
|
+
"id": "Detail Analisis",
|
|
122
|
+
"en": "Analysis Detail",
|
|
123
|
+
"my": "Butiran Analisis",
|
|
124
|
+
"ar": "تفاصيل التحليل",
|
|
125
|
+
},
|
|
126
|
+
"price_now": {
|
|
127
|
+
"id": "Harga Sekarang",
|
|
128
|
+
"en": "Current Price",
|
|
129
|
+
"my": "Harga Semasa",
|
|
130
|
+
"ar": "السعر الحالي",
|
|
131
|
+
},
|
|
132
|
+
"market_condition": {
|
|
133
|
+
"id": "Kondisi Pasar",
|
|
134
|
+
"en": "Market Condition",
|
|
135
|
+
"my": "Keadaan Pasaran",
|
|
136
|
+
"ar": "حالة السوق",
|
|
137
|
+
},
|
|
138
|
+
"iq_model": {
|
|
139
|
+
"id": "IQ Model",
|
|
140
|
+
"en": "Model IQ",
|
|
141
|
+
"my": "IQ Model",
|
|
142
|
+
"ar": "ذكاء النموذج",
|
|
143
|
+
},
|
|
144
|
+
"agresivitas": {
|
|
145
|
+
"id": "Agresivitas",
|
|
146
|
+
"en": "Aggressiveness",
|
|
147
|
+
"my": "Keagresifan",
|
|
148
|
+
"ar": "العدوانية",
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
# ── BRAIN ─────────────────────────────────────────────
|
|
152
|
+
"brain_title": {
|
|
153
|
+
"id": "NexTrade Brain — Status Model",
|
|
154
|
+
"en": "NexTrade Brain — Model Status",
|
|
155
|
+
"my": "NexTrade Brain — Status Model",
|
|
156
|
+
"ar": "NexTrade Brain — حالة النموذج",
|
|
157
|
+
},
|
|
158
|
+
"neurons_active": {
|
|
159
|
+
"id": "Neuron Aktif",
|
|
160
|
+
"en": "Active Neurons",
|
|
161
|
+
"my": "Neuron Aktif",
|
|
162
|
+
"ar": "الخلايا العصبية النشطة",
|
|
163
|
+
},
|
|
164
|
+
"last_trained": {
|
|
165
|
+
"id": "Terakhir Belajar",
|
|
166
|
+
"en": "Last Trained",
|
|
167
|
+
"my": "Latihan Terakhir",
|
|
168
|
+
"ar": "آخر تدريب",
|
|
169
|
+
},
|
|
170
|
+
"winrate": {
|
|
171
|
+
"id": "Winrate",
|
|
172
|
+
"en": "Win Rate",
|
|
173
|
+
"my": "Kadar Menang",
|
|
174
|
+
"ar": "معدل الفوز",
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
# ── LOADING ───────────────────────────────────────────
|
|
178
|
+
"loading_strategy": {
|
|
179
|
+
"id": "Memuat strategi",
|
|
180
|
+
"en": "Loading strategy",
|
|
181
|
+
"my": "Memuatkan strategi",
|
|
182
|
+
"ar": "جارٍ تحميل الاستراتيجية",
|
|
183
|
+
},
|
|
184
|
+
"loading_indicators": {
|
|
185
|
+
"id": "Menghitung indikator AI",
|
|
186
|
+
"en": "Calculating AI indicators",
|
|
187
|
+
"my": "Mengira penunjuk AI",
|
|
188
|
+
"ar": "جارٍ حساب مؤشرات الذكاء الاصطناعي",
|
|
189
|
+
},
|
|
190
|
+
"loading_data": {
|
|
191
|
+
"id": "Mengambil data",
|
|
192
|
+
"en": "Fetching data",
|
|
193
|
+
"my": "Mengambil data",
|
|
194
|
+
"ar": "جارٍ جلب البيانات",
|
|
195
|
+
},
|
|
196
|
+
"data_success": {
|
|
197
|
+
"id": "Data berhasil diambil",
|
|
198
|
+
"en": "Data fetched successfully",
|
|
199
|
+
"my": "Data berjaya diambil",
|
|
200
|
+
"ar": "تم جلب البيانات بنجاح",
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
# ── MARKET CONDITIONS ─────────────────────────────────
|
|
204
|
+
"TRENDING": {
|
|
205
|
+
"id": "TRENDING — Pasar sedang bergerak kuat",
|
|
206
|
+
"en": "TRENDING — Market moving strongly",
|
|
207
|
+
"my": "TRENDING — Pasaran bergerak kuat",
|
|
208
|
+
"ar": "TRENDING — السوق يتحرك بقوة",
|
|
209
|
+
},
|
|
210
|
+
"RANGING": {
|
|
211
|
+
"id": "RANGING — Pasar sedang sideways",
|
|
212
|
+
"en": "RANGING — Market moving sideways",
|
|
213
|
+
"my": "RANGING — Pasaran bergerak mendatar",
|
|
214
|
+
"ar": "RANGING — السوق يتحرك جانبياً",
|
|
215
|
+
},
|
|
216
|
+
"VOLATILE": {
|
|
217
|
+
"id": "VOLATILE — Pasar sedang tidak stabil",
|
|
218
|
+
"en": "VOLATILE — Market is unstable",
|
|
219
|
+
"my": "VOLATILE — Pasaran tidak stabil",
|
|
220
|
+
"ar": "VOLATILE — السوق غير مستقر",
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
# ── ERRORS ────────────────────────────────────────────
|
|
224
|
+
"error_strategy": {
|
|
225
|
+
"id": "Strategi tidak ditemukan. Pilih",
|
|
226
|
+
"en": "Strategy not found. Choose from",
|
|
227
|
+
"my": "Strategi tidak dijumpai. Pilih dari",
|
|
228
|
+
"ar": "الاستراتيجية غير موجودة. اختر من",
|
|
229
|
+
},
|
|
230
|
+
"error_data": {
|
|
231
|
+
"id": "Gagal ambil data market. Cek koneksi internet.",
|
|
232
|
+
"en": "Failed to fetch market data. Check your internet connection.",
|
|
233
|
+
"my": "Gagal mendapatkan data pasaran. Semak sambungan internet.",
|
|
234
|
+
"ar": "فشل في جلب بيانات السوق. تحقق من اتصالك بالإنترنت.",
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
# ── SET LANGUAGE ──────────────────────────────────────
|
|
238
|
+
"language_set": {
|
|
239
|
+
"id": "Bahasa diubah ke",
|
|
240
|
+
"en": "Language changed to",
|
|
241
|
+
"my": "Bahasa ditukar ke",
|
|
242
|
+
"ar": "تم تغيير اللغة إلى",
|
|
243
|
+
},
|
|
244
|
+
"language_invalid": {
|
|
245
|
+
"id": "Bahasa tidak tersedia. Pilih",
|
|
246
|
+
"en": "Language not available. Choose from",
|
|
247
|
+
"my": "Bahasa tidak tersedia. Pilih dari",
|
|
248
|
+
"ar": "اللغة غير متاحة. اختر من",
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
# ── BACKTEST ──────────────────────────────────────────
|
|
252
|
+
"backtest_title": {
|
|
253
|
+
"id": "NexTrade Backtest Engine",
|
|
254
|
+
"en": "NexTrade Backtest Engine",
|
|
255
|
+
"my": "NexTrade Enjin Ujian Balik",
|
|
256
|
+
"ar": "محرك الاختبار الخلفي NexTrade",
|
|
257
|
+
},
|
|
258
|
+
"total_trades": {
|
|
259
|
+
"id": "Total Trade",
|
|
260
|
+
"en": "Total Trades",
|
|
261
|
+
"my": "Jumlah Dagangan",
|
|
262
|
+
"ar": "إجمالي الصفقات",
|
|
263
|
+
},
|
|
264
|
+
"total_return": {
|
|
265
|
+
"id": "Total Return",
|
|
266
|
+
"en": "Total Return",
|
|
267
|
+
"my": "Jumlah Pulangan",
|
|
268
|
+
"ar": "إجمالي العائد",
|
|
269
|
+
},
|
|
270
|
+
"max_drawdown": {
|
|
271
|
+
"id": "Max Drawdown",
|
|
272
|
+
"en": "Max Drawdown",
|
|
273
|
+
"my": "Susutan Maksimum",
|
|
274
|
+
"ar": "أقصى تراجع",
|
|
275
|
+
},
|
|
276
|
+
"grade": {
|
|
277
|
+
"id": "Grade Model",
|
|
278
|
+
"en": "Model Grade",
|
|
279
|
+
"my": "Gred Model",
|
|
280
|
+
"ar": "تقييم النموذج",
|
|
281
|
+
},
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
# ── State bahasa aktif ─────────────────────────────────────
|
|
285
|
+
_current_lang = "id" # default Indonesia
|
|
286
|
+
|
|
287
|
+
def set_language(lang: str) -> bool:
|
|
288
|
+
"""
|
|
289
|
+
Set bahasa NexTrade.
|
|
290
|
+
lang: 'id' | 'en' | 'my' | 'ar'
|
|
291
|
+
"""
|
|
292
|
+
global _current_lang
|
|
293
|
+
lang = lang.lower().strip()
|
|
294
|
+
if lang not in LANGUAGES:
|
|
295
|
+
available = ", ".join([f"'{k}' ({v})" for k, v in LANGUAGES.items()])
|
|
296
|
+
print(f"\n \033[31m✗\033[0m {get('language_invalid')}: {available}\n")
|
|
297
|
+
return False
|
|
298
|
+
_current_lang = lang
|
|
299
|
+
lang_name = LANGUAGES[lang]
|
|
300
|
+
print(f"\n \033[32m✓\033[0m {get('language_set')}: \033[1m{lang_name}\033[0m\n")
|
|
301
|
+
return True
|
|
302
|
+
|
|
303
|
+
def get(key: str, lang: str = None) -> str:
|
|
304
|
+
"""Ambil teks dalam bahasa aktif."""
|
|
305
|
+
lang = lang or _current_lang
|
|
306
|
+
if key not in TRANSLATIONS:
|
|
307
|
+
return key
|
|
308
|
+
return TRANSLATIONS[key].get(lang, TRANSLATIONS[key].get("en", key))
|
|
309
|
+
|
|
310
|
+
def current() -> str:
|
|
311
|
+
"""Return kode bahasa aktif."""
|
|
312
|
+
return _current_lang
|
|
313
|
+
|
|
314
|
+
def list_languages():
|
|
315
|
+
"""Tampilkan semua bahasa yang tersedia."""
|
|
316
|
+
print(f"\n \033[1m\033[37m Bahasa tersedia / Available languages:\033[0m\n")
|
|
317
|
+
for code, name in LANGUAGES.items():
|
|
318
|
+
active = " \033[32m← aktif\033[0m" if code == _current_lang else ""
|
|
319
|
+
print(f" \033[33mnextrade.set_language('{code}')\033[0m → {name}{active}")
|
|
320
|
+
print()
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
2
|
NexTrade — Terminal UI
|
|
3
3
|
Semua tampilan, warna, dan wizard di terminal.
|
|
4
|
+
Support multi-bahasa via lang.py
|
|
4
5
|
"""
|
|
5
6
|
import sys
|
|
6
7
|
import time
|
|
8
|
+
from nextrade.lang import get, current
|
|
7
9
|
|
|
8
10
|
class Color:
|
|
9
11
|
RESET = "\033[0m"
|
|
@@ -17,15 +19,10 @@ class Color:
|
|
|
17
19
|
|
|
18
20
|
C = Color()
|
|
19
21
|
|
|
20
|
-
STRATEGIES =
|
|
21
|
-
"momentum" : "Ikut tren kuat · cocok market trending",
|
|
22
|
-
"reversal" : "Cari pembalikan arah · counter-trend",
|
|
23
|
-
"scalping" : "Entry cepat · target kecil · frekuensi tinggi",
|
|
24
|
-
"swing" : "Hold beberapa jam/hari · ikut swing besar",
|
|
25
|
-
"adaptive" : "AI pilih strategi otomatis sesuai kondisi pasar",
|
|
26
|
-
}
|
|
22
|
+
STRATEGIES = ["momentum", "reversal", "scalping", "swing", "adaptive"]
|
|
27
23
|
|
|
28
|
-
SEP
|
|
24
|
+
SEP = "─" * 68
|
|
25
|
+
SEP2 = "─" * 50
|
|
29
26
|
|
|
30
27
|
def print_banner():
|
|
31
28
|
print(f"""
|
|
@@ -41,16 +38,17 @@ def print_banner():
|
|
|
41
38
|
|
|
42
39
|
def print_welcome():
|
|
43
40
|
print_banner()
|
|
44
|
-
print(f"{C.BOLD}{C.WHITE}
|
|
45
|
-
print(f"{C.DIM}
|
|
46
|
-
print(f"{C.CYAN} ┌─
|
|
47
|
-
for i,
|
|
41
|
+
print(f"{C.BOLD}{C.WHITE} {get('welcome_title')}{C.RESET}")
|
|
42
|
+
print(f"{C.DIM} {get('welcome_sub')}{C.RESET}\n")
|
|
43
|
+
print(f"{C.CYAN} ┌─ {get('strategies_title')} ──────────────────────────────┐{C.RESET}")
|
|
44
|
+
for i, name in enumerate(STRATEGIES, 1):
|
|
45
|
+
desc = get(name)
|
|
48
46
|
print(f"{C.CYAN} │{C.RESET} {C.BOLD}{C.YELLOW}{i}. {name:<12}{C.RESET} {C.DIM}-> {desc}{C.RESET}")
|
|
49
47
|
print(f"{C.CYAN} └─────────────────────────────────────────────────────┘{C.RESET}\n")
|
|
50
|
-
print(f" {C.DIM}
|
|
51
|
-
print(f" {C.GREEN}nextrade.start(\"momentum\"){C.RESET} {C.DIM}#
|
|
52
|
-
print(f" {C.GREEN}nextrade.backtest(\"momentum\"){C.RESET} {C.DIM}#
|
|
53
|
-
print(f" {C.GREEN}nextrade.info(){C.RESET} {C.DIM}#
|
|
48
|
+
print(f" {C.DIM}{get('how_to_start')}:{C.RESET}")
|
|
49
|
+
print(f" {C.GREEN}nextrade.start(\"momentum\"){C.RESET} {C.DIM}# {get('cmd_start')}{C.RESET}")
|
|
50
|
+
print(f" {C.GREEN}nextrade.backtest(\"momentum\"){C.RESET} {C.DIM}# {get('cmd_backtest')}{C.RESET}")
|
|
51
|
+
print(f" {C.GREEN}nextrade.info(){C.RESET} {C.DIM}# {get('cmd_info')}{C.RESET}\n")
|
|
54
52
|
|
|
55
53
|
def print_loading(text: str, delay: float = 0.03):
|
|
56
54
|
steps = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]
|
|
@@ -58,30 +56,30 @@ def print_loading(text: str, delay: float = 0.03):
|
|
|
58
56
|
sys.stdout.write(f"\r {C.CYAN}{steps[i % len(steps)]}{C.RESET} {text}")
|
|
59
57
|
sys.stdout.flush()
|
|
60
58
|
time.sleep(delay)
|
|
61
|
-
sys.stdout.write(f"\r {C.GREEN}
|
|
59
|
+
sys.stdout.write(f"\r {C.GREEN}✓{C.RESET} {text}\n")
|
|
62
60
|
sys.stdout.flush()
|
|
63
61
|
|
|
64
|
-
def print_signal(signal: str, confidence: float,
|
|
62
|
+
def print_signal(signal: str, confidence: float,
|
|
63
|
+
strategy: str, market: str = ""):
|
|
65
64
|
color = C.GREEN if signal == "BUY" else C.RED if signal == "SELL" else C.YELLOW
|
|
66
65
|
bar_len = int(confidence / 5)
|
|
67
66
|
bar = "█" * bar_len + "░" * (20 - bar_len)
|
|
68
|
-
|
|
69
|
-
print(f"
|
|
70
|
-
print(f" {C.BOLD}Strategi :{C.RESET} {strategy}")
|
|
67
|
+
print(f"\n{C.CYAN}{SEP2}{C.RESET}")
|
|
68
|
+
print(f" {C.BOLD}{get('strategy'):<14}:{C.RESET} {strategy}")
|
|
71
69
|
if market:
|
|
72
|
-
print(f" {C.BOLD}
|
|
73
|
-
print(f" {C.BOLD}
|
|
74
|
-
print(f" {C.BOLD}
|
|
75
|
-
print(f"{C.CYAN}{
|
|
70
|
+
print(f" {C.BOLD}{get('market'):<14}:{C.RESET} {market}")
|
|
71
|
+
print(f" {C.BOLD}{get('signal'):<14}:{C.RESET} {color}{C.BOLD} {signal} {C.RESET}")
|
|
72
|
+
print(f" {C.BOLD}{get('confidence'):<14}:{C.RESET} {color}{bar}{C.RESET} {confidence:.1f}%")
|
|
73
|
+
print(f"{C.CYAN}{SEP2}{C.RESET}\n")
|
|
76
74
|
|
|
77
75
|
def print_error(msg: str):
|
|
78
|
-
print(f"\n {C.RED}
|
|
76
|
+
print(f"\n {C.RED}✗ {C.RESET}{msg}\n")
|
|
79
77
|
|
|
80
78
|
def print_success(msg: str):
|
|
81
|
-
print(f" {C.GREEN}
|
|
79
|
+
print(f" {C.GREEN}✓{C.RESET} {msg}")
|
|
82
80
|
|
|
83
81
|
def list_strategies():
|
|
84
|
-
print(f"\n{C.BOLD}{C.WHITE}
|
|
85
|
-
for name
|
|
86
|
-
print(f" {C.YELLOW}{C.BOLD}{name:<14}{C.RESET} {
|
|
87
|
-
print()
|
|
82
|
+
print(f"\n{C.BOLD}{C.WHITE} {get('strategies_title')}:{C.RESET}\n")
|
|
83
|
+
for name in STRATEGIES:
|
|
84
|
+
print(f" {C.YELLOW}{C.BOLD}{name:<14}{C.RESET} {get(name)}")
|
|
85
|
+
print()
|
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextrade-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: AI Trading Engine — Ringan, Multi-Market, Bisa di HP
|
|
5
5
|
Author-email: NexTrade <wafiqrazy035@gmail.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/nextrade-ai/nextrade
|
|
8
|
-
Project-URL: Issues, https://github.com/nextrade-ai/nextrade/issues
|
|
6
|
+
License-Expression: MIT
|
|
9
7
|
Keywords: trading,ai,forex,crypto,backtest,signal
|
|
10
8
|
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
9
|
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
10
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
-
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
21
11
|
Requires-Python: >=3.8
|
|
22
12
|
Description-Content-Type: text/markdown
|
|
23
13
|
License-File: LICENSE
|
{nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/SOURCES.txt
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
|
-
nextrade/setup.py
|
|
5
4
|
nextrade/nextrade/__init__.py
|
|
5
|
+
nextrade/nextrade/lang.py
|
|
6
6
|
nextrade/nextrade/backtest/__init__.py
|
|
7
7
|
nextrade/nextrade/backtest/engine.py
|
|
8
8
|
nextrade/nextrade/core/__init__.py
|
|
@@ -16,8 +16,8 @@ nextrade/nextrade/indicators/confluence.py
|
|
|
16
16
|
nextrade/nextrade/indicators/pattern.py
|
|
17
17
|
nextrade/nextrade/utils/__init__.py
|
|
18
18
|
nextrade/nextrade/utils/terminal_ui.py
|
|
19
|
-
nextrade_engine.egg-info/PKG-INFO
|
|
20
|
-
nextrade_engine.egg-info/SOURCES.txt
|
|
21
|
-
nextrade_engine.egg-info/dependency_links.txt
|
|
22
|
-
nextrade_engine.egg-info/requires.txt
|
|
23
|
-
nextrade_engine.egg-info/top_level.txt
|
|
19
|
+
nextrade/nextrade_engine.egg-info/PKG-INFO
|
|
20
|
+
nextrade/nextrade_engine.egg-info/SOURCES.txt
|
|
21
|
+
nextrade/nextrade_engine.egg-info/dependency_links.txt
|
|
22
|
+
nextrade/nextrade_engine.egg-info/requires.txt
|
|
23
|
+
nextrade/nextrade_engine.egg-info/top_level.txt
|
|
@@ -4,26 +4,18 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nextrade-engine"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "AI Trading Engine — Ringan, Multi-Market, Bisa di HP"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
license =
|
|
10
|
+
license = "MIT"
|
|
11
11
|
authors = [
|
|
12
12
|
{name = "NexTrade", email = "wafiqrazy035@gmail.com"}
|
|
13
13
|
]
|
|
14
14
|
keywords = ["trading", "ai", "forex", "crypto", "backtest", "signal"]
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
|
-
"Intended Audience :: Financial and Insurance Industry",
|
|
18
17
|
"Intended Audience :: Developers",
|
|
19
|
-
"License :: OSI Approved :: MIT License",
|
|
20
18
|
"Programming Language :: Python :: 3",
|
|
21
|
-
"Programming Language :: Python :: 3.8",
|
|
22
|
-
"Programming Language :: Python :: 3.9",
|
|
23
|
-
"Programming Language :: Python :: 3.10",
|
|
24
|
-
"Programming Language :: Python :: 3.11",
|
|
25
|
-
"Programming Language :: Python :: 3.12",
|
|
26
|
-
"Topic :: Office/Business :: Financial :: Investment",
|
|
27
19
|
]
|
|
28
20
|
requires-python = ">=3.8"
|
|
29
21
|
dependencies = [
|
|
@@ -31,10 +23,8 @@ dependencies = [
|
|
|
31
23
|
"yfinance",
|
|
32
24
|
]
|
|
33
25
|
|
|
34
|
-
[
|
|
35
|
-
|
|
36
|
-
Issues = "https://github.com/nextrade-ai/nextrade/issues"
|
|
26
|
+
[tool.setuptools]
|
|
27
|
+
package-dir = {"" = "nextrade"}
|
|
37
28
|
|
|
38
29
|
[tool.setuptools.packages.find]
|
|
39
|
-
where = ["
|
|
40
|
-
include = ["nextrade*"]
|
|
30
|
+
where = ["nextrade"]
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
NexTrade — AI Trading Engine
|
|
3
|
-
import nextrade → wizard muncul otomatis di terminal
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from nextrade.utils.terminal_ui import (
|
|
7
|
-
print_welcome, print_signal, print_error,
|
|
8
|
-
print_loading, print_success, list_strategies, STRATEGIES
|
|
9
|
-
)
|
|
10
|
-
from nextrade.indicators.confluence import confluence_score
|
|
11
|
-
from nextrade.core.regime import detect_regime
|
|
12
|
-
from nextrade.core.brain import Brain
|
|
13
|
-
from nextrade.data.fetcher import fetch, fetch_multi, list_markets
|
|
14
|
-
import numpy as np
|
|
15
|
-
|
|
16
|
-
__version__ = "0.3.0"
|
|
17
|
-
__author__ = "NexTrade"
|
|
18
|
-
|
|
19
|
-
# Tampilkan wizard saat pertama kali import
|
|
20
|
-
print_welcome()
|
|
21
|
-
|
|
22
|
-
# Instance brain global
|
|
23
|
-
_brain = Brain.__new__(Brain)
|
|
24
|
-
_brain.state = None
|
|
25
|
-
|
|
26
|
-
def _get_brain():
|
|
27
|
-
global _brain
|
|
28
|
-
if _brain.state is None:
|
|
29
|
-
_brain = Brain()
|
|
30
|
-
return _brain
|
|
31
|
-
|
|
32
|
-
# ─────────────────────────────────────────
|
|
33
|
-
# PUBLIC API
|
|
34
|
-
# ─────────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
def start(strategy: str = "adaptive",
|
|
37
|
-
market: str = "BTCUSD",
|
|
38
|
-
timeframe: str = "H1",
|
|
39
|
-
data: dict = None):
|
|
40
|
-
"""
|
|
41
|
-
Jalankan NexTrade — ambil data real lalu keluarkan sinyal.
|
|
42
|
-
|
|
43
|
-
Contoh:
|
|
44
|
-
nextrade.start("momentum", market="BTCUSD")
|
|
45
|
-
nextrade.start("reversal", market="EURUSD", timeframe="M15")
|
|
46
|
-
nextrade.start("adaptive", market="AAPL")
|
|
47
|
-
"""
|
|
48
|
-
strategy = strategy.lower().strip()
|
|
49
|
-
|
|
50
|
-
if strategy not in STRATEGIES:
|
|
51
|
-
print_error(f"Strategi '{strategy}' tidak ditemukan.")
|
|
52
|
-
list_strategies()
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
print_loading(f"Memuat strategi {strategy.upper()}...")
|
|
56
|
-
|
|
57
|
-
# Ambil data real kalau tidak ada data manual
|
|
58
|
-
if data is None:
|
|
59
|
-
data = fetch(market, timeframe, bars=500)
|
|
60
|
-
if data is None:
|
|
61
|
-
print_error("Gagal ambil data market. Cek koneksi internet.")
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
print_loading("Menghitung indikator AI...")
|
|
65
|
-
|
|
66
|
-
# Hitung sinyal pakai confluence score
|
|
67
|
-
result = confluence_score(
|
|
68
|
-
opens = data["open"],
|
|
69
|
-
highs = data["high"],
|
|
70
|
-
lows = data["low"],
|
|
71
|
-
closes = data["close"],
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
# Sesuaikan confidence threshold dengan agresivitas brain
|
|
75
|
-
brain = _get_brain()
|
|
76
|
-
threshold = brain.get_confidence_threshold()
|
|
77
|
-
confidence = result["confidence"]
|
|
78
|
-
|
|
79
|
-
# Adjust sinyal berdasarkan threshold agresivitas
|
|
80
|
-
if confidence >= threshold and result["details"]["pattern"]["direction"] != "bear":
|
|
81
|
-
signal = "BUY"
|
|
82
|
-
elif confidence <= (100 - threshold) or result["details"]["pattern"]["direction"] == "bear":
|
|
83
|
-
signal = "SELL"
|
|
84
|
-
else:
|
|
85
|
-
signal = "HOLD"
|
|
86
|
-
|
|
87
|
-
# Tampilkan sinyal
|
|
88
|
-
print_signal(
|
|
89
|
-
signal = signal,
|
|
90
|
-
confidence = confidence,
|
|
91
|
-
strategy = strategy,
|
|
92
|
-
market = market,
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
# Tampilkan detail tambahan
|
|
96
|
-
regime = result["details"]["regime"]["regime"]
|
|
97
|
-
rsi = result["details"]["rsi"]
|
|
98
|
-
mom = result["details"]["momentum"]
|
|
99
|
-
price = data["price_now"]
|
|
100
|
-
|
|
101
|
-
print(f" \033[2mDetail Analisis:\033[0m")
|
|
102
|
-
print(f" \033[36mHarga Sekarang :\033[0m {price:,.5f}")
|
|
103
|
-
print(f" \033[36mKondisi Pasar :\033[0m {regime}")
|
|
104
|
-
print(f" \033[36mRSI Adaptif :\033[0m {rsi:.1f}")
|
|
105
|
-
print(f" \033[36mMomentum Score :\033[0m {mom:.1f}")
|
|
106
|
-
print(f" \033[36mIQ Model :\033[0m {brain.state['iq']} / 100")
|
|
107
|
-
print(f" \033[36mAgresivitas :\033[0m {brain.state['agresivitas']}%")
|
|
108
|
-
print()
|
|
109
|
-
|
|
110
|
-
return {**result, "signal": signal, "market": market,
|
|
111
|
-
"price": price, "strategy": strategy}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def train(mode: str = "hybrid", market: str = "BTCUSD",
|
|
115
|
-
timeframe: str = "D1", bars: int = 1000):
|
|
116
|
-
"""
|
|
117
|
-
Latih brain NexTrade dengan data real market.
|
|
118
|
-
|
|
119
|
-
Contoh:
|
|
120
|
-
nextrade.train("offline", market="BTCUSD", timeframe="D1")
|
|
121
|
-
nextrade.train("hybrid", market="EURUSD", timeframe="H4")
|
|
122
|
-
nextrade.train("online", market="AAPL", timeframe="D1")
|
|
123
|
-
"""
|
|
124
|
-
print(f"\n \033[1m\033[37m Training NexTrade Brain\033[0m")
|
|
125
|
-
print(f" \033[36m{'─' * 40}\033[0m")
|
|
126
|
-
|
|
127
|
-
# Ambil data real untuk training
|
|
128
|
-
data = fetch(market, timeframe, bars=bars)
|
|
129
|
-
if data is None:
|
|
130
|
-
print_error("Gagal ambil data untuk training.")
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
brain = _get_brain()
|
|
134
|
-
brain.train(mode=mode, data=data)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def brain_status():
|
|
138
|
-
"""Tampilkan status otak NexTrade."""
|
|
139
|
-
_get_brain().status()
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def set_agresivitas(pct: int):
|
|
143
|
-
"""
|
|
144
|
-
Set seberapa agresif NexTrade dalam mengambil sinyal.
|
|
145
|
-
0 = sangat selektif (sedikit sinyal tapi akurat)
|
|
146
|
-
100 = sangat agresif (banyak sinyal)
|
|
147
|
-
|
|
148
|
-
Contoh:
|
|
149
|
-
nextrade.set_agresivitas(20) # konservatif
|
|
150
|
-
nextrade.set_agresivitas(50) # moderat
|
|
151
|
-
nextrade.set_agresivitas(80) # agresif
|
|
152
|
-
"""
|
|
153
|
-
_get_brain().set_agresivitas(pct)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def scan(markets: list = None, strategy: str = "adaptive",
|
|
157
|
-
timeframe: str = "H1"):
|
|
158
|
-
"""
|
|
159
|
-
Scan banyak market sekaligus — cari peluang trading terbaik.
|
|
160
|
-
|
|
161
|
-
Contoh:
|
|
162
|
-
nextrade.scan(["BTCUSD", "EURUSD", "AAPL"])
|
|
163
|
-
nextrade.scan(["BTCUSD", "ETHUSD", "SOLUSD"], timeframe="H4")
|
|
164
|
-
"""
|
|
165
|
-
if markets is None:
|
|
166
|
-
markets = ["BTCUSD", "EURUSD", "XAUUSD", "AAPL", "TSLA"]
|
|
167
|
-
|
|
168
|
-
print(f"\n \033[1m\033[37m NexTrade Market Scanner\033[0m")
|
|
169
|
-
print(f" \033[36m{'─' * 55}\033[0m")
|
|
170
|
-
print(f" \033[2m{'MARKET':<12} {'HARGA':>14} {'SINYAL':>8} {'CONFIDENCE':>12} {'REGIME'}\033[0m")
|
|
171
|
-
print(f" \033[36m{'─' * 55}\033[0m")
|
|
172
|
-
|
|
173
|
-
results = []
|
|
174
|
-
for market in markets:
|
|
175
|
-
data = fetch(market, timeframe, bars=300, silent=True)
|
|
176
|
-
if data is None:
|
|
177
|
-
continue
|
|
178
|
-
|
|
179
|
-
result = confluence_score(
|
|
180
|
-
opens = data["open"],
|
|
181
|
-
highs = data["high"],
|
|
182
|
-
lows = data["low"],
|
|
183
|
-
closes = data["close"],
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
signal = result["signal"]
|
|
187
|
-
confidence = result["confidence"]
|
|
188
|
-
regime = result["details"]["regime"]["regime"]
|
|
189
|
-
price = data["price_now"]
|
|
190
|
-
|
|
191
|
-
# Warna sinyal
|
|
192
|
-
if signal == "BUY":
|
|
193
|
-
sc = "\033[32m"
|
|
194
|
-
elif signal == "SELL":
|
|
195
|
-
sc = "\033[31m"
|
|
196
|
-
else:
|
|
197
|
-
sc = "\033[33m"
|
|
198
|
-
|
|
199
|
-
print(f" {market:<12} {price:>14,.5f} {sc}{signal:>8}\033[0m "
|
|
200
|
-
f"{confidence:>10.1f}% \033[2m{regime}\033[0m")
|
|
201
|
-
|
|
202
|
-
results.append({**result, "market": market, "price": price})
|
|
203
|
-
|
|
204
|
-
print(f" \033[36m{'─' * 55}\033[0m\n")
|
|
205
|
-
|
|
206
|
-
# Highlight sinyal terkuat
|
|
207
|
-
buys = [r for r in results if r["signal"] == "BUY"]
|
|
208
|
-
sells = [r for r in results if r["signal"] == "SELL"]
|
|
209
|
-
|
|
210
|
-
if buys:
|
|
211
|
-
best = max(buys, key=lambda x: x["confidence"])
|
|
212
|
-
print(f" \033[32m★ Peluang BUY terkuat : {best['market']} "
|
|
213
|
-
f"({best['confidence']:.1f}%)\033[0m")
|
|
214
|
-
if sells:
|
|
215
|
-
best = max(sells, key=lambda x: x["confidence"])
|
|
216
|
-
print(f" \033[31m★ Peluang SELL terkuat : {best['market']} "
|
|
217
|
-
f"({best['confidence']:.1f}%)\033[0m")
|
|
218
|
-
print()
|
|
219
|
-
return results
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def backtest(strategy: str = "adaptive", market: str = "BTCUSD",
|
|
223
|
-
timeframe: str = "D1"):
|
|
224
|
-
"""Jalankan backtest strategi (coming soon v0.4.0)."""
|
|
225
|
-
print_loading("Menyiapkan backtest engine...")
|
|
226
|
-
print_success("Backtest engine hadir di v0.4.0!")
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def info():
|
|
230
|
-
"""Tampilkan semua strategi dan market yang tersedia."""
|
|
231
|
-
list_strategies()
|
|
232
|
-
list_markets()
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def regime(market: str = "BTCUSD", timeframe: str = "H1") -> dict:
|
|
236
|
-
"""
|
|
237
|
-
Deteksi kondisi pasar saat ini.
|
|
238
|
-
|
|
239
|
-
Contoh:
|
|
240
|
-
r = nextrade.regime("EURUSD")
|
|
241
|
-
print(r["regime"]) # TRENDING / RANGING / VOLATILE
|
|
242
|
-
"""
|
|
243
|
-
data = fetch(market, timeframe, bars=100, silent=True)
|
|
244
|
-
if data is None:
|
|
245
|
-
return {}
|
|
246
|
-
return detect_regime(data["close"])
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
def backtest(strategy: str = "adaptive",
|
|
250
|
-
market: str = "BTCUSD",
|
|
251
|
-
timeframe: str = "D1",
|
|
252
|
-
bars: int = 500,
|
|
253
|
-
agresivitas: int = 30,
|
|
254
|
-
sl_pct: float = 2.0,
|
|
255
|
-
tp_pct: float = 4.0):
|
|
256
|
-
"""
|
|
257
|
-
Backtest strategi NexTrade dengan data real historis.
|
|
258
|
-
|
|
259
|
-
Contoh:
|
|
260
|
-
nextrade.backtest("momentum", market="BTCUSD", timeframe="D1")
|
|
261
|
-
nextrade.backtest("adaptive", market="EURUSD", agresivitas=50)
|
|
262
|
-
nextrade.backtest("reversal", market="AAPL", sl_pct=1.5, tp_pct=3.0)
|
|
263
|
-
"""
|
|
264
|
-
from nextrade.backtest.engine import run as _run
|
|
265
|
-
|
|
266
|
-
data = fetch(market, timeframe, bars=bars)
|
|
267
|
-
if data is None:
|
|
268
|
-
print_error("Gagal ambil data untuk backtest.")
|
|
269
|
-
return
|
|
270
|
-
|
|
271
|
-
return _run(
|
|
272
|
-
data = data,
|
|
273
|
-
strategy = strategy,
|
|
274
|
-
agresivitas = agresivitas,
|
|
275
|
-
sl_pct = sl_pct,
|
|
276
|
-
tp_pct = tp_pct,
|
|
277
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/requires.txt
RENAMED
|
File without changes
|
{nextrade_engine-0.5.0 → nextrade_engine-0.6.0/nextrade}/nextrade_engine.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|