mirror of
https://github.com/chrisnov-it/quantumbotx.git
synced 2026-07-28 03:07:53 +00:00
Refactor app and templates for backtesting and active page tracking
- Update `app.py` to include backtesting routes and improve blueprint registration. - Modify templates to include an active page parameter for navigation highlighting. - Remove unused `crypto_data.py` and `api_crypto.py`. - Add new backtesting-related files and templates.
This commit is contained in:
@@ -34,22 +34,22 @@ app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'your-secret-key-here')
|
||||
|
||||
# --- Registrasi Blueprints ---
|
||||
# Impor blueprints setelah 'app' dibuat untuk menghindari circular import
|
||||
from core.routes.api_dashboard import api_dashboard # noqa: E402
|
||||
from core.routes.api_chart import api_chart # noqa: E402
|
||||
from core.routes.api_bots import api_bots # noqa: E402
|
||||
from core.routes.api_profile import api_profile # noqa: E402
|
||||
from core.routes.api_portfolio import api_portfolio # noqa: E402
|
||||
from core.routes.api_history import api_history # noqa: E402
|
||||
from core.routes.api_notifications import api_notifications # noqa: E402
|
||||
from core.routes.api_stocks import api_stocks # noqa: E402
|
||||
from core.routes.api_forex import api_forex # noqa: E402
|
||||
from core.routes.api_crypto import api_crypto # noqa: E402
|
||||
from core.routes.api_fundamentals import api_fundamentals # noqa: E402
|
||||
from core.routes.api_dashboard import api_dashboard
|
||||
from core.routes.api_chart import api_chart
|
||||
from core.routes.api_bots import api_bots
|
||||
from core.routes.api_profile import api_profile
|
||||
from core.routes.api_portfolio import api_portfolio
|
||||
from core.routes.api_history import api_history
|
||||
from core.routes.api_notifications import api_notifications
|
||||
from core.routes.api_stocks import api_stocks
|
||||
from core.routes.api_forex import api_forex
|
||||
from core.routes.api_fundamentals import api_fundamentals
|
||||
from core.routes.api_backtest import api_backtest
|
||||
|
||||
# Buat daftar semua blueprints untuk registrasi yang lebih rapi
|
||||
blueprints = [
|
||||
api_dashboard, api_chart, api_bots, api_profile, api_portfolio, api_history,
|
||||
api_notifications, api_stocks, api_forex, api_crypto, api_fundamentals
|
||||
api_notifications, api_stocks, api_forex, api_fundamentals, api_backtest
|
||||
]
|
||||
|
||||
# Daftarkan setiap blueprint ke aplikasi
|
||||
@@ -59,48 +59,47 @@ for blueprint in blueprints:
|
||||
# --- Rute Halaman (Views) ---
|
||||
@app.route('/')
|
||||
def dashboard():
|
||||
return render_template('index.html')
|
||||
return render_template('index.html', active_page='dashboard')
|
||||
|
||||
@app.route('/trading_bots')
|
||||
def bots_page():
|
||||
return render_template('trading_bots.html')
|
||||
return render_template('trading_bots.html', active_page='trading_bots')
|
||||
|
||||
@app.route('/bots/<int:bot_id>')
|
||||
def bot_detail_page(bot_id):
|
||||
return render_template('bot_detail.html')
|
||||
return render_template('bot_detail.html', active_page='trading_bots') # Tetap di menu trading_bots
|
||||
|
||||
@app.route('/backtesting')
|
||||
def backtesting_page():
|
||||
return render_template('backtesting.html', active_page='backtesting')
|
||||
|
||||
# ... (rute-rute halaman lainnya tetap sama) ...
|
||||
@app.route('/portfolio')
|
||||
def portfolio_page():
|
||||
return render_template('portfolio.html')
|
||||
return render_template('portfolio.html', active_page='portfolio')
|
||||
|
||||
@app.route('/history')
|
||||
def history_page():
|
||||
return render_template('history.html')
|
||||
return render_template('history.html', active_page='history')
|
||||
|
||||
@app.route('/settings')
|
||||
def settings_page():
|
||||
return render_template('settings.html')
|
||||
return render_template('settings.html', active_page='settings')
|
||||
|
||||
@app.route('/profile')
|
||||
def profile_page():
|
||||
return render_template('profile.html')
|
||||
return render_template('profile.html', active_page='profile') # Asumsi profile punya menu sendiri
|
||||
|
||||
@app.route('/notifications')
|
||||
def notifications_page():
|
||||
return render_template('notifications.html')
|
||||
|
||||
@app.route('/cryptocurrency')
|
||||
def crypto_page():
|
||||
return render_template('cryptocurrency.html')
|
||||
return render_template('notifications.html', active_page='notifications')
|
||||
|
||||
@app.route('/stocks')
|
||||
def stocks_page():
|
||||
return render_template('stocks.html')
|
||||
return render_template('stocks.html', active_page='stocks')
|
||||
|
||||
@app.route('/forex')
|
||||
def forex_page():
|
||||
return render_template('forex.html')
|
||||
return render_template('forex.html', active_page='forex')
|
||||
|
||||
# --- Error Handlers & Rute Lain-lain ---
|
||||
@app.errorhandler(404)
|
||||
@@ -145,6 +144,21 @@ def shutdown_handler():
|
||||
mt5.shutdown() # Pastikan koneksi MT5 selalu ditutup
|
||||
logger.info("Koneksi MetaTrader 5 ditutup. Proses shutdown selesai.")
|
||||
|
||||
# --- Filter Log Kustom ---
|
||||
class RequestLogFilter(logging.Filter):
|
||||
"""
|
||||
Filter untuk menyembunyikan log permintaan (polling) yang tidak penting dari terminal.
|
||||
"""
|
||||
def filter(self, record):
|
||||
# Pesan log dari Werkzeug terlihat seperti: "GET /api/path HTTP/1.1" 200 -
|
||||
msg = record.getMessage()
|
||||
# Daftar path yang ingin kita sembunyikan dari log konsol
|
||||
paths_to_ignore = [
|
||||
"GET /api/notifications/unread-count",
|
||||
"GET /api/bots/analysis" # <-- Ini juga sering di-poll
|
||||
]
|
||||
return not any(path in msg for path in paths_to_ignore)
|
||||
|
||||
# --- Titik Eksekusi Utama ---
|
||||
if __name__ == '__main__':
|
||||
# Memuat kredensial MT5 dari .env dengan aman
|
||||
@@ -162,26 +176,34 @@ if __name__ == '__main__':
|
||||
exit(1)
|
||||
|
||||
# Inisialisasi koneksi ke MetaTrader 5
|
||||
if not initialize_mt5(ACCOUNT, PASSWORD, SERVER):
|
||||
logger.critical("GAGAL terhubung ke MetaTrader 5. Pastikan kredensial benar dan terminal berjalan.")
|
||||
exit(1)
|
||||
else:
|
||||
# PERBAIKAN: Jangan langsung exit. Coba hubungkan, tapi biarkan aplikasi tetap berjalan jika gagal.
|
||||
# Koneksi akan dicoba lagi saat bot pertama kali dimulai.
|
||||
if initialize_mt5(ACCOUNT, PASSWORD, SERVER):
|
||||
logger.info("Berhasil terhubung ke MetaTrader 5.")
|
||||
|
||||
# Muat semua bot yang ada di database
|
||||
try:
|
||||
ambil_semua_bot()
|
||||
logger.info("Semua bot dari database berhasil dimuat.")
|
||||
except Exception as e:
|
||||
logger.error(f"Terjadi kesalahan saat memuat bot: {e}", exc_info=True)
|
||||
else:
|
||||
logger.warning("GAGAL terhubung ke MetaTrader 5 saat startup. Aplikasi akan berjalan tanpa koneksi live.")
|
||||
logger.warning("Fitur bot live tidak akan berfungsi sampai koneksi MT5 pulih.")
|
||||
|
||||
# --- 3. Daftarkan fungsi shutdown ---
|
||||
atexit.register(shutdown_handler)
|
||||
|
||||
# Jalankan aplikasi Flask
|
||||
app.run(
|
||||
debug=os.getenv('FLASK_DEBUG', 'False').lower() == 'true',
|
||||
host=os.getenv('FLASK_HOST', '127.0.0.1'),
|
||||
port=int(os.getenv('FLASK_PORT', 5000)),
|
||||
use_reloader=False # Penting: False untuk mencegah eksekusi ganda pada background thread
|
||||
)
|
||||
# --- Terapkan Filter Log ---
|
||||
# Dapatkan logger bawaan Werkzeug dan tambahkan filter kita
|
||||
werkzeug_logger = logging.getLogger('werkzeug')
|
||||
werkzeug_logger.addFilter(RequestLogFilter())
|
||||
|
||||
# --- 3. Daftarkan fungsi shutdown ---
|
||||
# PERBAIKAN: Pindahkan ke luar blok if/else agar selalu dijalankan.
|
||||
atexit.register(shutdown_handler)
|
||||
|
||||
# Jalankan aplikasi Flask
|
||||
# PERBAIKAN: Pindahkan ke luar blok if/else agar server selalu berjalan.
|
||||
app.run(
|
||||
debug=os.getenv('FLASK_DEBUG', 'False').lower() == 'true',
|
||||
host=os.getenv('FLASK_HOST', '127.0.0.1'),
|
||||
port=int(os.getenv('FLASK_PORT', 5000)),
|
||||
use_reloader=False # Penting: False untuk mencegah eksekusi ganda pada background thread
|
||||
)
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# core/backtesting/engine.py
|
||||
|
||||
from core.strategies.strategy_map import STRATEGY_MAP
|
||||
|
||||
def run_backtest(strategy_id, params, historical_data_df):
|
||||
"""
|
||||
Menjalankan simulasi backtesting untuk strategi tertentu pada data historis.
|
||||
"""
|
||||
strategy_class = STRATEGY_MAP.get(strategy_id)
|
||||
if not strategy_class:
|
||||
return {"error": "Strategi tidak ditemukan"}
|
||||
|
||||
# Inisialisasi state backtesting
|
||||
trades = []
|
||||
in_position = False
|
||||
initial_capital = 10000 # Modal awal virtual $10,000
|
||||
capital = initial_capital
|
||||
equity_curve = [initial_capital]
|
||||
peak_equity = initial_capital
|
||||
max_drawdown = 0.0
|
||||
|
||||
position_type = None
|
||||
entry_price = 0.0
|
||||
sl_pips = params.get('sl_pips', 100)
|
||||
tp_pips = params.get('tp_pips', 200)
|
||||
|
||||
# Asumsi pip value sederhana untuk backtesting, bisa disempurnakan nanti
|
||||
# Untuk pair JPY, point adalah 0.001, untuk yang lain 0.00001
|
||||
point = 0.001 if 'JPY' in historical_data_df.columns[0].upper() else 0.00001
|
||||
# Asumsi nilai per pip untuk 0.01 lot
|
||||
# Ini adalah penyederhanaan besar, tapi cukup untuk backtesting awal
|
||||
value_per_pip = 0.1 # $0.10 per pip
|
||||
|
||||
pip_value = 10 * point
|
||||
|
||||
# Mock bot object untuk strategi
|
||||
class MockBot:
|
||||
def __init__(self):
|
||||
self.market_for_mt5 = "BACKTEST"
|
||||
self.timeframe = "H1"
|
||||
self.tf_map = {}
|
||||
|
||||
# Inisialisasi strategi dengan parameter yang diberikan
|
||||
strategy_instance = strategy_class(bot_instance=MockBot(), params=params)
|
||||
|
||||
# Loop melalui setiap bar data historis
|
||||
for i in range(1, len(historical_data_df)):
|
||||
# Buat DataFrame "seolah-olah" ini adalah data real-time hingga bar saat ini
|
||||
# PERBAIKAN: Gunakan .copy() untuk membuat salinan eksplisit dari slice.
|
||||
# Ini akan menghilangkan SettingWithCopyWarning di semua strategi.
|
||||
current_market_data = historical_data_df.iloc[:i].copy()
|
||||
|
||||
analysis = strategy_instance.analyze(current_market_data)
|
||||
signal = analysis.get("signal")
|
||||
current_price = historical_data_df.iloc[i]['close']
|
||||
|
||||
# Cek SL/TP jika sedang dalam posisi
|
||||
if in_position:
|
||||
profit = 0
|
||||
if position_type == 'BUY':
|
||||
profit_pips = (current_price - entry_price) / point / 10
|
||||
if current_price <= entry_price - (sl_pips * pip_value):
|
||||
trades.append({'entry': entry_price, 'exit': current_price, 'profit_pips': profit_pips, 'reason': 'SL'})
|
||||
capital += profit_pips * value_per_pip
|
||||
in_position = False
|
||||
elif current_price >= entry_price + (tp_pips * pip_value):
|
||||
trades.append({'entry': entry_price, 'exit': current_price, 'profit_pips': profit_pips, 'reason': 'TP'})
|
||||
capital += profit_pips * value_per_pip
|
||||
in_position = False
|
||||
elif position_type == 'SELL':
|
||||
profit_pips = (entry_price - current_price) / point / 10
|
||||
if current_price >= entry_price + (sl_pips * pip_value):
|
||||
trades.append({'entry': entry_price, 'exit': current_price, 'profit_pips': profit_pips, 'reason': 'SL'})
|
||||
capital += profit_pips * value_per_pip
|
||||
in_position = False
|
||||
elif current_price <= entry_price - (tp_pips * pip_value):
|
||||
trades.append({'entry': entry_price, 'exit': current_price, 'profit_pips': profit_pips, 'reason': 'TP'})
|
||||
capital += profit_pips * value_per_pip
|
||||
in_position = False
|
||||
|
||||
if not in_position: # Jika posisi baru saja ditutup
|
||||
equity_curve.append(capital)
|
||||
peak_equity = max(peak_equity, capital)
|
||||
drawdown = (peak_equity - capital) / peak_equity
|
||||
max_drawdown = max(max_drawdown, drawdown)
|
||||
|
||||
# Cek sinyal baru
|
||||
if signal == 'BUY' and not in_position:
|
||||
in_position = True
|
||||
position_type = 'BUY'
|
||||
entry_price = current_price
|
||||
elif signal == 'SELL' and not in_position:
|
||||
in_position = True
|
||||
position_type = 'SELL'
|
||||
entry_price = current_price
|
||||
elif (signal == 'SELL' and in_position and position_type == 'BUY') or \
|
||||
(signal == 'BUY' and in_position and position_type == 'SELL'):
|
||||
# Sinyal berlawanan, tutup posisi lama
|
||||
profit_pips = ((current_price - entry_price) if position_type == 'BUY' else (entry_price - current_price)) / point / 10
|
||||
trades.append({'entry': entry_price, 'exit': current_price, 'profit_pips': profit_pips, 'reason': 'Signal Flip'})
|
||||
capital += profit_pips * value_per_pip
|
||||
equity_curve.append(capital)
|
||||
peak_equity = max(peak_equity, capital)
|
||||
drawdown = (peak_equity - capital) / peak_equity
|
||||
max_drawdown = max(max_drawdown, drawdown)
|
||||
in_position = False
|
||||
|
||||
# Hitung hasil akhir
|
||||
total_profit_pips = sum(trade['profit_pips'] for trade in trades)
|
||||
wins = len([trade for trade in trades if trade['profit_pips'] > 0])
|
||||
losses = len(trades) - wins
|
||||
win_rate = (wins / len(trades) * 100) if trades else 0
|
||||
|
||||
return {
|
||||
"total_trades": len(trades),
|
||||
"total_profit_pips": total_profit_pips,
|
||||
"win_rate_percent": win_rate,
|
||||
"wins": wins,
|
||||
"losses": losses,
|
||||
"max_drawdown_percent": max_drawdown * 100,
|
||||
"equity_curve": equity_curve,
|
||||
"trades": trades[-20:] # Tampilkan 20 trade terakhir
|
||||
}
|
||||
@@ -68,9 +68,13 @@ class TradingBot(threading.Thread):
|
||||
time.sleep(self.check_interval)
|
||||
continue
|
||||
|
||||
# --- PERBAIKAN: Panggil metode analyze dari objek strategi ---
|
||||
# Metode analyze tidak lagi memerlukan argumen
|
||||
self.last_analysis = self.strategy_instance.analyze()
|
||||
# --- PERBAIKAN: Bot sekarang yang mengambil data ---
|
||||
from core.data.fetch import get_rates
|
||||
tf_const = self.tf_map.get(self.timeframe, mt5.TIMEFRAME_H1)
|
||||
# Ambil data yang cukup untuk strategi terkompleks (misal, 250 bar untuk EMA 200)
|
||||
df = get_rates(self.market_for_mt5, tf_const, 250)
|
||||
|
||||
self.last_analysis = self.strategy_instance.analyze(df)
|
||||
logger.info(f"Bot {self.id} [{self.strategy_name}] - Last Analysis: {self.last_analysis}")
|
||||
signal = self.last_analysis.get("signal", "HOLD")
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# core/routes/api_backtest.py
|
||||
|
||||
import pandas as pd
|
||||
import json
|
||||
from flask import Blueprint, request, jsonify
|
||||
from core.backtesting.engine import run_backtest
|
||||
|
||||
api_backtest = Blueprint('api_backtest', __name__)
|
||||
|
||||
@api_backtest.route('/api/backtest/run', methods=['POST'])
|
||||
def run_backtest_route():
|
||||
if 'file' not in request.files:
|
||||
return jsonify({"error": "Tidak ada file data yang diunggah"}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({"error": "Nama file kosong"}), 400
|
||||
|
||||
try:
|
||||
# Baca data CSV yang diunggah
|
||||
df = pd.read_csv(file, parse_dates=['time'])
|
||||
|
||||
# Ambil parameter dari form data
|
||||
strategy_id = request.form.get('strategy')
|
||||
params = json.loads(request.form.get('params', '{}'))
|
||||
|
||||
results = run_backtest(strategy_id, params, df)
|
||||
return jsonify(results)
|
||||
except Exception as e:
|
||||
return jsonify({"error": f"Terjadi kesalahan saat backtesting: {str(e)}"}), 500
|
||||
@@ -1,39 +0,0 @@
|
||||
from flask import Blueprint, jsonify
|
||||
|
||||
# Initialize blueprint
|
||||
api_crypto = Blueprint('api_crypto', __name__)
|
||||
|
||||
# Sample data for initial load
|
||||
SAMPLE_CRYPTO_DATA = [
|
||||
{
|
||||
'name': 'Bitcoin',
|
||||
'symbol': 'BTC',
|
||||
'price': 'Rp 1.234,567,890.00',
|
||||
'change': '+2.34%',
|
||||
'market_cap': 'Rp 2.345,678,901,234.00'
|
||||
},
|
||||
{
|
||||
'name': 'Ethereum',
|
||||
'symbol': 'ETH',
|
||||
'price': 'Rp 123,456,789.00',
|
||||
'change': '-1.23%',
|
||||
'market_cap': 'Rp 1.234,567,890,123.00'
|
||||
}
|
||||
]
|
||||
|
||||
@api_crypto.route('/api/crypto')
|
||||
def get_crypto_data():
|
||||
"""Get cryptocurrency market data"""
|
||||
try:
|
||||
# Try to get real data from CMC
|
||||
from core.utils.external import get_crypto_data_from_cmc
|
||||
real_data = get_crypto_data_from_cmc()
|
||||
|
||||
if real_data and len(real_data) > 0:
|
||||
return jsonify(real_data)
|
||||
|
||||
# Fallback to sample data if API fails
|
||||
return jsonify(SAMPLE_CRYPTO_DATA)
|
||||
except Exception as e:
|
||||
# Return error response
|
||||
return jsonify({'error': str(e)}), 500
|
||||
@@ -1,27 +1,24 @@
|
||||
# core/strategies/base_strategy.py
|
||||
|
||||
class BaseStrategy:
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class BaseStrategy(ABC):
|
||||
"""
|
||||
Kelas dasar abstrak untuk semua strategi trading.
|
||||
Setiap strategi harus mewarisi kelas ini dan mengimplementasikan metode `analyze`.
|
||||
"""
|
||||
def __init__(self, bot_instance, params: dict = {}):
|
||||
"""
|
||||
Inisialisasi strategi dengan instance dari bot yang menjalankannya.
|
||||
|
||||
Args:
|
||||
bot_instance (TradingBot): Instance dari bot yang aktif.
|
||||
params (dict): Dictionary berisi parameter kustom untuk strategi.
|
||||
"""
|
||||
self.bot = bot_instance
|
||||
self.params = params
|
||||
|
||||
def analyze(self):
|
||||
@abstractmethod
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Metode inti yang harus di-override oleh setiap strategi turunan.
|
||||
Metode ini harus mengembalikan sebuah dictionary yang berisi hasil analisis.
|
||||
Menerima DataFrame sebagai input.
|
||||
"""
|
||||
raise NotImplementedError("Setiap strategi harus mengimplementasikan metode `analyze()`.")
|
||||
raise NotImplementedError("Setiap strategi harus mengimplementasikan metode `analyze(df)`.")
|
||||
|
||||
@classmethod
|
||||
def get_definable_params(cls):
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# /core/strategies/bollinger_bands.py
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class BollingerBandsStrategy(BaseStrategy):
|
||||
name = 'Bollinger Bands Reversion'
|
||||
@@ -15,16 +13,11 @@ class BollingerBandsStrategy(BaseStrategy):
|
||||
{"name": "bb_std", "label": "Standar Deviasi BB", "type": "number", "default": 2.0, "step": 0.1}
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Menganalisis pasar menggunakan strategi Bollinger Bands® Mean Reversion.
|
||||
Ideal untuk pasar ranging yang volatil seperti EURUSD.
|
||||
"""
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
# Butuh data yang cukup untuk BBands(20)
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, 21)
|
||||
|
||||
if df is None or df.empty or len(df) < 21:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup untuk Bollinger Bands."}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# /core/strategies/bollinger_squeeze.py
|
||||
import pandas_ta as ta
|
||||
import numpy as np
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates # <-- PERBAIKAN: Impor dari lokasi yang benar
|
||||
|
||||
class BollingerSqueezeStrategy(BaseStrategy):
|
||||
name = 'Bollinger Squeeze Breakout'
|
||||
@@ -21,17 +19,12 @@ class BollingerSqueezeStrategy(BaseStrategy):
|
||||
{"name": "volume_factor", "label": "Faktor Volume", "type": "number", "default": 1.5, "step": 0.1}
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Menganalisis pasar menggunakan strategi Bollinger Band Squeeze.
|
||||
Strategi ini menunggu periode volatilitas rendah ("squeeze") lalu
|
||||
masuk saat harga breakout.
|
||||
"""
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
# Butuh data yang cukup untuk rolling window squeeze (120) + BBands (20)
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, 150) # <-- PERBAIKAN: Gunakan fungsi yang benar
|
||||
|
||||
if df is None or df.empty or len(df) < 121:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup untuk Bollinger Squeeze."}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# /core/strategies/ma_crossover.py
|
||||
import pandas_ta as ta
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class MACrossoverStrategy(BaseStrategy):
|
||||
name = 'Moving Average Crossover'
|
||||
@@ -16,17 +14,11 @@ class MACrossoverStrategy(BaseStrategy):
|
||||
{"name": "slow_period", "label": "Periode MA Lambat", "type": "number", "default": 50}
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Menganalisis pasar menggunakan strategi Moving Average Crossover (20/50).
|
||||
Ideal untuk pasar dengan tren kuat seperti XAUUSD.
|
||||
"""
|
||||
# Mengakses properti dari instance bot yang tersimpan
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
# Butuh data yang cukup untuk MA 50
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, 52)
|
||||
|
||||
if df is None or df.empty or len(df) < 51:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup untuk MA Crossover."}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class MercyEdgeStrategy(BaseStrategy):
|
||||
{"name": "stoch_smooth", "label": "Stoch Smooth", "type": "number", "default": 3},
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df_h1):
|
||||
# Ambil parameter dinamis
|
||||
macd_fast = self.params.get('macd_fast', 12)
|
||||
macd_slow = self.params.get('macd_slow', 26)
|
||||
@@ -28,9 +28,8 @@ class MercyEdgeStrategy(BaseStrategy):
|
||||
stoch_d = self.params.get('stoch_d', 3)
|
||||
stoch_smooth = self.params.get('stoch_smooth', 3)
|
||||
|
||||
# Gunakan fungsi get_rates yang terstandarisasi
|
||||
# Ambil data sekunder (D1), data primer (H1) sudah diberikan
|
||||
df_d1 = get_rates(self.bot.market_for_mt5, mt5.TIMEFRAME_D1, 200)
|
||||
df_h1 = get_rates(self.bot.market_for_mt5, mt5.TIMEFRAME_H1, 100)
|
||||
|
||||
if df_d1 is None or df_h1 is None or len(df_d1) < 50 or len(df_h1) < 30:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup"}
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
# core/strategies/pulse_sync.py
|
||||
import pandas_ta as ta
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class PulseSyncStrategy(BaseStrategy):
|
||||
name = 'Pulse Sync (AI)'
|
||||
description = 'Menggunakan AI untuk menganalisis momentum harga berdasarkan Simple Moving Average (SMA).'
|
||||
|
||||
def analyze(self):
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, 100)
|
||||
|
||||
def analyze(self, df):
|
||||
if df is None or df.empty or len(df) < 30:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup"}
|
||||
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
import pandas_ta as ta
|
||||
import numpy as np
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class QuantumVelocityStrategy(BaseStrategy):
|
||||
name = 'Quantum Velocity'
|
||||
@@ -21,15 +19,10 @@ class QuantumVelocityStrategy(BaseStrategy):
|
||||
{"name": "squeeze_factor", "label": "Faktor Squeeze", "type": "number", "default": 0.7, "step": 0.1},
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Menganalisis pasar dengan filter tren jangka panjang dan pemicu breakout.
|
||||
"""
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
# Butuh data yang cukup untuk EMA 200
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, 250)
|
||||
|
||||
if df is None or df.empty or len(df) < 201:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup untuk Quantum Velocity."}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# /core/strategies/quantumbotx_hybrid.py
|
||||
import pandas_ta as ta
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class QuantumBotXHybridStrategy(BaseStrategy):
|
||||
name = 'QuantumBotX Hybrid'
|
||||
@@ -20,19 +18,13 @@ class QuantumBotXHybridStrategy(BaseStrategy):
|
||||
{"name": "bb_std", "label": "Std Dev BB", "type": "number", "default": 2.0, "step": 0.1}
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
def analyze(self, df):
|
||||
"""
|
||||
Menganalisis pasar menggunakan strategi Hybrid yang adaptif.
|
||||
Menggunakan MA Crossover saat trending (ADX > 25) dan
|
||||
Bollinger Bands saat ranging (ADX < 25).
|
||||
"""
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
# PERBAIKAN: Minta lebih banyak data. Indikator kompleks seperti ADX
|
||||
# butuh "pemanasan" lebih lama. 100 bar adalah angka yang lebih aman.
|
||||
data_points_to_fetch = 100
|
||||
required_data_points = 51 # Tetap butuh minimal 51 untuk SMA(50)
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, data_points_to_fetch)
|
||||
|
||||
if df is None or df.empty or len(df) < required_data_points:
|
||||
return {"signal": "HOLD", "price": None, "explanation": f"Data tidak cukup ({len(df) if df is not None else 0}/{required_data_points} bar)."}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# /core/strategies/rsi_breakout.py
|
||||
import pandas_ta as ta
|
||||
import MetaTrader5 as mt5
|
||||
from .base_strategy import BaseStrategy
|
||||
from core.data.fetch import get_rates
|
||||
|
||||
class RSIBreakoutStrategy(BaseStrategy):
|
||||
name = 'RSI Breakout'
|
||||
@@ -17,15 +15,11 @@ class RSIBreakoutStrategy(BaseStrategy):
|
||||
{"name": "oversold_level", "label": "Level Oversold", "type": "number", "default": 30}
|
||||
]
|
||||
|
||||
def analyze(self):
|
||||
tf_const = self.bot.tf_map.get(self.bot.timeframe, mt5.TIMEFRAME_H1)
|
||||
|
||||
def analyze(self, df):
|
||||
rsi_period = self.params.get('rsi_period', 14)
|
||||
overbought_level = self.params.get('overbought_level', 70)
|
||||
oversold_level = self.params.get('oversold_level', 30)
|
||||
|
||||
df = get_rates(self.bot.market_for_mt5, tf_const, rsi_period + 5)
|
||||
|
||||
if df is None or df.empty or len(df) < rsi_period + 2:
|
||||
return {"signal": "HOLD", "price": None, "explanation": "Data tidak cukup untuk RSI."}
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
// static/js/backtesting.js
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const strategySelect = document.getElementById('strategy-select');
|
||||
const paramsContainer = document.getElementById('params-container');
|
||||
const form = document.getElementById('backtest-form');
|
||||
const runBtn = document.getElementById('run-backtest-btn');
|
||||
const resultsContainer = document.getElementById('results-container');
|
||||
const resultsSummary = document.getElementById('results-summary');
|
||||
const loadingSpinner = document.getElementById('loading-spinner');
|
||||
let equityChart = null; // Variabel untuk menyimpan instance grafik
|
||||
const resultsLog = document.getElementById('results-log');
|
||||
|
||||
// Muat strategi ke dropdown
|
||||
async function loadStrategies() {
|
||||
try {
|
||||
const response = await fetch('/api/strategies');
|
||||
if (!response.ok) throw new Error('Gagal memuat strategi.');
|
||||
const strategies = await response.json();
|
||||
|
||||
strategySelect.innerHTML = '<option value="" disabled selected>Pilih sebuah strategi</option>';
|
||||
strategies.forEach(strategy => {
|
||||
const option = document.createElement('option');
|
||||
option.value = strategy.id;
|
||||
option.textContent = strategy.name;
|
||||
strategySelect.appendChild(option);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading strategies:', error);
|
||||
strategySelect.innerHTML = '<option value="">Gagal memuat strategi</option>';
|
||||
}
|
||||
}
|
||||
|
||||
// Muat parameter saat strategi dipilih
|
||||
strategySelect.addEventListener('change', async () => {
|
||||
const strategyId = strategySelect.value;
|
||||
paramsContainer.innerHTML = '<p class="text-sm text-gray-500">Memuat parameter...</p>';
|
||||
if (!strategyId) {
|
||||
paramsContainer.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/strategies/${strategyId}/params`);
|
||||
const params = await res.json();
|
||||
paramsContainer.innerHTML = ''; // Kosongkan lagi
|
||||
|
||||
if (params.length > 0) {
|
||||
params.forEach(param => {
|
||||
paramsContainer.innerHTML += `
|
||||
<div>
|
||||
<label for="${param.name}" class="block text-sm font-medium text-gray-700">${param.label}</label>
|
||||
<input type="${param.type || 'number'}" name="${param.name}" id="${param.name}" value="${param.default}" step="${param.step || 'any'}" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
|
||||
</div>`;
|
||||
});
|
||||
} else {
|
||||
paramsContainer.innerHTML = '<p class="text-sm text-gray-500">Strategi ini tidak memiliki parameter kustom.</p>';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Gagal memuat parameter strategi:', err);
|
||||
paramsContainer.innerHTML = '<p class="text-sm text-red-500">Gagal memuat parameter.</p>';
|
||||
}
|
||||
});
|
||||
|
||||
// Jalankan backtest saat form disubmit
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
loadingSpinner.classList.remove('hidden');
|
||||
resultsContainer.classList.add('hidden');
|
||||
runBtn.disabled = true;
|
||||
runBtn.textContent = 'Menjalankan...';
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
// Kumpulkan parameter kustom
|
||||
const params = {};
|
||||
// Tambahkan parameter SL/TP yang mungkin tidak ada di form kustom
|
||||
params['sl_pips'] = 100; // Nilai default, bisa dibuat dinamis nanti
|
||||
params['tp_pips'] = 200; // Nilai default
|
||||
|
||||
paramsContainer.querySelectorAll('input').forEach(input => {
|
||||
const value = parseFloat(input.value);
|
||||
// Pastikan hanya angka valid yang di-parse, selain itu ambil string
|
||||
params[input.name] = isNaN(value) ? input.value : value;
|
||||
});
|
||||
formData.append('params', JSON.stringify(params));
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/backtest/run', {
|
||||
method: 'POST',
|
||||
body: formData, // Kirim sebagai multipart/form-data
|
||||
});
|
||||
const results = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
displayResults(results);
|
||||
} else {
|
||||
alert(`Error: ${results.error}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Backtest failed:", err);
|
||||
alert('Gagal terhubung ke server.');
|
||||
} finally {
|
||||
loadingSpinner.classList.add('hidden');
|
||||
runBtn.disabled = false;
|
||||
runBtn.textContent = 'Jalankan Backtest';
|
||||
}
|
||||
});
|
||||
|
||||
function displayResults(data) {
|
||||
resultsContainer.classList.remove('hidden');
|
||||
// PERBAIKAN: Tampilkan 6 metrik utama
|
||||
resultsSummary.innerHTML = `
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Total Profit</p><p class="text-2xl font-bold text-green-600">${data.total_profit_pips.toFixed(2)} pips</p></div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Max Drawdown</p><p class="text-2xl font-bold text-red-600">${data.max_drawdown_percent.toFixed(2)}%</p></div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Win Rate</p><p class="text-2xl font-bold text-blue-600">${data.win_rate_percent.toFixed(2)}%</p></div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Total Trades</p><p class="text-2xl font-bold">${data.total_trades}</p></div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Wins</p><p class="text-2xl font-bold">${data.wins}</p></div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg"><p class="text-sm text-gray-500">Losses</p><p class="text-2xl font-bold">${data.losses}</p></div>
|
||||
`;
|
||||
|
||||
// Tampilkan grafik kurva ekuitas
|
||||
displayEquityChart(data.equity_curve);
|
||||
|
||||
// Tampilkan log trade (opsional)
|
||||
if (data.trades && data.trades.length > 0) {
|
||||
let logHtml = '<h4 class="text-lg font-semibold mt-6 mb-2">20 Trade Terakhir</h4><div class="text-xs font-mono border rounded p-2 bg-gray-50 max-h-64 overflow-y-auto">';
|
||||
data.trades.forEach(trade => {
|
||||
const profitClass = trade.profit_pips > 0 ? 'text-green-600' : 'text-red-600';
|
||||
logHtml += `<p>Entry: ${trade.entry.toFixed(4)} | Exit: ${trade.exit.toFixed(4)} | Profit: <span class="${profitClass}">${trade.profit_pips.toFixed(2)} pips</span> | Reason: ${trade.reason}</p>`;
|
||||
});
|
||||
logHtml += '</div>';
|
||||
resultsLog.innerHTML = logHtml;
|
||||
} else {
|
||||
resultsLog.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function displayEquityChart(equityData) {
|
||||
const ctx = document.getElementById('equity-chart').getContext('2d');
|
||||
if (equityChart) {
|
||||
equityChart.destroy(); // Hancurkan grafik lama sebelum membuat yang baru
|
||||
}
|
||||
equityChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: Array.from({ length: equityData.length }, (_, i) => i + 1), // Label 1, 2, 3, ...
|
||||
datasets: [{
|
||||
label: 'Equity Curve',
|
||||
data: equityData,
|
||||
borderColor: 'rgb(59, 130, 246)',
|
||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
pointRadius: 0,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: 'Pertumbuhan Modal (Equity Curve)' }
|
||||
},
|
||||
scales: { y: { beginAtZero: false } }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadStrategies();
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
document.getElementById('sidebar-toggle').addEventListener('click', function() {
|
||||
document.getElementById('sidebar').classList.toggle('collapsed');
|
||||
});
|
||||
|
||||
async function fetchCryptoData() {
|
||||
const tableBody = document.querySelector('tbody');
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/crypto');
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
|
||||
}
|
||||
const cryptos = await response.json();
|
||||
|
||||
if (!cryptos || cryptos.length === 0) {
|
||||
tableBody.innerHTML = '<tr><td colspan="5" class="p-4 text-center text-gray-500">Tidak ada data cryptocurrency yang tersedia.</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
const rowsHtml = cryptos.map(crypto => {
|
||||
const changeClass = crypto.change.startsWith('+') ? 'text-green-600' : 'text-red-600';
|
||||
return `
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap"><div class="flex items-center"><div class="font-medium text-gray-900">${crypto.name}</div><div class="text-sm text-gray-500 ml-2">${crypto.symbol}</div></div></td>
|
||||
<td class="px-6 py-4 whitespace-nowrap font-medium">${crypto.price}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap ${changeClass} font-medium">${crypto.change}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${crypto.market_cap}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right"><button class="bg-blue-600 text-white py-1 px-3 rounded-md text-sm font-medium hover:bg-blue-700">Trade</button></td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
tableBody.innerHTML = rowsHtml;
|
||||
} catch (error) {
|
||||
console.error('Gagal mengambil data crypto:', error);
|
||||
tableBody.innerHTML = '<tr><td colspan="5" class="p-4 text-center text-red-500">Gagal memuat data.</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', fetchCryptoData);
|
||||
setInterval(fetchCryptoData, 15000);
|
||||
@@ -0,0 +1,27 @@
|
||||
<!-- templates/500.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Terjadi Kesalahan Internal - QuantumBotX</title>
|
||||
<!-- Menggunakan versi Tailwind yang lebih modern jika memungkinkan, tapi kita samakan dengan 404.html -->
|
||||
<link href="https://cdn.tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans flex items-center justify-center h-screen">
|
||||
<div class="text-center">
|
||||
<h1 class="text-9xl font-bold text-red-500">500</h1>
|
||||
<h2 class="text-3xl font-semibold text-gray-800 mt-4">Terjadi Kesalahan Internal</h2>
|
||||
<p class="text-gray-600 mt-2">
|
||||
Maaf, terjadi masalah pada server kami. Tim kami telah diberitahu dan sedang menanganinya.
|
||||
</p>
|
||||
<div class="mt-8">
|
||||
<a href="{{ url_for('dashboard') }}" class="bg-blue-500 text-white px-6 py-3 rounded-lg shadow hover:bg-blue-600 transition">
|
||||
<i class="fas fa-home mr-2"></i>Kembali ke Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!-- templates/backtesting.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Backtester{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-4">Strategy Backtester</h2>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Kolom Konfigurasi -->
|
||||
<div class="lg:col-span-1 bg-white p-6 rounded-lg shadow">
|
||||
<form id="backtest-form">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label for="strategy-select" class="block text-sm font-medium text-gray-700">Pilih Strategi</label>
|
||||
<select id="strategy-select" name="strategy" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"></select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="data-file" class="block text-sm font-medium text-gray-700">Unggah Data Historis (CSV)</label>
|
||||
<input type="file" id="data-file" name="file" accept=".csv" class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100" required>
|
||||
</div>
|
||||
<div id="params-container" class="space-y-4 pt-4 border-t">
|
||||
<!-- Parameter akan dimuat di sini -->
|
||||
</div>
|
||||
<button type="submit" id="run-backtest-btn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700">
|
||||
Jalankan Backtest
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Kolom Hasil -->
|
||||
<div id="results-container" class="lg:col-span-2 bg-white p-6 rounded-lg shadow hidden">
|
||||
<h3 class="text-xl font-bold mb-4">Hasil Backtest</h3>
|
||||
<div id="results-summary" class="grid grid-cols-2 md:grid-cols-3 gap-4 mb-6"></div>
|
||||
<div class="mb-6">
|
||||
<canvas id="equity-chart"></canvas>
|
||||
</div>
|
||||
<div id="results-log"></div>
|
||||
</div>
|
||||
<div id="loading-spinner" class="lg:col-span-2 flex items-center justify-center hidden">
|
||||
<i class="fas fa-spinner fa-spin text-blue-500 text-4xl"></i>
|
||||
<p class="ml-4 text-gray-600">Menjalankan simulasi...</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/backtesting.js') }}"></script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Dashboard{% endblock %} - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
{% block head_extra %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- SIDEBAR -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'dashboard' %}active{% endif %}"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'trading_bots' %}active{% endif %}"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'portfolio' %}active{% endif %}"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/backtesting" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'backtesting' %}active{% endif %}"><i class="fas fa-vial"></i><span class="ml-3 sidebar-text">Backtester</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'history' %}active{% endif %}"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'settings' %}active{% endif %}"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'stocks' %}active{% endif %}"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50 {% if active_page == 'forex' %}active{% endif %}"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative">
|
||||
<input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..." />
|
||||
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600"><i class="fas fa-bell"></i><span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span></a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Ini adalah area di mana konten unik setiap halaman akan disuntikkan -->
|
||||
<main class="p-6">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Skrip yang dibutuhkan oleh semua halaman -->
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<!-- Blok untuk skrip spesifik halaman -->
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
+42
-102
@@ -1,108 +1,48 @@
|
||||
<!-- templates/bot_detail.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Detail Bot - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"/>
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text"><h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1><p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p></div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<!-- templates/bot_detail.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</div>
|
||||
<div class="ml-3 sidebar-text ">
|
||||
<p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p>
|
||||
<p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Konten Utama -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600"><i class="fas fa-bell"></i><span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span></a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% block title %}Detail Bot{% endblock %}
|
||||
|
||||
<!-- Konten Utama Halaman Detail Bot -->
|
||||
<main class="p-6">
|
||||
<!-- Header Halaman -->
|
||||
<div class="flex justify-between items-start mb-6 bg-white p-4 rounded-lg shadow">
|
||||
<div>
|
||||
<h2 id="bot-name-header" class="text-2xl font-bold text-gray-800">Memuat...</h2>
|
||||
<p id="bot-market-header" class="text-gray-600">Memuat detail bot...</p>
|
||||
</div>
|
||||
<div id="bot-status-badge" class="px-4 py-2 rounded-full text-sm font-semibold bg-gray-200 text-gray-800">Memuat Status...</div>
|
||||
</div>
|
||||
{% block content %}
|
||||
<!-- Header Halaman -->
|
||||
<div class="flex justify-between items-start mb-6 bg-white p-4 rounded-lg shadow">
|
||||
<div>
|
||||
<h2 id="bot-name-header" class="text-2xl font-bold text-gray-800">Memuat...</h2>
|
||||
<p id="bot-market-header" class="text-gray-600">Memuat detail bot...</p>
|
||||
</div>
|
||||
<div id="bot-status-badge" class="px-4 py-2 rounded-full text-sm font-semibold bg-gray-200 text-gray-800">Memuat Status...</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout Grid Utama -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Kolom Kiri (Log Aktivitas) -->
|
||||
<div class="lg:col-span-2 bg-white rounded-lg shadow">
|
||||
<div class="p-4 border-b"><h3 class="text-lg font-semibold text-gray-800">Log Aktivitas</h3></div>
|
||||
<div id="history-log-container" class="overflow-y-auto" style="max-height: 60vh;">
|
||||
<p class="text-center text-gray-500 p-4">Memuat riwayat...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kolom Kanan (Info & Analisis) -->
|
||||
<div class="space-y-6">
|
||||
|
||||
<div class="bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-2 mb-3">Parameter</h3>
|
||||
<div id="bot-parameters-container" class="text-sm space-y-2">
|
||||
<p class="text-center text-gray-500">Memuat...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-2 mb-3">Analisis Real-Time</h3>
|
||||
<div id="bot-analysis-container" class="text-sm space-y-2">
|
||||
<p class="text-center text-gray-500">Memuat...</p>
|
||||
</div>
|
||||
<div id="analysis-signal" class="mt-4 text-center font-bold text-lg p-2 rounded-md bg-gray-100 text-gray-600">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Layout Grid Utama -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Kolom Kiri (Log Aktivitas) -->
|
||||
<div class="lg:col-span-2 bg-white rounded-lg shadow">
|
||||
<div class="p-4 border-b"><h3 class="text-lg font-semibold text-gray-800">Log Aktivitas</h3></div>
|
||||
<div id="history-log-container" class="overflow-y-auto" style="max-height: 60vh;">
|
||||
<p class="text-center text-gray-500 p-4">Memuat riwayat...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bot_detail.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
<!-- Kolom Kanan (Info & Analisis) -->
|
||||
<div class="space-y-6">
|
||||
|
||||
<div class="bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-2 mb-3">Parameter</h3>
|
||||
<div id="bot-parameters-container" class="text-sm space-y-2">
|
||||
<p class="text-center text-gray-500">Memuat...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-2 mb-3">Analisis Real-Time</h3>
|
||||
<div id="bot-analysis-container" class="text-sm space-y-2">
|
||||
<p class="text-center text-gray-500">Memuat...</p>
|
||||
</div>
|
||||
<div id="analysis-signal" class="mt-4 text-center font-bold text-lg p-2 rounded-md bg-gray-100 text-gray-600">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/bot_detail.js') }}"></script>
|
||||
{% endblock %}
|
||||
@@ -1,94 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Cryptocurrency Market - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="{{ url_for('dashboard') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="{{ url_for('bots_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="{{ url_for('portfolio_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="{{ url_for('history_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="{{ url_for('settings_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="{{ url_for('crypto_page') }}" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="{{ url_for('stocks_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="{{ url_for('forex_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative"><input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..."><i class="fas fa-search absolute right-3 top-3 text-gray-400"></i></div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="{{ url_for('profile_page') }}" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Pasar Cryptocurrency</h2>
|
||||
<p class="text-gray-600">Data harga real-time dari pasar kripto global.</p>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Cari aset...">
|
||||
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Aset</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Perubahan 24j</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kap. Pasar</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="5" class="p-4 text-center text-gray-500">Memuat data...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/cryptocurrency.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
+46
-103
@@ -1,108 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Forex Market - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="{{ url_for('dashboard') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="{{ url_for('bots_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="{{ url_for('portfolio_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="{{ url_for('history_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="{{ url_for('settings_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="{{ url_for('crypto_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="{{ url_for('stocks_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="{{ url_for('forex_page') }}" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="{{ url_for('profile_page') }}" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative"><input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..."><i class="fas fa-search absolute right-3 top-3 text-gray-400"></i></div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Pasar Forex</h2>
|
||||
<p class="text-gray-600">Data harga real-time dari pasar valuta asing.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- templates/forex.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Pasangan</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Bid</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Ask</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Spread</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="forex-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="5" class="p-4 text-center text-gray-500">Memuat data forex...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% block title %}Forex Market{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Pasar Forex</h2>
|
||||
<p class="text-gray-600">Data harga real-time dari pasar valuta asing.</p>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div id="forex-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
|
||||
<div class="relative top-20 mx-auto p-5 border w-1/2 shadow-lg rounded-md bg-white">
|
||||
<div class="mt-3 text-center">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title"></h3>
|
||||
<div class="mt-2 px-7 py-3">
|
||||
<p class="text-sm text-gray-500" id="modal-content"></p>
|
||||
</div>
|
||||
<div class="items-center px-4 py-3">
|
||||
<button id="close-modal" class="px-4 py-2 bg-gray-500 text-white text-base font-medium rounded-md w-full shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Pasangan</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Bid</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Ask</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Spread</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="forex-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="5" class="p-4 text-center text-gray-500">Memuat data forex...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div id="forex-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
|
||||
<div class="relative top-20 mx-auto p-5 border w-1/2 shadow-lg rounded-md bg-white">
|
||||
<div class="mt-3 text-center">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title"></h3>
|
||||
<div class="mt-2 px-7 py-3">
|
||||
<p class="text-sm text-gray-500" id="modal-content"></p>
|
||||
</div>
|
||||
<div class="items-center px-4 py-3">
|
||||
<button id="close-modal" class="px-4 py-2 bg-gray-500 text-white text-base font-medium rounded-md w-full shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/forex.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/forex.js') }}"></script>
|
||||
{% endblock %}
|
||||
+33
-99
@@ -1,102 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Riwayat Transaksi - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">
|
||||
QT
|
||||
</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t"><a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<!-- Top Navigation -->
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="ml-4 relative">
|
||||
<input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots...">
|
||||
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- templates/history.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Riwayat Transaksi Global</h2>
|
||||
<p class="text-gray-600">Semua transaksi yang telah ditutup dari akun MetaTrader 5.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Simbol</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipe</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Volume</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Profit</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Waktu Penutupan</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Magic Number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="history-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<!-- Data akan dimuat di sini oleh JavaScript -->
|
||||
<tr><td colspan="6" class="p-4 text-center text-gray-500">Memuat riwayat...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% block title %}Riwayat Transaksi{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Riwayat Transaksi Global</h2>
|
||||
<p class="text-gray-600">Semua transaksi yang telah ditutup dari akun MetaTrader 5.</p>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Simbol</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipe</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Volume</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Profit</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Waktu Penutupan</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Magic Number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="history-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<!-- Data akan dimuat di sini oleh JavaScript -->
|
||||
<tr><td colspan="6" class="p-4 text-center text-gray-500">Memuat riwayat...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/history.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
+56
-121
@@ -1,127 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Dashboard - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}" />
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- SIDEBAR -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p>
|
||||
</div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p>
|
||||
</div>
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text">
|
||||
<p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p>
|
||||
<p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% extends "base.html" %}
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative">
|
||||
<input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..." />
|
||||
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600"><i class="fas fa-bell"></i><span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span></a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
|
||||
<main class="p-6">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800">Dashboard</h2>
|
||||
<p class="text-gray-600">Welcome back! Here's your trading overview.</p>
|
||||
</div>
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}" />
|
||||
{% endblock %}
|
||||
|
||||
<!-- STAT CARDS -->
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4 mb-6">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Total Saldo (Equity)</h3>
|
||||
<p id="total-equity" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Profit Hari Ini</h3>
|
||||
<p id="todays-profit" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Bot Aktif</h3>
|
||||
<p id="active-bots-count" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Total Bot</h3>
|
||||
<p id="total-bots-count" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
</div>
|
||||
{% block content %}
|
||||
<div class="mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800">Dashboard</h2>
|
||||
<p class="text-gray-600">Welcome back! Here's your trading overview.</p>
|
||||
</div>
|
||||
|
||||
<!-- GRAFIK -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<h3 class="text-md font-semibold text-gray-700 mb-2">Grafik Harga EUR/USD</h3>
|
||||
<div class="chart-container"><canvas id="priceChart" height="100"></canvas></div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<h3 class="text-md font-semibold text-gray-700 mb-2">RSI EUR/USD (H1)</h3>
|
||||
<div class="chart-container"><canvas id="rsiChart" height="100"></canvas></div>
|
||||
</div>
|
||||
|
||||
<!-- BOT AKTIF -->
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="p-6 border-b">
|
||||
<h3 class="text-lg font-semibold text-gray-800">Active Trading Bots</h3>
|
||||
</div>
|
||||
<div id="active-bots-list" class="divide-y">
|
||||
<p class="p-4 text-gray-500">Memuat daftar bot...</p>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/trading_bots" class="block w-full text-center text-blue-600 font-medium hover:text-blue-800 transition">View All Bots</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<!-- STAT CARDS -->
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4 mb-6">
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Total Saldo (Equity)</h3>
|
||||
<p id="total-equity" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Profit Hari Ini</h3>
|
||||
<p id="todays-profit" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Bot Aktif</h3>
|
||||
<p id="active-bots-count" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-sm font-medium text-gray-500">Total Bot</h3>
|
||||
<p id="total-bots-count" class="mt-1 text-3xl font-semibold text-gray-800"><i class="fas fa-spinner fa-spin text-gray-400"></i></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
<!-- GRAFIK -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<h3 class="text-md font-semibold text-gray-700 mb-2">Grafik Harga EUR/USD</h3>
|
||||
<div class="chart-container"><canvas id="priceChart" height="100"></canvas></div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<h3 class="text-md font-semibold text-gray-700 mb-2">RSI EUR/USD (H1)</h3>
|
||||
<div class="chart-container"><canvas id="rsiChart" height="100"></canvas></div>
|
||||
</div>
|
||||
|
||||
<!-- BOT AKTIF -->
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<div class="p-6 border-b">
|
||||
<h3 class="text-lg font-semibold text-gray-800">Active Trading Bots</h3>
|
||||
</div>
|
||||
<div id="active-bots-list" class="divide-y">
|
||||
<p class="p-4 text-gray-500">Memuat daftar bot...</p>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/trading_bots" class="block w-full text-center text-blue-600 font-medium hover:text-blue-800 transition">View All Bots</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,75 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Notifikasi - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative"><input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..."><i class="fas fa-search absolute right-3 top-3 text-gray-400"></i></div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Notifikasi</h2>
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<!-- Kontainer ini akan diisi oleh JavaScript -->
|
||||
<div id="notifications-container" class="divide-y divide-gray-200">
|
||||
<p class="p-6 text-center text-gray-500">Memuat notifikasi...</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<!-- templates/notifications.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Notifikasi{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Notifikasi</h2>
|
||||
<div class="bg-white rounded-lg shadow">
|
||||
<!-- Kontainer ini akan diisi oleh JavaScript -->
|
||||
<div id="notifications-container" class="divide-y divide-gray-200">
|
||||
<p class="p-6 text-center text-gray-500">Memuat notifikasi...</p>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/notifications.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/notifications.js') }}"></script>
|
||||
{% endblock %}
|
||||
+53
-99
@@ -1,102 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Portfolio Real-Time - QuantumBotX</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text"><h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1><p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p></div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<!-- templates/portfolio.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</div>
|
||||
<div class="ml-3 sidebar-text ">
|
||||
<p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p>
|
||||
<p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Konten Utama -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600"><i class="fas fa-bell"></i><span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span></a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Portfolio Real-Time</h2>
|
||||
<p class="text-gray-600">Posisi trading yang sedang terbuka di akun MetaTrader 5.</p>
|
||||
</div>
|
||||
<div id="portfolio-summary" class="text-right">
|
||||
<!-- Summary akan dimuat di sini -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 mb-2">Grafik Profit/Loss Terbuka (Real-Time)</h3>
|
||||
<div style="height: 250px;"><canvas id="pnlChart"></canvas></div>
|
||||
</div>
|
||||
{% block title %}Portfolio Real-Time{% endblock %}
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Simbol</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipe</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Volume</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Buka</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Profit/Loss</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Magic Number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="portfolio-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="6" class="p-4 text-center text-gray-500">Memuat posisi terbuka...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% block head_extra %}
|
||||
<!--
|
||||
Chart.js sudah ada di base.html. Kita hanya perlu menambahkan adapter tanggal.
|
||||
Namun, lebih baik memuat semua JS di akhir, jadi kita akan letakkan ini di blok 'scripts'.
|
||||
Blok ini dibiarkan sebagai contoh jika butuh CSS khusus.
|
||||
-->
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Portfolio Real-Time</h2>
|
||||
<p class="text-gray-600">Posisi trading yang sedang terbuka di akun MetaTrader 5.</p>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/portfolio.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
<div id="portfolio-summary" class="text-right">
|
||||
<!-- Summary akan dimuat di sini -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 bg-white rounded-lg shadow p-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800 mb-2">Grafik Profit/Loss Terbuka (Real-Time)</h3>
|
||||
<div style="height: 250px;"><canvas id="pnlChart"></canvas></div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Simbol</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipe</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Volume</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga Buka</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Profit/Loss</th>
|
||||
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Magic Number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="portfolio-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="6" class="p-4 text-center text-gray-500">Memuat posisi terbuka...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<!--
|
||||
Memuat adapter tanggal untuk Chart.js yang diperlukan di halaman ini,
|
||||
diikuti dengan skrip logika halaman portfolio.
|
||||
-->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/portfolio.js') }}"></script>
|
||||
{% endblock %}
|
||||
+45
-102
@@ -1,106 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Profil - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
<div class="ml-4 relative"><input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots..."><i class="fas fa-search absolute right-3 top-3 text-gray-400"></i></div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Profil Saya</h2>
|
||||
<!-- templates/profile.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="bg-white p-6 rounded-lg shadow text-center">
|
||||
<div class="w-24 h-24 rounded-full bg-gray-200 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fas fa-user fa-3x text-gray-500"></i>
|
||||
</div>
|
||||
<h3 id="profile-display-name" class="text-xl font-bold text-gray-800">Memuat...</h3>
|
||||
<p class="text-sm text-gray-500">Developer</p>
|
||||
<p id="profile-join-date" class="text-xs text-gray-400 mt-2">Bergabung sejak: Juli 2025</p>
|
||||
</div>
|
||||
</div>
|
||||
{% block title %}Profil{% endblock %}
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">Detail Akun</h3>
|
||||
<form id="profile-form" class="space-y-4">
|
||||
<div>
|
||||
<label for="profile-name" class="text-sm font-medium text-gray-700">Nama Lengkap</label>
|
||||
<input type="text" id="profile-name" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="profile-email" class="text-sm font-medium text-gray-700">Alamat Email</label>
|
||||
<input type="email" id="profile-email" class="mt-1 block w-full px-3 py-2 bg-gray-100 border border-gray-300 rounded-md" required>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4 pt-6">Keamanan</h3>
|
||||
<div>
|
||||
<label for="profile-password" class="text-sm font-medium text-gray-700">Ganti Password (kosongkan jika tidak ingin diubah)</label>
|
||||
<input type="password" id="profile-password" placeholder="••••••••" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm">
|
||||
</div>
|
||||
<div class="flex justify-end pt-4">
|
||||
<button type="submit" class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700">Simpan Perubahan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
{% block content %}
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Profil Saya</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="md:col-span-1">
|
||||
<div class="bg-white p-6 rounded-lg shadow text-center">
|
||||
<div class="w-24 h-24 rounded-full bg-gray-200 flex items-center justify-center mx-auto mb-4">
|
||||
<i class="fas fa-user fa-3x text-gray-500"></i>
|
||||
</div>
|
||||
<h3 id="profile-display-name" class="text-xl font-bold text-gray-800">Memuat...</h3>
|
||||
<p class="text-sm text-gray-500">Developer</p>
|
||||
<p id="profile-join-date" class="text-xs text-gray-400 mt-2">Bergabung sejak: Juli 2025</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/profile.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">Detail Akun</h3>
|
||||
<form id="profile-form" class="space-y-4">
|
||||
<div>
|
||||
<label for="profile-name" class="text-sm font-medium text-gray-700">Nama Lengkap</label>
|
||||
<input type="text" id="profile-name" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="profile-email" class="text-sm font-medium text-gray-700">Alamat Email</label>
|
||||
<input type="email" id="profile-email" class="mt-1 block w-full px-3 py-2 bg-gray-100 border border-gray-300 rounded-md" required>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4 pt-6">Keamanan</h3>
|
||||
<div>
|
||||
<label for="profile-password" class="text-sm font-medium text-gray-700">Ganti Password (kosongkan jika tidak ingin diubah)</label>
|
||||
<input type="password" id="profile-password" placeholder="••••••••" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm">
|
||||
</div>
|
||||
<div class="flex justify-end pt-4">
|
||||
<button type="submit" class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700">Simpan Perubahan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/profile.js') }}"></script>
|
||||
{% endblock %}
|
||||
+28
-131
@@ -1,137 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Settings - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">
|
||||
QT
|
||||
<!-- templates/settings.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Settings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Pengaturan</h2>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">Profil</h3>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700">Nama Lengkap</label>
|
||||
<input type="text" value="Reynov Christian" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
||||
</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700">Alamat Email</label>
|
||||
<input type="email" value="contact@chrisnov.com" class="mt-1 block w-full px-3 py-2 bg-gray-100 border border-gray-300 rounded-md shadow-sm" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p>
|
||||
</div>
|
||||
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
<span class="ml-3 sidebar-text">Dashboard</span>
|
||||
</a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-robot"></i>
|
||||
<span class="ml-3 sidebar-text">Trading Bots</span>
|
||||
</a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-wallet"></i>
|
||||
<span class="ml-3 sidebar-text">Portfolio</span>
|
||||
</a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-history"></i>
|
||||
<span class="ml-3 sidebar-text">History</span>
|
||||
</a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600">
|
||||
<i class="fas fa-cog"></i>
|
||||
<span class="ml-3 sidebar-text">Settings</span>
|
||||
</a>
|
||||
|
||||
<div class="px-4 mt-8 mb-4">
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p>
|
||||
</div>
|
||||
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fab fa-bitcoin"></i>
|
||||
<span class="ml-3 sidebar-text">Cryptocurrency</span>
|
||||
</a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-chart-bar"></i>
|
||||
<span class="ml-3 sidebar-text">Stocks</span>
|
||||
</a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
<span class="ml-3 sidebar-text">Forex</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</div>
|
||||
<div class="ml-3 sidebar-text ">
|
||||
<p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p>
|
||||
<p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p>
|
||||
</div>
|
||||
</a>
|
||||
<button class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700">Simpan Perubahan</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<!-- Top Navigation -->
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="ml-4 relative">
|
||||
<input type="text" class="w-64 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Search markets, bots...">
|
||||
<i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span>
|
||||
</a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800 mb-6">Pengaturan</h2>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div class="lg:col-span-2 space-y-6">
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">Profil</h3>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700">Nama Lengkap</label>
|
||||
<input type="text" value="Reynov Christian" class="mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-sm font-medium text-gray-700">Alamat Email</label>
|
||||
<input type="email" value="contact@chrisnov.com" class="mt-1 block w-full px-3 py-2 bg-gray-100 border border-gray-300 rounded-md shadow-sm" readonly>
|
||||
</div>
|
||||
<button class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700">Simpan Perubahan</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">API Keys Bursa</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<h3 class="text-lg font-semibold text-gray-800 border-b pb-4 mb-4">API Keys Bursa</h3>
|
||||
<!-- Konten untuk API Keys bisa ditambahkan di sini -->
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||
{% endblock %}
|
||||
+45
-94
@@ -1,100 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Stocks Market - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text">
|
||||
<h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1>
|
||||
<p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="{{ url_for('dashboard') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="{{ url_for('bots_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="{{ url_for('portfolio_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="{{ url_for('history_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="{{ url_for('settings_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
<a href="{{ url_for('crypto_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="{{ url_for('stocks_page') }}" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="{{ url_for('forex_page') }}" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="{{ url_for('profile_page') }}" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center"><i class="fas fa-user text-gray-600"></i></div>
|
||||
<div class="ml-3 sidebar-text "><p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p><p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Pasar Saham</h2>
|
||||
<p class="text-gray-600">Data harga real-time dari pasar saham global.</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- templates/stocks.html (Setelah Refactor) -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Saham</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Perubahan 24j</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Waktu</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stocks-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="5" class="p-4 text-center text-gray-500">Memuat data saham...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% block title %}Stocks Market{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Pasar Saham</h2>
|
||||
<p class="text-gray-600">Data harga real-time dari pasar saham global.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div id="stock-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
|
||||
<div class="relative top-20 mx-auto p-5 border w-1/2 shadow-lg rounded-md bg-white">
|
||||
<div class="mt-3 text-center">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title"></h3>
|
||||
<div class="mt-2 px-7 py-3">
|
||||
<p class="text-sm text-gray-500" id="modal-content"></p>
|
||||
</div>
|
||||
<div class="items-center px-4 py-3">
|
||||
<button id="close-modal" class="px-4 py-2 bg-gray-500 text-white text-base font-medium rounded-md w-full shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Saham</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Perubahan 24j</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Waktu</th>
|
||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stocks-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<tr><td colspan="5" class="p-4 text-center text-gray-500">Memuat data saham...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div id="stock-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden">
|
||||
<div class="relative top-20 mx-auto p-5 border w-1/2 shadow-lg rounded-md bg-white">
|
||||
<div class="mt-3 text-center">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title"></h3>
|
||||
<div class="mt-2 px-7 py-3">
|
||||
<p class="text-sm text-gray-500" id="modal-content"></p>
|
||||
</div>
|
||||
<div class="items-center px-4 py-3">
|
||||
<button id="close-modal" class="px-4 py-2 bg-gray-500 text-white text-base font-medium rounded-md w-full shadow-sm hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-300">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/stocks.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/stocks.js') }}"></script>
|
||||
{% endblock %}
|
||||
+40
-93
@@ -1,94 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Trading Bots - QuantumBotX</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body class="bg-gray-100 font-sans">
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<div id="sidebar" class="sidebar bg-white w-64 shadow-lg flex flex-col">
|
||||
<div class="p-4 flex items-center border-b">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white font-bold">QT</div>
|
||||
<div class="ml-3 logo-text"><h1 class="text-xl font-bold text-gray-800">QuantumBotX</h1><p class="text-xs text-gray-500">The AI-Powered Strategy Platform</p></div>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<nav class="mt-6">
|
||||
<div class="px-4 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Navigation</p></div>
|
||||
<a href="/" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-line"></i><span class="ml-3 sidebar-text">Dashboard</span></a>
|
||||
<a href="/trading_bots" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-robot"></i><span class="ml-3 sidebar-text">Trading Bots</span></a>
|
||||
<a href="/portfolio" class="nav-item flex items-center px-4 py-3 text-blue-600 bg-blue-50 border-r-4 border-blue-600"><i class="fas fa-wallet"></i><span class="ml-3 sidebar-text">Portfolio</span></a>
|
||||
<a href="/history" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-history"></i><span class="ml-3 sidebar-text">History</span></a>
|
||||
<a href="/settings" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-cog"></i><span class="ml-3 sidebar-text">Settings</span></a>
|
||||
{% extends "base.html" %}
|
||||
|
||||
<div class="px-4 mt-8 mb-4"><p class="text-xs font-semibold text-gray-500 uppercase tracking-wider sidebar-text">Market Data</p></div>
|
||||
|
||||
<a href="/cryptocurrency" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fab fa-bitcoin"></i><span class="ml-3 sidebar-text">Cryptocurrency</span></a>
|
||||
<a href="/stocks" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-chart-bar"></i><span class="ml-3 sidebar-text">Stocks</span></a>
|
||||
<a href="/forex" class="nav-item flex items-center px-4 py-3 text-gray-600 hover:text-blue-600 hover:bg-blue-50"><i class="fas fa-exchange-alt"></i><span class="ml-3 sidebar-text">Forex</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="p-4 border-t">
|
||||
<a href="/profile" class="flex items-center group">
|
||||
<div class="w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center">
|
||||
<i class="fas fa-user text-gray-600"></i>
|
||||
</div>
|
||||
<div class="ml-3 sidebar-text ">
|
||||
<p class="text-sm font-medium text-gray-800 group-hover:text-blue-600">Reynov Christian</p>
|
||||
<p class="text-xs text-gray-500 group-hover:text-blue-600">Developer</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Konten Utama -->
|
||||
<div class="flex-1 overflow-auto">
|
||||
<header class="bg-white shadow-sm">
|
||||
<div class="flex items-center justify-between px-6 py-4">
|
||||
<div class="flex items-center">
|
||||
<button id="sidebar-toggle" class="text-gray-500 focus:outline-none"><i class="fas fa-bars"></i></button>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<a href="/notifications" class="relative text-gray-500 hover:text-blue-600"><i class="fas fa-bell"></i><span id="notification-dot" class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500 hidden"></span></a>
|
||||
<a href="/profile" class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center hover:bg-gray-300"><i class="fas fa-user text-gray-600"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="p-6">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Trading Bots</h2>
|
||||
<p class="text-gray-600">Kelola semua bot trading aktif dan non-aktif Anda.</p>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<button id="start-all-btn" class="bg-green-500 text-white py-2 px-4 rounded-lg font-medium hover:bg-green-600 transition flex items-center" title="Jalankan semua bot yang dijeda">
|
||||
<i class="fas fa-play mr-2"></i> Start All
|
||||
</button>
|
||||
<button id="stop-all-btn" class="bg-red-500 text-white py-2 px-4 rounded-lg font-medium hover:bg-red-600 transition flex items-center" title="Hentikan semua bot yang aktif">
|
||||
<i class="fas fa-stop mr-2"></i> Stop All
|
||||
</button>
|
||||
<button id="create-bot-btn" class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700 transition flex items-center"><i class="fas fa-plus mr-2"></i> Buat Bot Baru</button>
|
||||
</div>
|
||||
</div>
|
||||
{% block title %}Trading Bots{% endblock %}
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nama / Pasar</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Parameter</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Konfigurasi</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
||||
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="bots-table-body" class="bg-white divide-y divide-gray-200"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Header Halaman: Judul di kiri, tombol di kanan -->
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Trading Bots</h2>
|
||||
<p class="text-gray-600">Kelola semua bot dan strategi Anda.</p>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<button id="start-all-btn" class="bg-green-500 text-white py-2 px-4 rounded-lg font-medium hover:bg-green-600 transition flex items-center" title="Jalankan semua bot yang dijeda">
|
||||
<i class="fas fa-play mr-2"></i> Start All</button>
|
||||
<button id="stop-all-btn" class="bg-red-500 text-white py-2 px-4 rounded-lg font-medium hover:bg-red-600 transition flex items-center" title="Hentikan semua bot yang aktif">
|
||||
<i class="fas fa-stop mr-2"></i> Stop All</button>
|
||||
<button id="create-bot-btn" class="bg-blue-600 text-white py-2 px-4 rounded-lg font-medium hover:bg-blue-700 transition flex items-center"><i class="fas fa-plus mr-2"></i> Buat Bot Baru</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200" aria-label="Trading Bots Table">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nama / Pasar</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Parameter</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Konfigurasi</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
||||
<th scope="col" class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="bots-table-body" class="bg-white divide-y divide-gray-200"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Modal untuk Membuat/Mengedit Bot -->
|
||||
<div id="create-bot-modal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full flex items-center justify-center z-50 p-4">
|
||||
<!-- PERBAIKAN: Panel modal kini menggunakan flexbox vertikal dan tinggi maksimal -->
|
||||
@@ -173,7 +119,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/trading_bots.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/trading_bots.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user