Skip to content

Commit 0af5d5b

Browse files
authored
add trade stream for BtcTurk (#772)
1 parent 7df21d1 commit 0af5d5b

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
using Newtonsoft.Json.Linq;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace ExchangeSharp
9+
{
10+
public sealed partial class ExchangeBtcTurkAPI : ExchangeAPI
11+
{
12+
public override string BaseUrl { get; set; } = "https://api.btcturk.com";
13+
public override string BaseUrlWebSocket { get; set; } = "wss://ws-feed-pro.btcturk.com";
14+
15+
public ExchangeBtcTurkAPI()
16+
{
17+
NonceStyle = NonceStyle.UnixMilliseconds;
18+
NonceOffset = TimeSpan.FromSeconds(0.1);
19+
// WebSocketOrderBookType = not implemented
20+
MarketSymbolSeparator = "";
21+
MarketSymbolIsUppercase = true;
22+
// ExchangeGlobalCurrencyReplacements[] not implemented
23+
}
24+
25+
protected internal override async Task<IEnumerable<ExchangeMarket>> OnGetMarketSymbolsMetadataAsync()
26+
{ /*{
27+
"data": {
28+
"timeZone": "UTC",
29+
"serverTime": 1645091654418,
30+
"symbols": [
31+
{
32+
"id": 1,
33+
"name": "BTCTRY",
34+
"nameNormalized": "BTC_TRY",
35+
"status": "TRADING",
36+
"numerator": "BTC",
37+
"denominator": "TRY",
38+
"numeratorScale": 8,
39+
"denominatorScale": 2,
40+
"hasFraction": false,
41+
"filters": [
42+
{
43+
"filterType": "PRICE_FILTER",
44+
"minPrice": "0.0000000000001",
45+
"maxPrice": "10000000",
46+
"tickSize": "10",
47+
"minExchangeValue": "99.91",
48+
"minAmount": null,
49+
"maxAmount": null
50+
}
51+
],
52+
"orderMethods": [
53+
"MARKET",
54+
"LIMIT",
55+
"STOP_MARKET",
56+
"STOP_LIMIT"
57+
],
58+
"displayFormat": "#,###",
59+
"commissionFromNumerator": false,
60+
"order": 1000,
61+
"priceRounding": false,
62+
"isNew": false,
63+
"marketPriceWarningThresholdPercentage": 0.2500000000000000,
64+
"maximumOrderAmount": null,
65+
"maximumLimitOrderPrice": 5895000.0000000000000000,
66+
"minimumLimitOrderPrice": 58950.0000000000000000
67+
}
68+
}*/
69+
var instruments = await MakeJsonRequestAsync<JToken>("api/v2/server/exchangeinfo");
70+
var markets = new List<ExchangeMarket>();
71+
foreach (JToken instrument in instruments["symbols"])
72+
{
73+
markets.Add(new ExchangeMarket
74+
{
75+
MarketSymbol = instrument["name"].ToStringUpperInvariant(),
76+
QuoteCurrency = instrument["denominator"].ToStringInvariant(),
77+
BaseCurrency = instrument["numerator"].ToStringInvariant(),
78+
});
79+
}
80+
return markets;
81+
}
82+
83+
protected override async Task<IWebSocket> OnGetTradesWebSocketAsync(Func<KeyValuePair<string, ExchangeTrade>, Task> callback, params string[] marketSymbols)
84+
{
85+
if (marketSymbols == null || marketSymbols.Length == 0)
86+
{
87+
marketSymbols = (await GetMarketSymbolsMetadataAsync()).Select(m => m.MarketSymbol).ToArray();
88+
}
89+
return await ConnectPublicWebSocketAsync("/market", async (_socket, msg) =>
90+
{ /* {[
91+
991,
92+
{
93+
"type": 991,
94+
"current": "5.1.0",
95+
"min": "2.3.0"
96+
}
97+
]}*/
98+
99+
/* {[
100+
451,
101+
{
102+
"type": 451,
103+
"pairId": 0,
104+
"symbol": "BTCTRY",
105+
"id": 0,
106+
"method": 0,
107+
"userId": 0,
108+
"orderType": 0,
109+
"price": "0",
110+
"amount": "0",
111+
"numLeft": "0.00",
112+
"denomLeft": "0",
113+
"newOrderClientId": null
114+
}
115+
]}] */
116+
JToken token = JToken.Parse(msg.ToStringFromUTF8());
117+
if (token[0].ToObject<int>() == 991)
118+
{
119+
// no need to do anything with this
120+
}
121+
//else if (token["method"].ToStringInvariant() == "ERROR" || token["method"].ToStringInvariant() == "unknown")
122+
//{
123+
// throw new APIException(token["code"].ToStringInvariant() + ": " + token["message"].ToStringInvariant());
124+
//}
125+
else if (token[0].ToObject<int>() == 451)
126+
{
127+
// channel 451 OrderInsert. Ignore.
128+
}
129+
else if (token[0].ToObject<int>() == 100)
130+
{ /*
131+
{[
132+
100,
133+
{
134+
"ok": true,
135+
"message": "join|trade:BTCTRY",
136+
"type": 100
137+
}
138+
]}
139+
*/
140+
// successfully joined
141+
}
142+
else if (token[0].ToObject<int>() == 421)
143+
{ /*
144+
{[
145+
421,
146+
{
147+
"symbol": "BTCTRY",
148+
"items": [
149+
{
150+
"D": "1651204111661",
151+
"I": "100163785789620803",
152+
"A": "0.0072834700",
153+
"P": "586484.0000000000",
154+
"S": 0
155+
},
156+
{
157+
"D": "1651202811844",
158+
"I": "100163785789620737",
159+
"A": "0.0004123600",
160+
"P": "585778.0000000000",
161+
"S": 1
162+
}
163+
],
164+
"channel": "trade",
165+
"event": "BTCTRY",
166+
"type": 421
167+
}
168+
]} */
169+
var data = token[1];
170+
var dataArray = data["items"].ToArray();
171+
for (int i = 0; i < dataArray.Length; i++)
172+
{
173+
var trade = dataArray[i].ParseTrade("A", "P", "S", "D", TimestampType.UnixMilliseconds, "I", "0");
174+
string marketSymbol = data["symbol"].ToStringInvariant();
175+
trade.Flags |= ExchangeTradeFlags.IsFromSnapshot;
176+
if (i == dataArray.Length - 1)
177+
trade.Flags |= ExchangeTradeFlags.IsLastFromSnapshot;
178+
await callback(new KeyValuePair<string, ExchangeTrade>(marketSymbol, trade));
179+
}
180+
}
181+
else if (token[0].ToObject<int>() == 422)
182+
{ /* {[
183+
422,
184+
{
185+
"D": "1651204593830",
186+
"I": "100163785789620825",
187+
"A": "0.0008777700",
188+
"P": "586950.0000000000",
189+
"PS": "BTCTRY",
190+
"S": 1,
191+
"channel": "trade",
192+
"event": "BTCTRY",
193+
"type": 422
194+
}
195+
]} */
196+
var data = token[1];
197+
var trade = data.ParseTrade("A", "P", "S", "D", TimestampType.UnixMilliseconds, "I", "0");
198+
string marketSymbol = data["PS"].ToStringInvariant();
199+
await callback(new KeyValuePair<string, ExchangeTrade>(marketSymbol, trade));
200+
}
201+
else Logger.Warn($"Unexpected channel {token[0].ToObject<int>()}");
202+
}, async (_socket) =>
203+
{ /*
204+
[
205+
151,
206+
{
207+
"type": 151,
208+
"channel": 'CHANNEL_NAME_HERE',
209+
"event": 'PAIR_NAME_HERE',
210+
"join": True
211+
}
212+
]
213+
*/
214+
foreach (var marketSymbol in marketSymbols)
215+
{
216+
var subscribeRequest = new List<object>();
217+
subscribeRequest.Add(151);
218+
subscribeRequest.Add(new
219+
{
220+
type = 151,
221+
channel = "trade",
222+
@event = marketSymbol,
223+
join = true, // If true, it means that you want to subscribe, if false, you can unsubscribe.
224+
});
225+
await _socket.SendMessageAsync(subscribeRequest.ToArray());
226+
}
227+
});
228+
}
229+
230+
}
231+
public partial class ExchangeName { public const string BtcTurk = "BtcTurk"; }
232+
}

0 commit comments

Comments
 (0)