A IA está realmente muito popular ultimamente.
Nos últimos dois anos, a linha principal mais forte do mercado, não importa como se olhe, basicamente gira em torno da IA. NVIDIA, AMD, Broadcom, TSMC, Micron, Microsoft, Google, Meta, CoreWeave, Supermicro... de tempos em tempos, alguma empresa dispara devido a palavras-chave como relatórios financeiros, pedidos, gastos de capital, HBM, GPU, computação em nuvem, data centers.
O mais interessante é que elas geralmente não sobem isoladamente.
Às vezes a NVIDIA se move primeiro, e então o mercado começa a buscar ASICs, módulos ópticos, servidores, refrigeração líquida, energia; outras vezes, o relatório financeiro da Micron supera as expectativas, e depois o dinheiro vai para HBM, armazenamento, equipamentos semicondutores, empacotamento avançado; também há casos em que as empresas de nuvem aumentam os gastos de capital, e toda a cadeia de infraestrutura de IA é reapreciada.
Isso se parece mais com uma rotação de ativos dentro do tema da IA. O mercado não está simplesmente comprando uma ação, mas, sob uma grande narrativa, constantemente procurando novos ramos, novas interpretações e novos alvos de recuperação.
Surge então a questão: se essas relações forem organizadas manualmente, é muito cansativo.
Uma pessoa pode conhecer NVIDIA, AMD, Micron, Microsoft, Google, mas é difícil acompanhar continuamente as mudanças nos negócios, notícias, classificações setoriais e correlações de preços de dezenas ou centenas de contratos de ações TradFi. O problema é ainda mais complicado porque muitas empresas não têm uma única característica. Google é nuvem de IA, Gemini e plataforma de publicidade; Microsoft é nuvem, Copilot e software empresarial; Broadcom tem ASIC, chips de rede e também está relacionada a data centers de IA.
Então comecei a tentar: será que podemos deixar um modelo grande nos ajudar a montar um mapa de ações de IA?
Não se trata de pedir ao modelo grande para nos dizer o que comprar diretamente, mas sim deixá-lo fazer o que faz melhor: entender os negócios das empresas, classificar subseções de IA, organizar notícias, explicar eventos e julgar quais ações do mesmo tema podem ser afetadas pelo movimento de uma empresa. A verdadeira decisão de negociação ainda é deixada para preços, estatísticas e gestão de risco.
Primeiro, coloque as ações nas baskets corretas
O primeiro passo da estratégia não é negociar, mas sim construir o mapa.
Atualmente, a bolsa possui vários contratos de ações TradFi, que permitem obter diretamente um conjunto de contratos de ações como NVDA, AMD, MU, MSFT, GOOGL, SMCI. O sistema primeiro filtra os contratos de ações, mantendo apenas os ativos realmente do tipo EQUITY.
Aqui há um detalhe muito importante: não se pode misturar ETFs, índices, ETFs alavancados. Coisas como QQQ, SOXL, EWT, embora possam aparecer na lista de contratos, não são ações de empresas. Se forem colocadas na basket de ações de IA, as relações estatísticas posteriores serão contaminadas.
A lógica principal de filtragem é mais ou menos assim:
python
def refresh_equity_universe(store, force_reanalyze):
ms = exchange.GetMarkets()
symbols = []
for key, market in ms.items():
info = market.get("Info", {}) or {}
sub_type = info.get("underlyingSubType", []) or []
underlying_type = info.get("underlyingType", "")
if ".swap" not in key:
continue
if "TradFi" not in sub_type:
continue
if underlying_type != "EQUITY":
continue
symbol = normalize_symbol(key)
store["markets"][symbol] = {
"symbol": symbol,
"contract": key,
"underlyingType": underlying_type,
"amountPrecision": market.get("AmountPrecision", 0),
"pricePrecision": market.get("PricePrecision", 2),
"ctVal": market.get("CtVal", 1) or 1,
"minQty": market.get("MinQty", 0) or 0,
}
symbols.append(symbol)
Depois de obter o conjunto de ações, o sistema pede ao modelo grande para fazer um perfil de cada ação.
O perfil não é simplesmente escrever "isso é uma ação de tecnologia", mas sim determinar a quais subseções de IA ela pertence. Por exemplo, uma ação pode pertencer a múltiplas baskets ao mesmo tempo. Google pode pertencer a nuvem de IA, aplicações de modelos de IA, publicidade em plataforma de IA; Microsoft pode pertencer a nuvem de IA e aplicações empresariais de IA; NVIDIA pode pertencer a poder computacional de IA e servidores de IA; Micron pode pertencer a armazenamento de IA.
O ponto chave aqui é: na era da IA, as ações não têm uma única etiqueta, mas sim múltiplas etiquetas.
Cada ação carrega vários atributos: a quais baskets pertence, qual o grau de exposição, se nessa basket é mais líder ou seguidora, quais empresas podem influenciá-la e quais empresas ela pode influenciar.
Eu impus uma restrição forte na estrutura de saída do modelo grande:
python
schema = {
"symbol": symbol,
"asset_type": "stock|adr|etf|leveraged_etf|index|fund|other",
"company_name": "",
"sector": "",
"business_summary": "",
"tradable": False,
"model_confidence": 0,
"baskets": [
{
"id": "ai_cloud",
"exposure": 0.0,
"role": "leader|follower|both|observer",
"sub_theme": "",
"reason": ""
}
],
"search_names": [],
"event_keywords": [],
"negative_keywords": [],
"possible_leaders": [],
"possible_followers": [],
"brave_queries": [],
"reason": ""
}
O mais crucial aqui é asset_type. Apenas stock e adr podem entrar na basket; ETFs, ETFs alavancados, índices, fundos, commodities ou ETFs regionais são diretamente filtrados.
Além disso, o campo reason deve estar em chinês, os nomes dos campos devem ser consistentes, e a confiança deve ser uniformizada de 0 a 100. Caso contrário, a página de negociação ao vivo ficará muito confusa.
Informações setoriais não podem ser baseadas em suposições
Apenas a classificação das ações não é suficiente.
O setor de IA muda muito rapidamente. Hoje o mercado negocia GPU, amanhã pode negociar HBM, depois de amanhã módulos ópticos, e alguns dias depois começa a negociar refrigeração líquida, energia, gastos de capital de empresas de nuvem.
Se depender apenas do conhecimento do modelo grande, facilmente fica desatualizado. Por isso, o sistema precisa de fontes de informação em tempo real.
Aqui eu integrei o BraveSearch. O sistema pesquisa periodicamente informações setoriais de cada basket de IA, e também pesquisa notícias sobre ações importantes dentro da basket.
Por exemplo, para a basket de armazenamento de IA, são pesquisadas palavras-chave como Micron, Western Digital, SanDisk, HBM, DRAM, NAND; para a basket de comunicação óptica de IA, são pesquisadas informações sobre Ciena, Credo, Lumentum, AAOI, módulos ópticos de 800G, 1.6T.
O fluxo principal de inteligência setorial é:
python
def refresh_basket_intelligence(store):
if not BRAVE_KEY:
return
if not LLM_API_KEY:
return
intel = {}
for bid, basket in store["baskets"].items():
members = sorted(
basket["members"],
key=lambda x: x.get("exposure", 0),
reverse=True
)
top_symbols = [m["symbol"] for m in members[:8]]
basket_news = fetch_basket_news(basket, top_symbols)
stock_news = {}
for symbol in top_symbols[:6]:
profile = store["profiles"].get(symbol, {})
stock_news[symbol] = fetch_stock_news(profile, bid)
Sleep(800)
analysis = analyze_basket_intel_with_llm(
store, basket, top_symbols, basket_news, stock_news
)
if analysis:
analysis["basket"] = bid
analysis["basket_name"] = basket["name"]
analysis["symbols"] = top_symbols
analysis["updatedAt"] = int(time.time())
intel[bid] = analysis
store["basket_intel"] = intel
Este passo serve para criar um contexto dinâmico para cada sub-setor da IA.
O modelo grande, com base nas notícias obtidas via BraveSearch, gera a tendência do setor, catalisadores principais, riscos principais, líder candidato, seguidor candidato e as relações que precisam ser verificadas posteriormente.
Isso é diferente de simplesmente perguntar ao modelo "o que acha do setor de IA de armazenamento?". Primeiro alimentamos as notícias em tempo real e depois pedimos que ele faça um resumo.
Não é negociação baseada em notícias, o preço anormal vem primeiro
No começo, também pensei em uma abordagem baseada em notícias.
Por exemplo, ao ver que os resultados de uma empresa superaram as expectativas, pedir ao modelo grande para julgar quais ações se beneficiariam e gerar um sinal diretamente. Mas, na prática, esse caminho é muito ruidoso. Existem muitas notícias; muitas parecem importantes, mas o mercado simplesmente não reage.
Então inverti a lógica.
Primeiro, olhamos para o preço, depois para as notícias.
Se todas as ações de uma cesta estiverem relativamente estáveis, o sistema apenas observa. Somente quando uma ação se desvia visivelmente do desempenho médio do setor, tornando-se a líder atual, o sistema pergunta: por que ela se moveu?
Este passo usa o ZScore dentro da cesta.
De forma simples, é ver se uma ação está anormalmente forte ou fraca em relação às outras do mesmo setor. Se uma ação se destaca de repente, enquanto as outras na mesma cesta ainda não reagiram, pode haver uma oportunidade de difusão.
A lógica central para calcular o ZScore da cesta é a seguinte:
python
def calc_basket_zscores(store, symbols):
returns = {}
min_len = 999999
for symbol in symbols:
bars = get_records(
store["markets"][symbol]["contract"],
KLINE_PERIOD,
SYNC_WINDOW + 10
)
if len(bars) < SYNC_WINDOW + 2:
return None
r = calc_returns(bars)[-SYNC_WINDOW:]
returns[symbol] = r
min_len = min(min_len, len(r))
latest = {s: returns[s][-1] for s in symbols}
avg_latest = mean(list(latest.values()))
dev_series = {s: [] for s in symbols}
for i in range(min_len):
row = [returns[s][-min_len + i] for s in symbols]
row_avg = mean(row)
for s in symbols:
dev_series[s].append(returns[s][-min_len + i] - row_avg)
zscores = {}
max_abs = 0
for s in symbols:
sigma = std(dev_series[s])
z = (latest[s] - avg_latest) / sigma if sigma > 0 else 0
zscores[s] = round(z, 3)
max_abs = max(max_abs, abs(z))
return {"zscores": zscores, "maxAbs": max_abs}
Se o desvio máximo de uma cesta ultrapassar o limite de breakout, o sistema entra no estado BREAKOUT_DETECTED.
Neste momento, o sistema não negocia imediatamente; começa a investigar a causa.
As notícias apenas explicam; as relações estatísticas verificam
Quando o líder apresenta um breakout de preço, o sistema captura suas notícias mais recentes e pede ao modelo grande para julgar se aquela notícia pode explicar o movimento anormal de preço.
Mas não é simplesmente perguntar "esta notícia é boa?".
O sistema envia ao modelo grande: a cesta atual, a inteligência do setor, o estado do preço em tempo real, o ZScore do líder, os seguidores candidatos, as relações estatísticas já verificadas e as notícias obtidas via BraveSearch.
O modelo grande precisa responder:
(1) Se esta notícia explica a anomalia de preço do líder.
(2) Se a direção da notícia é consistente com a direção do preço.
(3) Se a negociação é permitida.
(4) Quais seguidores são afetados.
(5) Qual é o impacto em cada seguidor.
(6) Por que esses seguidores podem ser afetados.
A lógica central da investigação causal é a seguinte:
python
def explain_breakout_with_news(store, bid, leader, direction, leader_z, followers, edges):
if not BRAVE_KEY:
return None
if not LLM_API_KEY:
return None
profile = store["profiles"].get(leader, {})
news = fetch_stock_news(profile, bid)
if not news:
return None
event = analyze_breakout_news_with_llm(
store, bid, leader, direction, leader_z,
followers, edges, news
)
if not event:
return None
if not event.get("explains_price_move"):
return None
expected_direction = "bullish" if direction == "long" else "bearish"
if event.get("direction") != expected_direction:
return None
event["confidence"] = normalize_confidence(event.get("confidence", 0))
if event["confidence"] < MIN_NEWS_CONFIDENCE:
return None
if not event.get("trade_allowed"):
return None
return event
Mas mesmo que o modelo grande diga que um determinado follower pode ser afetado, não dá para negociar imediatamente.
Também é preciso observar a relação estatística dos candles.
O sistema calcula, dentro de cada basket, a correlação histórica entre as ações. Por exemplo, após a ruptura (breakout) do source, o target costuma seguir? Qual a correlação? Qual o melhor período de defasagem (lag)? Qual o retorno médio de seguir?
Apenas as relações source -> target que passam na verificação estatística se tornam active edges.
python
def rebuild_basket_stats(store):
edges = []
for bid, basket in store["baskets"].items():
symbols = [
m["symbol"] for m in basket["members"]
if m["symbol"] in store["markets"]
]
for source in symbols:
for target in symbols:
if source == target:
continue
metric = validate_pair(store, source, target)
if not metric:
continue
source_exp = basket_member_info(basket, source).get("exposure", 0)
target_exp = basket_member_info(basket, target).get("exposure", 0)
score = clamp(
metric["corr"] * 0.3 +
metric["follow"] * 0.4 +
min(source_exp, target_exp) * 0.3,
0, 1
)
edge = {
"basket": bid,
"source": source,
"target": target,
"corr": round(metric["corr"], 3),
"follow": round(metric["follow"], 3),
"lag": metric["lag"],
"avgReturn": round(metric["avgReturn"], 6),
"sample": metric["sample"],
"score": round(score, 3),
"active": (
score >= MIN_EDGE_SCORE and
metric["corr"] >= MIN_CORR and
metric["follow"] >= MIN_FOLLOW_SUCCESS
),
"updatedAt": int(time.time()),
}
edges.append(edge)
store["edges"] = edges
Este passo é importante.
Modelos grandes são bons em entender lógica, mas o mercado nem sempre segue a lógica. A relação estatística serve para validar: essa lógica já foi negociada pelo mercado no passado?
Negocia-se a difusão, não a perseguição de alta
Esta estratégia não é para perseguir o leader.
O leader já rompeu; entrar diretamente atrás dele facilmente se torna perseguição de alta. O que a estratégia realmente busca são as oportunidades de difusão dentro do mesmo basket de IA.
Ou seja: o leader já se moveu, a notícia faz sentido, mas alguns followers ainda não reagiram completamente. Se esses followers e o leader realmente têm uma relação de correlação histórica, pode existir uma oportunidade de curto prazo de seguir.
Na varredura de breakout, primeiro se procuram active edges, depois os followers defasados:
python
def scan_price_breakouts(store):
for bid, rt in store["realtime"].items():
if rt["state"] != "BREAKOUT_DETECTED":
continue
leader = rt["leader"]
z = 0
for m in rt["members"]:
if m["symbol"] == leader:
z = m["z"]
direction = "long" if z > 0 else "short"
edges = [
e for e in store["edges"]
if e["active"] and e["basket"] == bid and e["source"] == leader
]
followers = []
for e in edges:
target_rt = find_realtime_member(rt, e["target"])
if target_rt and abs(target_rt["z"]) < BREAKOUT_THRESHOLD * 0.75:
followers.append(e["target"])
if not followers:
continue
Somente quando a verificação de causalidade por notícias também é aprovada é que um confirmed signal é gerado.
Os alvos de negociação são principalmente os followers.
Se no momento não há posição, abre-se na direção do sinal. Se já existe uma posição no mesmo contrato com a mesma direção, adiciona-se. Se já existe uma posição contrária, fecha-se primeiro e depois abre-se na nova direção.
python
def execute_symbol_trade(store, signal, symbol, detail):
direction = signal["direction"]
if TRADE_MODE != "trade":
return open_or_add_position(store, signal, symbol, detail, add_mode=False)
pos = get_position_by_symbol(symbol)
if pos:
pos_dir = position_direction(pos)
if pos_dir == direction:
return open_or_add_position(store, signal, symbol, detail, add_mode=True)
close_existing_position(store, symbol, pos, "reverse_signal")
Sleep(1000)
return open_or_add_position(store, signal, symbol, detail, add_mode=False)
Isso também porque muitas ações aparecem simultaneamente em múltiplos baskets. Uma ação pode ser follower no basket "Nuvem de IA" e, no basket "Aplicações de IA", ser membro de outra lógica. Sinais de diferentes baskets podem afetá-la ao mesmo tempo, por isso é necessário tratar a direção do mesmo contrato de forma unificada.
Controle de risco simples primeiro, mas obrigatório
No controle de risco, atualmente usamos stop loss fixo e trailing stop.
Se o prejuízo atingir o limite, sai-se; quando o lucro atinge um certo patamar, ativa-se o trailing stop. Se houver um recuo excessivo a partir do lucro flutuante máximo, o lucro é bloqueado e a posição é encerrada.
python
def monitor_positions(store):
for pos in exchange.GetPosition() or []:
symbol = position_symbol(pos)
if symbol not in store["markets"]:
continue
state = _G(position_state_key(symbol)) or {}
market = store["markets"][symbol]
ticker = exchange.GetTicker(market["contract"])
direction = position_direction(pos)
pnl_pct = (
(ticker["Last"] - pos["Price"]) /
pos["Price"] * 100 *
(1 if direction == "long" else -1)
)
if pnl_pct > state.get("peakPnlPct", 0):
state["peakPnlPct"] = pnl_pct
if not state.get("trailActive") and state.get("peakPnlPct", 0) >= TRAIL_ACTIVATE_PCT:
state["trailActive"] = True
hard_stop = False
if state.get("stop"):
hard_stop = (
ticker["Last"] <= state["stop"]
if direction == "long"
else ticker["Last"] >= state["stop"]
)
trail_hit = False
if state.get("trailActive"):
giveback = state.get("peakPnlPct", 0) - pnl_pct
allowed = max(
1.5,
state.get("peakPnlPct", 0) * TRAIL_GIVEBACK_PCT / 100.0
)
trail_hit = giveback >= allowed
if hard_stop or trail_hit:
close_existing_position(
store, symbol, pos,
"hard_stop" if hard_stop else "trailing_stop"
)
Isso não é a versão final do controle de risco, mas já é suficiente como primeira versão para observação em tempo real.
Depois, será necessário adicionar restrições de nível de conta, como posição total, exposição por setor, limite de perda diária, confirmação de execução e limite de número de adições.
Qual o estágio atual do sistema?
O sistema atual já consegue concluir um ciclo de pesquisa relativamente completo.
Ele pode escanear automaticamente contratos de ações TradFi, fazer com que o modelo grande crie automaticamente um perfil do basket de ações long, construir automaticamente sub-setores de IA, puxar automaticamente informações sobre setores e ações individuais via BraveSearch, resumir automaticamente as notícias do setor, detectar automaticamente a força em tempo real de cada basket, contar automaticamente a relação de seguimento entre as ações do basket e, quando o preço do líder romper, realizar o rastreamento de notícias.
Se a explicação da notícia for válida, a direção estiver alinhada e a relação estatística também apoiar, o sistema gera um sinal confirmado. No modo padrão, apenas notifica, sem operar em tempo real; só negocia quando alternar para o modo "trade".
Na página de negociação real, não são apenas logs: são exibidos em tabelas a visão geral do sistema, o estado em tempo real dos baskets, as notícias do setor, os sinais recentes, as negociações recentes e os passos recentes. Isso permite ver claramente em qual etapa o sistema está travando: se é apenas uma anomalia de preço, se a notícia não tem explicação, se os seguidores não atendem às condições, ou se o controle de risco está bloqueando.
O que ainda não está maduro
Sinceramente, este sistema ainda não pode ser considerado uma estratégia de negociação automática madura.
Ele é mais como um framework de pesquisa de rotação temática baseada em IA, que já consegue conectar "perfil de ações, notícias do setor, anomalias de preço, rastreamento de notícias, validação estatística e sinais de negociação", mas ainda precisa de mais validação.
O que mais precisa ser aprimorado são alguns pontos.
(1) Qualidade do perfil de ações. Às vezes, o modelo grande coloca ações marginais no basket, por isso é necessário forçar asset_type para evitar a mistura de ETFs, índices e fundos regionais.
(2) Qualidade das notícias. As notícias obtidas pelo BraveSearch nem sempre são as principais; o modelo precisa julgar quais realmente explicam o preço.
(3) Relações estatísticas. A relação histórica de seguimento não garante eficácia futura; é necessário revisar continuamente.
(4) Controle de risco das negociações. Antes de negociar automaticamente, é obrigatório adicionar posição total de conta, exposição por setor, perda diária e confirmação de execução.
Por isso, agora é mais adequado rodar primeiro o modo "notify" para observar a qualidade dos sinais confirmados.
Se depois de algum tempo os sinais realmente explicarem as anomalias do mercado e os seguidores frequentemente reagirem, então considerar a negociação real com posição pequena.
Considerações finais
Esta estratégia não faz com que a IA dê ordens diretamente.
Sempre achei que a posição mais adequada dos modelos grandes em sistemas de negociação não é "dizer o que comprar", mas ajudar a processar informações que são difíceis de manter manualmente: negócios das empresas, classificação setorial, notícias em tempo real, explicação de eventos, caminhos de rotação de capital e potenciais impactados.
A negociação real deve ser deixada para preço, estatística e controle de risco.
Uma estratégia quantitativa na era da IA não deve apenas adicionar uma interface de modelo grande, mas sim conectar dados em tempo real, grafos temáticos, notícias de eventos, estruturas de preço, execução de negociação e explicação de revisão.
A estratégia de grafo de ações com IA é uma tentativa nessa direção.
Código-fonte da estratégia: Sistema de Negociação com Contratos TradFi da Cadeia da Indústria com IA
- 1





