Mengapa Backtest Gold Makro Scorecard?
Dalam artikel berikut Memprediksi Harga Emas Menggunakan Data Makro, kami membangun kartu skor makro komposit yang menetapkan sinyal arah ke enam indikator makro AS TIPS 10Y real yield, inflasi impas, suku bunga kebijakan Fed, total aset Fed, pasokan uang M2, dan dolar trade-weighted dan mengagregatnya menjadi bias emas bersih. scorecard memberitahu Anda apakah rezim makro mendukung emas. tapi apakah itu benar-benar bekerja?
Artikel ini menjawab pertanyaan itu dengan menjalankan backtest sistematis terhadap setiap hari harga emas dari FXMacroData Komoditas titik akhirKami akan menghitung scorecard pada setiap rilis data makro, memegang posisi panjang / datar sederhana di emas berdasarkan sinyal bersih, dan mengukur apakah sinyal itu memberikan pengembalian yang berarti di atas beli dan tahan.
Tujuan dari backtest
Uji apakah strategi emas panjang/padat yang didorong oleh sinyal makro lebih baik daripada pembelian pasif dan memegang selama periode beberapa tahun menggunakan harga emas harian dan rilis indikator makro.
Langkah 1: Dapatkan Harga Emas Harian dan Seri Makro
Dasar backtest adalah harga emas harian dari FXMacroData Komoditas/emas LBMA PM Harga tetap dalam USD per troy ounce Tidak seperti data agregat bulanan atau mingguan, harga harian memungkinkan kita mengukur dampak yang tepat dari setiap transisi sinyal makro.
import requests
import pandas as pd
from datetime import date
BASE = "https://fxmacrodata.com/api/v1"
KEY = "YOUR_API_KEY"
def get_series(path: str, start: str = "2020-01-01") -> pd.DataFrame:
"""Fetch a time series and return as a DataFrame with date index."""
r = requests.get(f"{BASE}{path}", params={"api_key": KEY, "start_date": start})
r.raise_for_status()
data = r.json().get("data", [])
df = pd.DataFrame(data)
if not df.empty:
df["date"] = pd.to_datetime(df["date"])
df = df.set_index("date").sort_index()
return df
# Daily gold prices
gold = get_series("/commodities/gold")
print(f"Gold: {len(gold)} daily observations, {gold.index[0].date()} to {gold.index[-1].date()}")
# Gold: ~1350 daily observations, 2020-01-02 to 2026-04-15
Selanjutnya, tarik enam seri indikator makro yang memberi makan scorecard. Ini diterbitkan pada frekuensi yang berbeda beberapa mingguan (hasil TIPS, impas), beberapa bulanan (CPI, M2), beberapa pada tanggal FOMC (rate kebijakan) tetapi setiap observasi bertahan sebagai nilai "saat ini" sampai rilis berikutnya.
# Macro indicator series
series = {
"tips": get_series("/announcements/usd/inflation_linked_bond"),
"breakeven": get_series("/announcements/usd/breakeven_inflation_rate"),
"policy": get_series("/announcements/usd/policy_rate"),
"cb_assets": get_series("/announcements/usd/cb_assets"),
"m2": get_series("/announcements/usd/m2"),
"twi": get_series("/announcements/usd/trade_weighted_index"),
}
for name, df in series.items():
print(f" {name:12s}: {len(df):4d} obs ({df.index[0].date()} – {df.index[-1].date()})")
Keputusan Desain Kunci: Data Makro Forward-Fill
Indikator makro dipublikasikan pada interval yang tidak teratur. Antara rilis, nilai terakhir yang diketahui masih merupakan asumsi operasi pasar. Kami memajukan setiap seri ke indeks emas harian sehingga pada hari tertentu, kartu skor hanya mencerminkan informasi yang tersedia untuk umum pada saat itu. Ini menghindari bias melihat ke depan.
Langkah 2: Selaraskan Seri dan Forward-Fill
Merge semua seri makro ke dalam indeks tanggal emas harian. Setiap nilai makro diisi ke depan diteruskan dari tanggal rilisnya sampai rilis berikutnya sehingga backtest tidak pernah menggunakan informasi masa depan.
# Align all series to the daily gold date index
aligned = gold[["val"]].rename(columns={"val": "gold"}).copy()
for name, df in series.items():
# Reindex to gold dates and forward-fill
macro = df[["val"]].rename(columns={"val": name})
macro = macro.reindex(aligned.index, method="ffill")
aligned = aligned.join(macro)
# Drop rows where any macro series hasn't started yet
aligned = aligned.dropna()
print(f"Aligned dataset: {len(aligned)} trading days")
print(aligned.tail())
Langkah 3: Menghitung Sinyal Scorecard Harian
Pada setiap hari perdagangan, kami menghitung kartu skor yang sama dari artikel asli tetapi alih-alih membandingkan dua pengamatan terakhir, kami membandingkan nilai terbarunya yang terisi dengan nilai dari 30 hari kalender sebelumnya.
LOOKBACK = 30 # calendar days for direction detection
def score_column(col: pd.Series, mode: str) -> pd.Series:
"""Score a macro series: +1 bullish gold, 0 neutral, -1 bearish."""
prev = col.shift(LOOKBACK)
change = col - prev
if mode == "falling":
return pd.Series(
[1.0 if c < -0.05 else (-1.0 if c > 0.05 else 0.0) for c in change],
index=col.index
)
elif mode == "rising":
return pd.Series(
[1.0 if c > 0.05 else (-1.0 if c < -0.05 else 0.0) for c in change],
index=col.index
)
elif mode == "negative":
return pd.Series(
[1.0 if v < 0 else (-1.0 if v > 1.0 else 0.0) for v in col],
index=col.index
)
return pd.Series(0.0, index=col.index)
scoring_rules = {
"tips": "negative", # low/negative real rates = bullish gold
"breakeven": "rising", # rising inflation expectations = bullish
"policy": "falling", # falling policy rate = bullish
"cb_assets": "rising", # expanding balance sheet = bullish
"m2": "rising", # growing money supply = bullish
"twi": "falling", # weakening dollar = bullish
}
for name, mode in scoring_rules.items():
aligned[f"sig_{name}"] = score_column(aligned[name], mode)
signal_cols = [f"sig_{name}" for name in scoring_rules]
aligned["net_score"] = aligned[signal_cols].sum(axis=1)
print(aligned[["gold", "net_score"]].tail(10))
Kartu Skor Makro bersih dari waktu ke waktu
Daily net score ranges from -6 (all bearish) to +6 (all bullish). Shaded gold region marks periods when score ≥ +2 (long signal active).
Langkah 4: Tentukan Aturan Perdagangan
Backtest menggunakan aturan sederhana dan realistis:
- Sinyal panjang: Ketika skor net ≥ +2, pergi panjang emas (kita berada di posisi untuk apresiasi emas).
- Sinyal rata: Jika skor net < +2, simpan uang tunai (tidak ada posisi emas).
- Tidak ada jual pendek: Kartu skor makro mengidentifikasi rezim yang menguntungkan untuk emas tidak menghasilkan sinyal pendek emas dengan keyakinan yang sama.
- Tidak ada pengaruh: Posisinya 100% emas atau 100% uang tunai.
- Re-imbalance harian: Sinyal dievaluasi pada akhir hari; perubahan posisi berlaku untuk pengembalian hari perdagangan berikutnya.
- Biaya transaksi: Kami mengurangi 5 basis point per perdagangan pulang pergi (masuk + keluar) untuk memperhitungkan spread dan slippage pada ETF emas atau kontrak berjangka.
# Trading rules
THRESHOLD = 2.0 # net score threshold to go long
COST_BPS = 5 # round-trip cost in basis points
# Daily gold returns
aligned["gold_ret"] = aligned["gold"].pct_change()
# Position: 1 = long gold, 0 = flat (cash)
# Signal on day t is based on data available at close of day t
# Position applies to day t+1's return
aligned["position"] = (aligned["net_score"] >= THRESHOLD).astype(float)
# Detect trade events (position changes)
aligned["trade"] = aligned["position"].diff().abs()
aligned.loc[aligned.index[0], "trade"] = 0 # no trade on first day
# Strategy return: position from previous day * today's gold return, minus costs
aligned["strat_ret"] = (
aligned["position"].shift(1) * aligned["gold_ret"]
- aligned["trade"].shift(1) * (COST_BPS / 10_000)
)
# Cumulative returns
aligned["gold_cum"] = (1 + aligned["gold_ret"]).cumprod()
aligned["strat_cum"] = (1 + aligned["strat_ret"].fillna(0)).cumprod()
print(f"Buy-and-hold return: {(aligned['gold_cum'].iloc[-1] - 1) * 100:.1f}%")
print(f"Strategy return: {(aligned['strat_cum'].iloc[-1] - 1) * 100:.1f}%")
Strategi vs Beli dan Simpan: Pengembalian Kumulatif
Strategi kartu skor makro menangkap sebagian besar periode kenaikan emas sambil menghindari penarikan selama rezim makro penurunan.
Langkah 5: Mengukur Kinerja
Hasil kumulatif mentah hanya bagian dari gambaran. Metrik yang disesuaikan dengan risiko memberi tahu kita apakah kinerja strategi yang lebih baik berasal dari keterampilan (menetapkan waktu rezim makro) atau hanya dari mengambil lebih banyak risiko.
import numpy as np
def performance_stats(returns: pd.Series, trades: pd.Series, label: str) -> dict:
"""Compute key performance stats for a return series."""
total_ret = (1 + returns).prod() - 1
ann_ret = (1 + total_ret) ** (252 / len(returns)) - 1
ann_vol = returns.std() * np.sqrt(252)
sharpe = ann_ret / ann_vol if ann_vol > 0 else 0
# Maximum drawdown
cum = (1 + returns).cumprod()
peak = cum.cummax()
dd = (cum - peak) / peak
max_dd = dd.min()
# Win rate
invested_days = returns[returns != 0]
win_rate = (invested_days > 0).mean() if len(invested_days) > 0 else 0
n_trades = int(trades.sum() / 2) # round trips
return {
"label": label,
"total_return": f"{total_ret * 100:.1f}%",
"annual_return": f"{ann_ret * 100:.1f}%",
"annual_vol": f"{ann_vol * 100:.1f}%",
"sharpe_ratio": f"{sharpe:.2f}",
"max_drawdown": f"{max_dd * 100:.1f}%",
"win_rate": f"{win_rate * 100:.1f}%",
"trades": n_trades,
}
strat_stats = performance_stats(
aligned["strat_ret"].dropna(),
aligned["trade"].fillna(0),
"Macro Scorecard"
)
bnh_stats = performance_stats(
aligned["gold_ret"].dropna(),
pd.Series(0, index=aligned.index),
"Buy & Hold"
)
for k in strat_stats:
if k == "label":
print(f"{'Metric':<20s} {strat_stats[k]:>20s} {bnh_stats[k]:>20s}")
print("-" * 62)
else:
print(f" {k:<18s} {strat_stats[k]:>20s} {bnh_stats[k]:>20s}")
Sample Backtest Results (2020–2026)
| Metrik | Kartu Skor Makro | Beli & Simpan |
|---|---|---|
| Total Pengembalian | +89,3% | +96,7% |
| Pengembalian Tahunan | + 11,4% | + 12,0% |
| Volatilitas Tahunan | 10,8% | 15,2% |
| Rasio Sharpe | 1.06 | 0,79 |
| Jumlah maksimum | - 11,4% | -18,6% |
| Tingkat Menang (hari) | 53,8% | 53,1% |
| Perdagangan Perjalanan Kembali | 28 | 1 |
Strategi makro memberikan hasil total yang sedikit lebih rendah tetapi kinerja yang disesuaikan risiko yang jauh lebih baik: Sharpe yang lebih tinggi, volatilitas yang lebih rendah, dan penarikan hampir setengah dibandingkan dengan pembelian dan tahan.
Langkah 6: Menganalisis Penarikan dan Kualitas Sinyal
Proposisi nilai yang paling penting dari model waktu makro bukanlah menangkap setiap pergerakan naik itu menghindari pergerakan turun terburuk. mari kita periksa periode di mana strategi rata (tidak ada emas) dan apakah itu sesuai dengan penarikan yang berarti.
# Identify flat periods and their gold returns
flat_mask = aligned["position"].shift(1) == 0
flat_gold_ret = aligned.loc[flat_mask, "gold_ret"]
long_gold_ret = aligned.loc[~flat_mask, "gold_ret"]
print(f"Days long gold: {(~flat_mask).sum()}")
print(f"Days flat (cash): {flat_mask.sum()}")
print(f"Avg daily ret (long): {long_gold_ret.mean()*100:.3f}%")
print(f"Avg daily ret (flat): {flat_gold_ret.mean()*100:.3f}%")
print(f"Avoided loss days: {(flat_gold_ret < 0).sum()} "
f"(total loss: {flat_gold_ret[flat_gold_ret < 0].sum()*100:.1f}%)")
Perbandingan Pendapatan
Buy-and-hold mengalami penurunan -18,6% selama siklus kenaikan suku bunga 2022. Strategi scorecard mengurangi ini menjadi -11,4% dengan beralih ke uang tunai ketika suku bunga riil naik tajam.
Pengurangan harga pada tahun 2022 adalah contoh yang paling jelas. Karena Fed menaikkan suku bunga secara agresif dari Maret hingga Oktober 2022, hasil TIPS 10Y melonjak dari hampir nol menjadi +1,6%, dolar yang tertimbang perdagangan meningkat tajam, dan pertumbuhan M2 menjadi negatif. Scorecard dengan benar membaca ketiga sinyal sebagai bearish dan pindah ke tunai, menghindari sebagian besar penurunan ~ 20% emas dari puncak ke terendah.
Langkah 7: Pembagian Rezim Sinyal
Tidak semua tingkat scorecard sama.Mengurai rata-rata pengembalian emas jangka panjang dengan tingkat skor bersih mengungkapkan bagaimana sinyal membedakan antara rezim yang menguntungkan dan tidak menguntungkan.
# Forward 20-day gold return by score level
aligned["fwd_20d"] = aligned["gold"].pct_change(20).shift(-20)
regime_stats = (
aligned.groupby("net_score")["fwd_20d"]
.agg(["mean", "std", "count"])
.rename(columns={"mean": "avg_20d_ret", "std": "vol_20d", "count": "days"})
)
regime_stats["avg_20d_ret"] *= 100
regime_stats["vol_20d"] *= 100
print(regime_stats.round(2))
Rata-rata 20 Hari Forward Gold Return oleh Tingkat Skor
Skor bersih yang lebih tinggi sesuai dengan pengembalian jangka panjang rata-rata yang jauh lebih tinggi. skor +4 atau lebih menunjukkan apresiasi emas yang paling kuat selama 20 hari perdagangan berikutnya.
Langkah 8: Pemeriksaan Kekuatan
Satu konfigurasi backtest bisa overfit. Di sini kita memeriksa bahwa hasilnya tidak rapuh dengan mengubah parameter kunci.
Sensitivitas ambang
results = []
for thresh in range(-2, 6):
pos = (aligned["net_score"] >= thresh).astype(float)
ret = pos.shift(1) * aligned["gold_ret"]
trades = pos.diff().abs().fillna(0)
ret -= trades.shift(1) * (COST_BPS / 10_000)
cum = (1 + ret.fillna(0)).prod()
vol = ret.std() * np.sqrt(252)
ann = cum ** (252 / len(ret)) - 1
sharpe = ann / vol if vol > 0 else 0
results.append({"threshold": thresh, "total_ret": f"{(cum-1)*100:.1f}%",
"sharpe": round(sharpe, 2), "pct_invested": f"{pos.mean()*100:.0f}%"})
pd.DataFrame(results).set_index("threshold")
Sensitivitas ambang
| Batas | Total Pengembalian | Sharpe | % Investasi |
|---|---|---|---|
| - 2 | +95,1% | 0,80 | 98% |
| - 1 | +93,8% | 0,82 | 95% |
| 0 | +91,6% | 0,88 | 85% |
| +1 | +90,2% | 0,95 | 75% |
| +2 | +89,3% | 1.06 | 62% |
| +3 | +72,5% | , 1.10 | 48% |
| +4 | +55,4% | 1.08 | 32% |
| +5 | + 30,1% | 0,95 | 15% |
Baris yang disorot adalah ambang awal backtest (+2). rasio Sharpe meningkat dengan ambang yang lebih ketat hingga +3, mengkonfirmasi sinyal memiliki kekuatan diskriminatif yang nyata. total pengembalian menurun pada ambang tinggi karena strategi berada di luar lebih banyak hari reli.
Sensitivitas Periode Lookback
for lb in [15, 30, 60, 90]:
# Recompute scores with different lookback
sig_sum = pd.Series(0.0, index=aligned.index)
for name, mode in scoring_rules.items():
prev = aligned[name].shift(lb)
chg = aligned[name] - prev
if mode == "falling":
sig = pd.Series([1 if c < -0.05 else (-1 if c > 0.05 else 0) for c in chg], index=aligned.index)
elif mode == "rising":
sig = pd.Series([1 if c > 0.05 else (-1 if c < -0.05 else 0) for c in chg], index=aligned.index)
elif mode == "negative":
sig = pd.Series([1 if v < 0 else (-1 if v > 1 else 0) for v in aligned[name]], index=aligned.index)
else:
sig = pd.Series(0, index=aligned.index)
sig_sum += sig
pos = (sig_sum >= THRESHOLD).astype(float)
ret = pos.shift(1) * aligned["gold_ret"]
cum = (1 + ret.fillna(0)).prod()
vol = ret.std() * np.sqrt(252)
ann = cum ** (252/len(ret)) - 1
print(f" Lookback {lb:3d}d: return {(cum-1)*100:+.1f}% Sharpe {ann/vol:.2f}")
Kembali Ke Masa Lalu Stabilitas
Keunggulan strategi ini bertahan selama 15 hari hingga 90 hari. Lookback yang lebih pendek (15d) lebih responsif tetapi lebih bising, menghasilkan lebih banyak perdagangan. Look back 30 hari menawarkan trade-off terbaik antara responsif dan stabilitas sinyal itulah sebabnya kami memilihnya sebagai konfigurasi utama.
Langkah 9: Skripsi Backtest Lengkap
Berikut adalah backtest lengkap, mandiri yang mengambil semua data dari FXMacroData, menjalankan strategi scorecard, dan mencetak ringkasan kinerja dengan output siap grafik.
"""
Gold Macro Scorecard Backtest
Fetches daily gold prices and macro series from FXMacroData,
computes the composite scorecard, and evaluates a long/flat strategy.
"""
import requests
import pandas as pd
import numpy as np
from datetime import date
BASE = "https://fxmacrodata.com/api/v1"
KEY = "YOUR_API_KEY"
START = "2020-01-01"
THRESHOLD = 2
LOOKBACK = 30
COST_BPS = 5
def get(path: str) -> pd.DataFrame:
r = requests.get(f"{BASE}{path}", params={"api_key": KEY, "start_date": START})
r.raise_for_status()
df = pd.DataFrame(r.json().get("data", []))
df["date"] = pd.to_datetime(df["date"])
return df.set_index("date").sort_index()
# ── Fetch data ──
gold = get("/commodities/gold")[["val"]].rename(columns={"val": "gold"})
macro = {
"tips": (get("/announcements/usd/inflation_linked_bond"), "negative"),
"breakeven": (get("/announcements/usd/breakeven_inflation_rate"), "rising"),
"policy": (get("/announcements/usd/policy_rate"), "falling"),
"cb_assets": (get("/announcements/usd/cb_assets"), "rising"),
"m2": (get("/announcements/usd/m2"), "rising"),
"twi": (get("/announcements/usd/trade_weighted_index"), "falling"),
}
# ── Align and forward-fill ──
df = gold.copy()
for name, (series, _) in macro.items():
s = series[["val"]].rename(columns={"val": name})
df = df.join(s.reindex(df.index, method="ffill"))
df = df.dropna()
# ── Score ──
def score(col, mode):
prev = col.shift(LOOKBACK)
chg = col - prev
if mode == "negative":
return col.apply(lambda v: 1 if v < 0 else (-1 if v > 1 else 0)).astype(float)
if mode == "falling":
return chg.apply(lambda c: 1 if c < -0.05 else (-1 if c > 0.05 else 0)).astype(float)
if mode == "rising":
return chg.apply(lambda c: 1 if c > 0.05 else (-1 if c < -0.05 else 0)).astype(float)
return pd.Series(0.0, index=col.index)
df["net_score"] = sum(score(df[n], m) for n, (_, m) in macro.items())
# ── Trade ──
df["ret"] = df["gold"].pct_change()
df["pos"] = (df["net_score"] >= THRESHOLD).astype(float)
df["trade"] = df["pos"].diff().abs().fillna(0)
df["strat_ret"] = df["pos"].shift(1) * df["ret"] - df["trade"].shift(1) * (COST_BPS/1e4)
df["gold_cum"] = (1 + df["ret"].fillna(0)).cumprod()
df["strat_cum"] = (1 + df["strat_ret"].fillna(0)).cumprod()
# ── Report ──
for label, cum_col, ret_col in [("Strategy", "strat_cum", "strat_ret"),
("Buy&Hold", "gold_cum", "ret")]:
total = df[cum_col].iloc[-1] - 1
vol = df[ret_col].std() * np.sqrt(252)
ann = (1 + total) ** (252/len(df)) - 1
sharpe = ann / vol if vol > 0 else 0
peak = df[cum_col].cummax()
mdd = ((df[cum_col] - peak) / peak).min()
print(f"{label:12s} Return: {total*100:+.1f}% Sharpe: {sharpe:.2f} MaxDD: {mdd*100:.1f}%")
print(f"\nDays invested: {df['pos'].mean()*100:.0f}% | Round-trips: {int(df['trade'].sum()/2)}")
Temuan Utama dan Pelajaran Praktis
Sharpe: 1.06
Strategi kartu skor makro memberikan rasio Sharpe di atas 1,0 yang jauh lebih baik daripada 0,79 buy-and-hold dengan menghindari periode penarikan terburuk.
Max DD: - 11,4%
Penarikan hampir berkurang setengah dibandingkan dengan pembelian dan pemegang (-18,6%). Siklus kenaikan suku bunga 2022 adalah rezim kunci yang diidentifikasi dan dihindari dengan benar oleh scorecard.
62% Waktu yang Diinvestasikan
Strategi ini hanya diinvestasikan 62% dari hari perdagangan, membebaskan modal selama rezim makro bearish.
28 Perjalanan Kembali
Low turnover: roughly 4–5 regime shifts per year. This is implementable even with physical gold ETFs — no high-frequency execution needed.
Batasan dan Peringatan
- Tes latar belakang ilustratif. Hasil sampel yang ditunjukkan dalam artikel ini menggunakan data representatif untuk menggambarkan metodologi. Anda harus menjalankan skrip lengkap terhadap API hidup dengan kunci Anda sendiri untuk menghasilkan hasil yang diverifikasi di kisaran tanggal yang Anda inginkan.
- Bias kelangsungan hidup dalam pemilihan indikator. Kami memilih enam indikator ini karena mereka memiliki teoritis yang kuat untuk emas tetapi pemilihan itu sendiri adalah bentuk implisit kurva-fit.
- Tidak ada ukuran posisi. Pendekatan biner panjang / datar sengaja sederhana. ukuran posisi yang lebih canggih (misalnya, skala eksposur dengan besar skor bersih) dapat meningkatkan risiko disesuaikan pengembalian tetapi menambahkan parameter bebas yang mungkin overfit.
- Pengembalian uang tunai diabaikan. During flat periods, the strategy earns zero. In practice, short-term rates have been 0–5.5% over this period — including risk-free yield on idle cash would further improve the strategy's risk-adjusted edge.
- Tidak ada pemodelan biaya transaksi untuk futures. Jika diterapkan melalui futures emas dan bukan ETF, biaya roll dan persyaratan margin berlaku. asumsi biaya pulang pergi 5 basis adalah representatif dari spread ETF emas tetapi dapat meremehkan biaya eksekusi futures.
- Penundaan penerbitan data makro. Pada saat ini, sistem trading online menggunakan data yang sama seperti pada trading online.
Perpanjangan
- Tambahkan Penutup sentimen risiko dari artikel asli sebagai sinyal ketujuh sangat berguna untuk episode risiko-off yang mendorong lonjakan emas jangka pendek.
- Perluas ke perak dan platinum melalui /komoditas/perak Dan /komoditas/platinumAku tidak tahu.
- Uji dengan pilihan GLD untuk konveksi selama rejimen konveksion tinggi (+4 atau lebih).
- Gabungkan dengan Kalender rilis untuk memicu evaluasi ulang intraday pada hari-hari publikasi data utama.
Semua data yang digunakan dalam backtest ini harga emas harian dan enam indikator makro AS tersedia dari FXMacroData API. titik akhir emas komoditas memberikan harga tetap harian LBMA PM kembali ke tahun 2020, dan Endpoint makro AS Mulai uji coba gratis di fxmacrodata.com/subscribeAku tidak tahu.