SignalR · WebSocket
Socket Bağlantıları
Emir, portföy ve ham TradingView sinyalleri için gerçek zamanlı hub metotları.
3 hub metodu
JWT kimlik doğrulama
Reconnect yeniden abonelik
Hub URL
https://api.tradewize.com.tr/hubs/positions
Bağlantı
Resmî SignalR istemcisi negotiate ve WebSocket yükseltmesini yönetir. JWT access token ile bağlanın. Emir ve portföy aboneliklerini Heartbeat() ile canlı tutun; yeniden bağlantı kurulduğunda ilgili hub metodunu tekrar çağırın. Ham TradingView sinyallerindeki bağlantı boşluğunu REST catch-up ile kapatın.
SubscribeToTradingViewSignals - ham sinyallere abone ol
Webhook akışına signalStreamId ile abone olur ve bool sonuç döndürür. Canlı olaylar ReceiveTradingViewSignal eventiyle { cursor, signal } biçiminde gelir. Önce canlı aboneliği kurun, ardından REST catch-up okuyun; iki kanaldaki örtüşmeyi signal.notificationId ile tekilleştirin.
Abone ol, sonra catch-up yap
Bağlantı kurulduğunda ve her reconnect sonrasında önce SubscribeToTradingViewSignals çağırın, sonra son saklanan cursor’dan REST catch-up okuyun. Arada iki kanala da düşen aynı olayı signal.notificationId ile tekilleştirin.
Bağlantı ve istemci sınırları
Bir bağlantıda en fazla 32 farklı stream’e abone olunabilir; limit aşımında metot false döner ve Error eventi gelir. Recovery işlemlerini seri çalıştırın, tekilleştirme kümesini ve canlı tamponu sınırlayın; tampon taşarsa son kalıcı cursor’dan catch-up’ı yeniden başlatın. Cursor yalnız handler başarısından sonra monoton ilerlemelidir.
Teslimat anlamı
ReceiveTradingViewSignal, Gateway’in webhook’u kalıcı olarak kabul ettiğini bildirir. Robot.Api bu akışta değildir; robot sinyali reddedebilir, hiç çalışmayabilir veya emir üretmeyebilir.
Alanların bulunabilirliği
symbol, signal, price, quantity, signalName, interval ve sourceEventId nullable olabilir. parseStatus partial veya invalid olduğunda olay yine geçerlidir; istemci yalnız mevcut alanları göstermelidir.
Hub metodu argümanları
SubscribeToTradingViewSignals - ham sinyallere abone ol — Hub metodu argümanları
| Argüman |
Tip |
Açıklama |
signalStreamId
zorunlu
|
string |
Webhook URL oluşturma/yenileme yanıtının data.signalStreamId alanındaki gizli, 64 karakterli stream kimliği. |
Bağlantı ve abonelikJavaScript
import * as signalR from '@microsoft/signalr';
const signalStreamId = '<signalStreamId-from-webhook-response>';
const seenNotificationIds = new Set();
const seenOrder = [];
const maxSeenNotificationIds = 20_000;
const maxPendingLive = 1_000;
let pendingLive = [];
let catchingUp = true;
let pendingOverflowed = false;
let recovery = Promise.resolve();
const connection = new signalR.HubConnectionBuilder()
.withUrl('https://api.tradewize.com.tr/hubs/positions', {
accessTokenFactory: () => accessToken,
})
.withAutomaticReconnect()
.build();
function rememberOnce(id) {
if (seenNotificationIds.has(id)) return false;
seenNotificationIds.add(id);
seenOrder.push(id);
if (seenOrder.length > maxSeenNotificationIds) {
seenNotificationIds.delete(seenOrder.shift());
}
return true;
}
function deliver(item) {
const id = item.signal.notificationId;
if (!rememberOnce(id)) return;
handleTradingViewSignal(item.signal);
saveCursorMonotonic(item.cursor);
}
connection.on('ReceiveTradingViewSignal', (item) => {
if (catchingUp && pendingLive.length < maxPendingLive) pendingLive.push(item);
else if (catchingUp) pendingOverflowed = true;
else deliver(item);
});
async function subscribeThenCatchUp() {
catchingUp = true;
pendingLive = [];
pendingOverflowed = false;
const pageSize = 100;
const subscribed = await connection.invoke(
'SubscribeToTradingViewSignals',
signalStreamId,
);
if (!subscribed) throw new Error('TradingView signal subscription failed');
while (true) {
let cursor = loadCursor() || '0-0';
while (true) {
const url =
'https://api.tradewize.com.tr/api/v1/tradingview-signals/' +
encodeURIComponent(signalStreamId) +
'?after=' + encodeURIComponent(cursor) + '&count=' + pageSize;
const response = await fetch(url, {
headers: { Authorization: 'Bearer ' + accessToken },
});
if (!response.ok) throw new Error('TradingView signal catch-up failed');
const history = await response.json();
history.events.forEach(deliver);
if (history.events.length < pageSize) break;
if (history.nextCursor === cursor) {
throw new Error('TradingView signal cursor did not advance');
}
cursor = history.nextCursor;
}
if (!pendingOverflowed) break;
// Canlı olaylar Redis Stream’de de bulunduğu için son kalıcı cursor’dan tekrar okuyun.
pendingLive = [];
pendingOverflowed = false;
}
pendingLive.forEach(deliver);
pendingLive = [];
catchingUp = false;
}
function queueRecovery() {
recovery = recovery.catch(() => {}).then(subscribeThenCatchUp);
return recovery;
}
connection.onreconnected(() => {
void queueRecovery().catch(reportRecoveryError);
});
await connection.start();
await queueRecovery();
// Kapatırken:
// await connection.invoke('UnsubscribeFromTradingViewSignals', signalStreamId);
Event · ReceiveTradingViewSignalJSON
{
"cursor": "1793364001000-0",
"signal": {
"schemaVersion": "1.0",
"notificationId": "gws-example-42",
"deliveryId": "tvd-example-42",
"correlationId": "2f846fb1-81ac-4134-9b8e-d4c86f9291d5",
"streamId": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"brokerageCode": "MarbasMenkul",
"symbol": "THYAO",
"signal": "buy",
"price": 321.45,
"quantity": 2.5,
"signalTimestampUtc": "2026-10-30T09:59:59.123Z",
"gatewayReceivedAtUtc": "2026-10-30T10:00:00Z",
"signalName": "Kırılım v3",
"interval": "15",
"sourceEventId": "tv-42",
"parseStatus": "parsed"
}
}
SubscribeToPositions - emir değişikliklerine abone ol
Belirtilen aracı kurum hesabının emir değişiklikleri akışına abone olur ve bool sonuç döndürür. Metot adı geriye dönük uyumluluk nedeniyle SubscribeToPositions olarak kalmıştır; bu abonelik portföy değil, ReceiveOrderChanges eventindeki emir değişikliklerini yayınlar.
Gerekli yetki
JWT zorunludur ve API anahtarında read:orders kapsamı bulunmalıdır. Yalnızca JWT sahibine ait hesaplara abone olunabilir.
Metot adı ve event eşleşmesi
SubscribeToPositions çağrısından sonra ReceiveOrderChanges dinlenmelidir. Eski ReceivePositions eventi kullanılmaz.
Abonelik yaşam döngüsü
Aboneliği UnsubscribeFromPositions ile kapatın. Bağlantı kesildiğinde sunucu abonelik kaydını temizler; uzun yaşayan bağlantılarda Heartbeat() çağırın.
Hub metodu argümanları
SubscribeToPositions - emir değişikliklerine abone ol — Hub metodu argümanları
| Argüman |
Tip |
Açıklama |
brokerageCode
zorunlu
|
string |
Aracı kurum kodu (örn. MarbasMenkul). |
accountNumber
zorunlu
|
string |
Abone olunacak ve JWT sahibine ait olması gereken hesap numarası. |
Bağlantı ve abonelikJavaScript
import * as signalR from '@microsoft/signalr';
const connection = new signalR.HubConnectionBuilder()
.withUrl('https://api.tradewize.com.tr/hubs/positions', {
accessTokenFactory: () => accessToken,
})
.withAutomaticReconnect()
.build();
connection.on('ReceiveOrderChanges', (changes) => {
console.log('Emir değişiklikleri', changes);
});
connection.on('Error', (message) => console.error(message));
await connection.start();
const subscribed = await connection.invoke(
'SubscribeToPositions',
'MarbasMenkul',
'77777',
);
// Aktif aboneliklerin TTL süresini yenileyin.
setInterval(() => connection.invoke('Heartbeat'), 60_000);
// Aboneliği kapatmak için:
// await connection.invoke('UnsubscribeFromPositions', 'MarbasMenkul', '77777');
Event · ReceiveOrderChangesJSON
[
{
"orderId": "305344701",
"symbol": "THYAO",
"side": "BUY",
"quantity": 100,
"remainingQuantity": 0,
"visibleQuantity": 100,
"orderType": 2,
"status": "Completed",
"statusDescription": "Gerçekleşti",
"accountNumber": "77777",
"changeType": "StatusChanged",
"previousStatus": "Pending",
"changedAt": "2026-08-26T10:35:22Z"
}
]
SubscribeToPortfolio - portföy güncellemelerine abone ol
Belirtilen aracı kurum hesabının portföy akışına abone olur ve bool sonuç döndürür. Başarılı abonelikten sonra güncel portföy nesneleri ReceivePortfolio eventiyle yayınlanır.
Gerekli yetki
JWT zorunludur ve API anahtarında read:positions kapsamı bulunmalıdır. Yalnızca JWT sahibine ait hesaplara abone olunabilir.
Abonelik yaşam döngüsü
Aboneliği UnsubscribeFromPortfolio ile kapatın. Bağlantı kesildiğinde sunucu abonelik kaydını temizler; uzun yaşayan bağlantılarda Heartbeat() çağırın.
Hub metodu argümanları
SubscribeToPortfolio - portföy güncellemelerine abone ol — Hub metodu argümanları
| Argüman |
Tip |
Açıklama |
brokerageCode
zorunlu
|
string |
Aracı kurum kodu (örn. MarbasMenkul). |
accountNumber
zorunlu
|
string |
Abone olunacak ve JWT sahibine ait olması gereken hesap numarası. |
Bağlantı ve abonelikJavaScript
import * as signalR from '@microsoft/signalr';
const connection = new signalR.HubConnectionBuilder()
.withUrl('https://api.tradewize.com.tr/hubs/positions', {
accessTokenFactory: () => accessToken,
})
.withAutomaticReconnect()
.build();
connection.on('ReceivePortfolio', (portfolio) => {
console.log('Portföy güncellemesi', portfolio);
});
connection.on('Error', (message) => console.error(message));
await connection.start();
const subscribed = await connection.invoke(
'SubscribeToPortfolio',
'MarbasMenkul',
'77777',
);
// Aktif aboneliklerin TTL süresini yenileyin.
setInterval(() => connection.invoke('Heartbeat'), 60_000);
// Aboneliği kapatmak için:
// await connection.invoke('UnsubscribeFromPortfolio', 'MarbasMenkul', '77777');
Event · ReceivePortfolioJSON
{
"accountNumber": "77777",
"dateTime": "2026-08-26T10:35:22Z",
"accountBalance": 152340.50,
"cashAmount": 12500.00,
"t1NetCashAmount": 12500.00,
"t2NetCashAmount": 12500.00,
"overall": 152340.50,
"stockOverall": 139840.50,
"totalProfit": 8420.75,
"positions": [
{
"symbol": "THYAO",
"lot": 100,
"sellable": 100,
"profitRate": 6.02
}
]
}