Por que os dados macro impulsionam o Bitcoin
O Bitcoin não é uma empresa. Ele não paga dividendos, não relata ganhos e não tem múltiplos de receita para ancorar uma avaliação. Em vez disso, o BTC é negociado como o ativo mais sensível ao risco no mercado uma aposta alavancada nas condições de liquidez global, força do dólar e expectativas de taxa de juros real. Isso significa que o mesmo conjunto de ferramentas macro usado pelos traders de FX para posicionar em EUR/USD ou AUD/JPY se aplica diretamente ao Bitcoin.
Quando o Fed corta as taxas, a liquidez do dólar se expande e os ativos de risco BTC geralmente lideram a carga. Quando o IPC surpreende para cima, as narrativas de cobertura da inflação reaparecem. Quando os rendimentos reais colapsam, as narrativas sobre a depreciação monetária empurram o capital para alternativas de ativos duros. Cada um desses sinais é observado antecipadamente através dos endpoints de indicadores do FXMacroData, timestamped ao segundo e disponível através de uma API REST limpa.
Este guia mostra como criar um bot de negociação algorítmica baseado em macro-sinal para BTC/USDT no Binance.
- Extrai sinais macro em tempo real de FXMacroData (taxa de juro, inflação, taxa de equilíbrio, ouro)
- Combina-os numa pontuação macro composta
- Agendar a execução em torno de lançamentos de alto impacto através do calendário de lancamentos
- Envia ordens de mercado e limite na Binance através do Python SDK oficial
Tese central
Mudanças de regime macro ciclos de corte de taxas, pivots de inflação, inversões de tendência do dólar criam ventos favoráveis direcionais de várias semanas para o Bitcoin.
Requisitos prévios
Antes de começar, certifique-se de ter pronto o seguinte:
- Python 3.9+ todos os trechos usam sintaxe de digitação padrão
- Chave da API do FXMacroData Inscreva-se em / subscrever e pega a tua chave do painel
- Conta Binance com um saldo USDT financiado criar chaves API no painel do Binance com Ativar a negociação de margem e de ponto verificado
- Pacotes Python- Não .
requests- Não .python-binance- Não .pandas- Não .schedule
pip install requests python-binance pandas schedule
Armazenar as chaves da API como variáveis de ambiente em vez de codificá-las:
export FXMACRO_API_KEY="YOUR_FXMACRODATA_KEY"
export BINANCE_API_KEY="YOUR_BINANCE_KEY"
export BINANCE_SECRET_KEY="YOUR_BINANCE_SECRET"
Passo 1: Obter sinais de macro do FXMacroData
Quatro séries macro são fundamentais para um modelo de regime BTC: Taxa de política do dólar- Não . Inflação do IPC- O quê ? Taxa de inflação de equilíbrio a 10 anosE ... preço spot do ouroJuntos, descrevem o ambiente de liquidez, o regime de inflação e o sentimento de fuga para ativos duros.
import os
import requests
BASE_URL = "https://fxmacrodata.com/api/v1"
FXMACRO_KEY = os.environ["FXMACRO_API_KEY"]
def get_series(path: str, start: str = "2024-01-01") -> list[dict]:
"""Fetch a time-series from FXMacroData."""
resp = requests.get(
f"{BASE_URL}{path}",
params={"api_key": FXMACRO_KEY, "start": start},
timeout=10,
)
resp.raise_for_status()
return resp.json()["data"]
# Macro inputs
policy_rate = get_series("/announcements/usd/policy_rate")
cpi = get_series("/announcements/usd/inflation")
breakeven_10y = get_series("/announcements/usd/breakeven_inflation_rate")
gold = get_series("/commodities/gold")
# Each item: {"date": "2025-04-08", "val": 5.25, "announcement_datetime": "..."}
print(f"Policy rate (latest): {policy_rate[0]['val']}%")
print(f"CPI (latest): {cpi[0]['val']}%")
print(f"10Y breakeven: {breakeven_10y[0]['val']}%")
print(f"Gold spot: ${gold[0]['val']:.2f}")
Cada ponto final retorna uma lista ordenada do mais recente ao mais antigo data[0] A chave para as commodities é val; para os indicadores macro, val É o título do livro e ... announcement_datetime A data de lançamento do segundo nível é utilizada para a programação (aberta na etapa 4).
Introduções de sinais macro Regime actual
Valores ilustrativos baseados em dados de 2024-2025. Como o Fed reduziu as taxas e a inflação de equilíbrio aumentou, o BTC formou uma tendência de alta de vários meses.
Passo 2: Crie uma pontuação macro composta
Em vez de reagir a um único indicador, uma pontuação composta sintetiza todos os quatro sinais em um número direcional entre -1 (totalmente de risco) e +1 (total risco).
def macro_score(
policy_rate_pct: float,
cpi_pct: float,
breakeven_pct: float,
gold_usd: float,
*,
gold_baseline: float = 1900.0,
) -> float:
"""
Returns a composite macro score in [-1, +1].
Positive = risk-on / BTC bullish environment.
Negative = risk-off / BTC bearish environment.
"""
score = 0.0
# ── Policy rate regime (weight 0.35) ──────────────────────────
# Sub-4.5% = accommodative → bullish; above 5.5% = restrictive → bearish
if policy_rate_pct < 4.5:
score += 0.35
elif policy_rate_pct <= 5.5:
score += 0.35 * (5.5 - policy_rate_pct) / 1.0
else:
score -= 0.20
# ── Inflation regime (weight 0.25) ────────────────────────────
# CPI 2–4%: moderate inflation → neutral/slightly bullish
# CPI > 6%: high inflation → monetary debasement narrative → bullish
# CPI < 1.5%: deflationary risk → bearish
if cpi_pct > 6.0:
score += 0.25
elif cpi_pct >= 2.0:
score += 0.10
else:
score -= 0.15
# ── Breakeven inflation (weight 0.20) ─────────────────────────
# Rising breakevens signal inflation expectations are re-anchoring → bullish
if breakeven_pct >= 2.5:
score += 0.20
elif breakeven_pct >= 2.0:
score += 0.10
else:
score -= 0.10
# ── Gold trend (weight 0.20) ──────────────────────────────────
# Gold above baseline confirms hard-asset demand → bullish
gold_ratio = (gold_usd - gold_baseline) / gold_baseline
score += 0.20 * max(-1.0, min(1.0, gold_ratio * 5))
return round(max(-1.0, min(1.0, score)), 4)
score = macro_score(
policy_rate_pct=policy_rate[0]["val"],
cpi_pct=cpi[0]["val"],
breakeven_pct=breakeven_10y[0]["val"],
gold_usd=gold[0]["val"],
)
print(f"Composite macro score: {score:+.4f}")
# e.g. → +0.6500 (bullish regime)
Guia de interpretação de pontuação
| Intervalo de pontuação | Macro regime | Sugestão de sinal |
|---|---|---|
| +0,5 a +1,0 | Risco-a taxas de ajustamento, inflação moderada a elevada | Acumular / manter BTC em longo prazo |
| +0,1 a +0,5 | Aumentar ligeiramente sinais mistos, regime de transição | Posição reduzida, aguardando confirmação. |
| -0,1 a +0,1 | Neutro sem sinal de regime forte | Flat / fora de circulação |
| -1,0 a -0,1 | Risco de compensação taxas elevadas, ambiente deflacionário ou estagflacionário | Sair / Reduzir a exposição prolongada |
Passo 3: Conecte-se ao Binance e obtenha o preço do BTC
Com o sinal macro pronto, conecte-se ao Binance usando o oficial python-binance Sempre procure o preço spot actual antes de fazer uma encomenda para evitar valores de referência obsoletos.
import os
from binance.client import Client
BINANCE_KEY = os.environ["BINANCE_API_KEY"]
BINANCE_SECRET = os.environ["BINANCE_SECRET_KEY"]
client = Client(BINANCE_KEY, BINANCE_SECRET)
# Verify connectivity
status = client.get_system_status()
print(f"Binance status: {status['msg']}") # → "normal"
# Latest BTC/USDT price
ticker = client.get_symbol_ticker(symbol="BTCUSDT")
btc_price = float(ticker["price"])
print(f"BTC/USDT spot: ${btc_price:,.2f}")
# Current USDT balance
account = client.get_account()
usdt_balance = next(
(float(b["free"]) for b in account["balances"] if b["asset"] == "USDT"),
0.0,
)
print(f"Available USDT: ${usdt_balance:,.2f}")
Negociação de papel em primeiro lugar
A Binance fornece um ambiente de testes na testnet.binance.vision- Usar . Client(key, secret, testnet=True) Valida a lógica do sinal e o dimensionamento durante pelo menos duas semanas antes de mudar para a vida.
Passo 4: Agendar em torno de eventos de Macro Release
Uma das características mais poderosas do FXMacroData para negociação algorítmica é o ponto final do calendário de liberaçãoEm vez de pesquisar indicadores em um temporizador fixo, você pode consultar a hora exata de lançamento programada para qualquer indicador e disparar sua lógica precisamente quando novos dados aterrissam.
import datetime
import schedule
import time
def get_next_release(currency: str, indicator: str) -> datetime.datetime | None:
"""
Returns the next scheduled release datetime for an indicator.
The calendar endpoint returns upcoming release dates ordered ascending.
"""
resp = requests.get(
f"{BASE_URL}/calendar/{currency}",
params={"api_key": FXMACRO_KEY},
timeout=10,
)
resp.raise_for_status()
events = resp.json().get("data", [])
now_utc = datetime.datetime.now(tz=datetime.timezone.utc)
for event in events:
if event.get("indicator") != indicator:
continue
release_str = event.get("release_datetime") or event.get("date")
if not release_str:
continue
release_dt = datetime.datetime.fromisoformat(release_str.replace("Z", "+00:00"))
if release_dt > now_utc:
return release_dt
return None
# Find when the next FOMC policy rate decision is scheduled
next_fomc = get_next_release("usd", "policy_rate")
if next_fomc:
delta = next_fomc - datetime.datetime.now(tz=datetime.timezone.utc)
print(f"Next FOMC release: {next_fomc.isoformat()} ({delta.days}d {delta.seconds // 3600}h away)")
else:
print("No upcoming policy_rate event found in calendar.")
# Find when the next CPI release is scheduled
next_cpi = get_next_release("usd", "inflation")
if next_cpi:
print(f"Next CPI release: {next_cpi.isoformat()}")
Armado com o carimbo de lançamento exato, você pode agendar uma atualização de sinal pós-lançamento permitindo que o mercado absorva a impressão por alguns minutos antes de re-pontuar e re-negociar:
def on_macro_release():
"""Called shortly after a scheduled macro release."""
print("Macro release fired — refreshing signals...")
run_strategy()
def schedule_next_release(currency: str, indicator: str, delay_seconds: int = 90):
"""
Schedules the strategy to run 'delay_seconds' after the next release.
A 90-second delay lets the initial market reaction settle slightly.
"""
release_dt = get_next_release(currency, indicator)
if not release_dt:
return
fire_at = release_dt + datetime.timedelta(seconds=delay_seconds)
fire_str = fire_at.strftime("%H:%M:%S") # schedule library uses HH:MM:SS
schedule.every().day.at(fire_str).do(on_macro_release).tag(f"{currency}_{indicator}")
print(f"Scheduled signal refresh at {fire_str} UTC after {currency.upper()} {indicator}")
schedule_next_release("usd", "policy_rate", delay_seconds=90)
schedule_next_release("usd", "inflation", delay_seconds=60)
Passo 5: Tamanho das posições e envio de ordens
O dimensionamento de posição é onde a maioria das estratégias algorítmicas perde dinheiro não na lógica de sinal. A função abaixo dimensionam o comércio BTC como uma fração do capital disponível, dimensionando com a magnitude absoluta da pontuação macro. Um ambiente macro de maior convicção (pontuação mais longe de zero) justifica uma alocação maior, mas nunca mais do que um máximo configurável.
from binance.enums import SIDE_BUY, SIDE_SELL, ORDER_TYPE_MARKET, ORDER_TYPE_LIMIT
from binance.exceptions import BinanceAPIException
import math
def compute_quantity(
score: float,
usdt_balance: float,
btc_price: float,
max_position_pct: float = 0.20,
) -> float:
"""
Scale position size between 0 and max_position_pct of USDT balance.
Only trade when |score| > 0.30 to avoid noise-driven entries.
Returns BTC quantity rounded to Binance's minimum lot size (0.00001 BTC).
"""
if abs(score) < 0.30:
return 0.0
conviction = (abs(score) - 0.30) / 0.70 # 0.0 → 1.0
usdt_to_trade = usdt_balance * max_position_pct * conviction
btc_qty = usdt_to_trade / btc_price
return math.floor(btc_qty * 100_000) / 100_000 # 5 decimal places
def place_order(side: str, quantity: float, btc_price: float) -> dict | None:
"""
Submit a market order. For limit orders, pass a price to get_order_book
and sit 0.1% inside the spread.
"""
if quantity <= 0.0:
print("Quantity zero — no order placed.")
return None
try:
order = client.order_market(
symbol="BTCUSDT",
side=side,
quantity=quantity,
)
print(f"Order placed: {side} {quantity:.5f} BTC @ ~${btc_price:,.2f}")
return order
except BinanceAPIException as exc:
print(f"Binance order error: {exc.message}")
return None
Passo 6: Montar o ciclo completo da estratégia
Agora , junte cada peça numa única . run_strategy() Função que recupera dados macro frescos, calcula a pontuação, verifica uma alteração de regime e abre ou fecha uma posição BTC em conformidade.
import json
import pathlib
STATE_FILE = pathlib.Path("strategy_state.json")
def load_state() -> dict:
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {"position": 0.0, "last_score": 0.0}
def save_state(state: dict) -> None:
STATE_FILE.write_text(json.dumps(state, indent=2))
def run_strategy() -> None:
state = load_state()
# ── 1. Fetch fresh macro data ──────────────────────────────────
policy_rate_val = get_series("/announcements/usd/policy_rate")[0]["val"]
cpi_val = get_series("/announcements/usd/inflation")[0]["val"]
breakeven_val = get_series("/announcements/usd/breakeven_inflation_rate")[0]["val"]
gold_val = get_series("/commodities/gold")[0]["val"]
# ── 2. Compute macro score ─────────────────────────────────────
score = macro_score(policy_rate_val, cpi_val, breakeven_val, gold_val)
print(f"Macro score: {score:+.4f} (prev: {state['last_score']:+.4f})")
# ── 3. Fetch current Binance position and price ───────────────
account = client.get_account()
btc_held = float(next(b["free"] for b in account["balances"] if b["asset"] == "BTC"))
usdt_held = float(next(b["free"] for b in account["balances"] if b["asset"] == "USDT"))
btc_price = float(client.get_symbol_ticker(symbol="BTCUSDT")["price"])
# ── 4. Regime change logic ─────────────────────────────────────
prev_score = state["last_score"]
was_long = prev_score >= 0.30
is_long_now = score >= 0.30
was_flat = abs(prev_score) < 0.30
is_flat_now = abs(score) < 0.30
if is_long_now and (was_flat or prev_score < 0):
# Enter or increase long
qty = compute_quantity(score, usdt_held, btc_price)
place_order(SIDE_BUY, qty, btc_price)
elif is_flat_now and was_long and btc_held > 0.0001:
# Exit long — macro regime has turned neutral
exit_qty = math.floor(btc_held * 100_000) / 100_000
place_order(SIDE_SELL, exit_qty, btc_price)
elif score < -0.30 and btc_held > 0.0001:
# Hard exit on bearish signal
exit_qty = math.floor(btc_held * 100_000) / 100_000
place_order(SIDE_SELL, exit_qty, btc_price)
print("BEARISH regime — full exit.")
# ── 5. Persist state ───────────────────────────────────────────
state["last_score"] = score
save_state(state)
# ── Run once immediately, then on each scheduled release ──────────────
run_strategy()
# Keep scheduler alive
while True:
schedule.run_pending()
time.sleep(10)
O valor da taxa de juro é o valor da dívida de um banco central.
O resultado foi de +0,3 no início de 2024, coincidindo com o início da mudança do BTC de ~ $ 40k para $ 70k. A pontuação recuou à medida que as expectativas de corte de taxa foram avaliadas e a narrativa de ativos duros resfriou.
Etapa 7: Gestão de riscos e considerações operacionais
Uma estratégia de sinal macro tem uma frequência de negociação muito menor do que um sistema técnico puro entradas e saídas normalmente ocorrem em torno de 68 lançamentos de indicadores principais por ano. Essa baixa frequência é uma característica, não um bug: você está posicionando para mudanças de regime de várias semanas, não ruído intradiário. No entanto, também significa que cada posição carrega mais risco por negociação, tornando a gestão disciplinada do risco não negociável.
✓ Fazer
- Ativos de capital próprio
- Limitar a posição máxima a 20% da conta por transacção
- Testes retrospectivos de pelo menos 2 ciclos de taxas da Fed antes da entrada em funcionamento
- Registre cada transação e pontuação em um arquivo para auditoria
- Use a Binance testnet para testes em seco primeiro
Evite
- Perseguição de movimentos intradiários de BTC com sinais macro
- Introdução imediata à liberação dos dados (espera 6090 segundos)
- Superajuste de pesos de pontuação num único ciclo
- Funcionamento sem interruptor de redução diária
- Chaves de API de codificação dura em arquivos de origem
Uma consideração adicional: o BTC é negociado 24 horas por dia, 24 horas, 7 dias por semana, mas os eventos macro são agendados. Os lançamentos do FOMC, do IPC e do NFP ocorrem todos durante as horas de mercado dos EUA. Seu agendador deve estar ciente do fuso horário use UTC em todo o tempo e converta apenas quando exibido para os usuários finais. announcement_datetime campo é sempre UTC, tornando isso simples.
Extensão da Estratégia
Esta estrutura é intencionalmente modular. Aqui estão as extensões naturais para explorar a seguir:
- Adicionar dados de posicionamento COT O ponto final CFTC COT da FXMacroData fornece posicionamento especulativo semanal em futuros em USD.
/cot/usde adicionar um termo de posicionamento líquido à pontuação macro. - Pontuação em várias moedas incorporar sinais macro EUR, JPY e GBP para construir uma pontuação global de liquidez.
- Velocidade da tendência de equilíbrio em vez do nível de inflação de equilíbrio, utilizar a taxa de variação de 4 semanas.
- Integração do calendário de lançamento consulta do Calendário de lançamento Para todos os eventos USD a um mês de distância, agrupá-los por peso de impacto e identificar as janelas em que várias libertações de alto impacto se agrupam no prazo de 48 horas esses são os períodos que merecem posicionamento.
Resumo
Agora você tem um bot de negociação de Bitcoin que funciona com sinais macro que conecta os dados do indicador FXMacroData diretamente à execução da Binance. A estratégia lê a taxa de política do USD, o IPC, a inflação de equilíbrio e o ouro para construir uma pontuação macro composta, agende-se em torno de eventos de anúncio do mundo real e os tamanhos e envia ordens BTC/USDT proporcionalmente à convicção do regime.
O próximo artigo desta série abrange o backtesting deste quadro contra dados históricos e calibração dos pesos de pontuação usando séries temporais reais FXMacroData que remontam a 2015.