├── .gitignore ├── README.md ├── algolab.py ├── config.py ├── ornek.py ├── ornek_soket.py ├── requirements.txt ├── tick_to_ohlcv_converter.py └── ws.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | *.txt 4 | *.json 5 | *.log 6 | *.json 7 | config.py 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ALGOLAB API KOD ORNEKLERİ 2 | 3 | Algolab API örnek Python kodu, ilgili kodu indirdikten sonra config içerisinde yer alan (API-KEY,TC_NO,PASSWORD) bilgilerini doldurarak Algolab API işlemleri için kullanabilirsiniz. ornek.py dosyasını çalıştırarak tüm endpoint işlemlerini bir menü üzerinden test edebilir ornek_socket üzerinden anlık veri akışı,derinlik,işlem teyit bilgisi çekebilirsiniz. tick_to_ohlcv_converter dosyasından anlık işlem bilgisini JSON formatında OHLCV verilerine dönüştürebilirsiniz. 4 | 5 | 6 | Öncelikle Algolab'e denizbank hesabınız ile kayıt olmanız ve Profilim --> Başvurular kısmından API ve İşlem sözleşmesi başvurusu yapıp size mail olarak iletilen gerekli adımları tamamladıktan sonra API-Keyinizin tanımlanması gerekmektedir. 7 | Algolab'e üye olmak için Denizbank Müşteri girişi yapmanız yeterlidir. 8 | 9 | https://www.algolab.com.tr/ 10 | -------------------------------------------------------------------------------- /algolab.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import requests, hashlib, json, base64, inspect, time 3 | from Crypto.Cipher import AES 4 | from Crypto.Util.Padding import pad 5 | from threading import Thread 6 | from config import * 7 | 8 | last_request = 0.0 9 | LOCK = False 10 | class API(): 11 | def __init__(self, api_key, username, password, auto_login=True, keep_alive=False, verbose=True): 12 | """ 13 | api_key: API_KEY 14 | username: TC Kimlik No 15 | password: DENIZBANK_HESAP_ŞİFRENİZ 16 | verbose: True, False - İşlemlerin çiktisini yazdirir 17 | """ 18 | if verbose: 19 | print("Sistem hazirlaniyor...") 20 | try: 21 | self.api_code = api_key.split("-")[1] 22 | except: 23 | self.api_code = api_key 24 | self.api_key = "API-" + self.api_code 25 | self.username = username 26 | self.password = password 27 | self.api_hostname = api_hostname 28 | self.api_url = api_url 29 | self.auto_login = auto_login 30 | self.headers = {"APIKEY": self.api_key} 31 | self.keep_alive = keep_alive 32 | self.thread_keepalive = Thread(target=self.ping) 33 | self.verbose = verbose 34 | self.ohlc = [] 35 | self.token = "" 36 | self.new_hour = False 37 | self.sms_code = "" 38 | self.hash = "" 39 | self.start() 40 | 41 | def save_settings(self): 42 | data = { 43 | "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), 44 | "token": self.token, 45 | "hash": self.hash 46 | } 47 | with open("./data.json", "w") as f: 48 | # Dosyaya yaz 49 | json.dump(data, f) 50 | 51 | def load_settings(self): 52 | try: 53 | with open("./data.json", "r") as f: 54 | data = json.load(f) 55 | self.token = data["token"] 56 | self.hash = data["hash"] 57 | return True 58 | except: 59 | return False 60 | 61 | def start(self): 62 | if self.auto_login: 63 | # önceki login bilgileri varsa yükle 64 | s = self.load_settings() 65 | if not s or not self.is_alive: 66 | if self.verbose: 67 | print("Login zaman aşimina uğradi. Yeniden giriş yapiliyor...") 68 | 69 | if self.LoginUser(): 70 | self.LoginUserControl() 71 | else: 72 | if self.verbose: 73 | print("Otomatik login başarili...") 74 | 75 | if self.keep_alive: 76 | self.thread_keepalive.start() 77 | 78 | def ping(self): 79 | while self.keep_alive: 80 | p = self.SessionRefresh(silent=True) 81 | time.sleep(60 * 5) 82 | 83 | # LOGIN 84 | 85 | def LoginUser(self): 86 | try: 87 | if self.verbose: 88 | print("Login işlemi yapiliyor...") 89 | 90 | f = inspect.stack()[0][3] 91 | u = self.encrypt(self.username) 92 | p = self.encrypt(self.password) 93 | payload = {"username": u, "password": p} 94 | endpoint = URL_LOGIN_USER 95 | resp = self.post(endpoint=endpoint, payload=payload, login=True) 96 | login_user = self.error_check(resp, f) 97 | if not login_user: 98 | return False 99 | login_user = resp.json() 100 | succ = login_user["success"] 101 | msg = login_user["message"] 102 | content = login_user["content"] 103 | if succ: 104 | self.token = content["token"] 105 | if self.verbose: 106 | print("Login başarili.") 107 | return True 108 | else: 109 | if self.verbose: 110 | print(f"Login Başarisiz. self.mesaj: {msg}") 111 | except Exception as e: 112 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 113 | 114 | def LoginUserControl(self): 115 | try: 116 | if self.verbose: 117 | print("Login kontrolü yapiliyor...") 118 | 119 | self.sms_code = input("Cep telefonunuza gelen SMS kodunu girin: ") 120 | f = inspect.stack()[0][3] 121 | t = self.encrypt(self.token) 122 | s = self.encrypt(self.sms_code) 123 | payload = {'token': t, 'password': s} 124 | endpoint = URL_LOGIN_CONTROL 125 | resp = self.post(endpoint, payload=payload, login=True) 126 | login_control = self.error_check(resp, f) 127 | if not login_control: 128 | return False 129 | login_control = resp.json() 130 | succ = login_control["success"] 131 | msg = login_control["message"] 132 | content = login_control["content"] 133 | if succ: 134 | self.hash = content["hash"] 135 | if self.verbose: 136 | print("Login kontrolü başarili.") 137 | 138 | self.save_settings() 139 | return True 140 | else: 141 | if self.verbose: 142 | print(f"Login kontrolü başarisiz.\nself.mesaj: {msg}") 143 | 144 | except Exception as e: 145 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 146 | 147 | 148 | # REQUESTS 149 | 150 | def SessionRefresh(self, silent=False): 151 | """ 152 | Oturum süresi uzatmak için atılan bir istektir. 153 | Cevap olarak Success: True veya eğer hash'iniz geçerliliğini yitirmişte 401 auth hatası olarak döner. 154 | """ 155 | try: 156 | f = inspect.stack()[0][3] 157 | endpoint = URL_SESSIONREFRESH 158 | payload = {} 159 | resp = self.post(endpoint, payload=payload) 160 | return self.error_check(resp, f, silent) 161 | except Exception as e: 162 | if not silent: 163 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 164 | 165 | 166 | def GetEquityInfo(self, symbol): 167 | """ 168 | Sembolle ilgili tavan taban yüksek düşük anlık fiyat gibi bilgileri çekebilirsiniz. 169 | :String symbol: Sembol Kodu Örn: ASELS 170 | """ 171 | try: 172 | f = inspect.stack()[0][3] 173 | endpoint = URL_GETEQUITYINFO 174 | payload = {'symbol': symbol} 175 | resp = self.post(endpoint, payload=payload) 176 | return self.error_check(resp, f) 177 | except Exception as e: 178 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 179 | 180 | 181 | def GetSubAccounts(self, silent=False): 182 | try: 183 | f = inspect.stack()[0][3] 184 | end_point = URL_GETSUBACCOUNTS 185 | resp = self.post(end_point, {}) 186 | return self.error_check(resp, f, silent=silent) 187 | except Exception as e: 188 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 189 | 190 | 191 | def GetInstantPosition(self, sub_account=""): 192 | """ 193 | Yatırım Hesabınıza bağlı alt hesapları (101, 102 v.b.) ve limitlerini görüntüleyebilirsiniz. 194 | """ 195 | try: 196 | f = inspect.stack()[0][3] 197 | end_point = URL_INSTANTPOSITION 198 | payload = {'Subaccount': sub_account} 199 | resp = self.post(end_point, payload) 200 | return self.error_check(resp, f) 201 | except Exception as e: 202 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 203 | 204 | 205 | def GetTodaysTransaction(self, sub_account=""): 206 | """ 207 | Günlük işlemlerinizi çekebilirsiniz.(Bekleyen gerçekleşen silinen v.b.) 208 | """ 209 | try: 210 | f = inspect.stack()[0][3] 211 | end_point = URL_TODAYTRANSACTION 212 | payload = {'Subaccount': sub_account} 213 | resp = self.post(end_point, payload) 214 | return self.error_check(resp, f) 215 | except Exception as e: 216 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 217 | 218 | 219 | def GetViopCustomerOverall(self, sub_account=""): 220 | try: 221 | f = inspect.stack()[0][3] 222 | end_point = URL_VIOPCUSTOMEROVERALL 223 | payload = {'Subaccount': sub_account} 224 | resp = self.post(end_point, payload) 225 | return self.error_check(resp, f) 226 | except Exception as e: 227 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 228 | 229 | 230 | def GetViopCustomerTransactions(self, sub_account=""): 231 | try: 232 | f = inspect.stack()[0][3] 233 | end_point = URL_VIOPCUSTOMERTRANSACTIONS 234 | payload = {'Subaccount': sub_account} 235 | resp = self.post(end_point, payload) 236 | return self.error_check(resp, f) 237 | except Exception as e: 238 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 239 | 240 | 241 | 242 | def ViopColleteralInfo(self, sub_account=""): 243 | try: 244 | f = inspect.stack()[0][3] 245 | end_point = URL_VIOPCOLLETERALINFO 246 | payload = {'Subaccount': sub_account} 247 | resp = self.post(end_point, payload) 248 | return self.error_check(resp, f) 249 | except Exception as e: 250 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 251 | 252 | 253 | def RiskSimulation(self, sub_account=""): 254 | try: 255 | f = inspect.stack()[0][3] 256 | end_point = URL_RISKSIMULATION 257 | payload = {'Subaccount': sub_account} 258 | resp = self.post(end_point, payload) 259 | return self.error_check(resp, f) 260 | except Exception as e: 261 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 262 | 263 | def AccountExtre(self, sub_account="", start_date=None, end_date=None): 264 | """ 265 | start_date: başlangiç tarihi "2023-07-01 00:00:00.0000" iso formatında 266 | end_date: bitiş tarihi "2023-07-01 00:00:00.0000" iso formatında 267 | """ 268 | try: 269 | f = inspect.stack()[0][3] 270 | end_point = URL_ACCOUNTEXTRE 271 | # datetime nesneleri isoformat() ile dönüştürülüyor 272 | payload = { 273 | 'start': start_date.isoformat() if start_date else None, 274 | 'end': end_date.isoformat() if end_date else None, 275 | 'Subaccount': sub_account 276 | } 277 | resp = self.post(end_point, payload) 278 | return self.error_check(resp, f) 279 | except Exception as e: 280 | print(f"{f}() fonksiyonunda hata oluştu: {e}") 281 | 282 | def CashFlow(self, sub_account=""): 283 | try: 284 | f = inspect.stack()[0][3] 285 | end_point = URL_CASHFLOW 286 | payload = {'Subaccount': sub_account} 287 | resp = self.post(end_point, payload) 288 | return self.error_check(resp, f) 289 | except Exception as e: 290 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 291 | 292 | def GetCandleData(self, symbol, period): 293 | """ 294 | Belirlediğiniz sembole ait son 250 barlık OHLCV verileri çekilebilir. 295 | symbol: Sembol kodu 296 | period: İstenilen bar periyodu dakikalık olarak girilir.(1,2,5,10,15,30,60,120,240,480,1440(Günlük için)) 297 | 298 | Örnek Body: 299 | { 300 | "symbol": "TSKB", 301 | "period": "1440", 302 | } 303 | """ 304 | try: 305 | f = inspect.stack()[0][3] 306 | end_point = URL_GETCANDLEDATA 307 | payload = { 308 | 'symbol': symbol, 309 | 'period': period 310 | } 311 | resp = self.post(end_point, payload) 312 | return self.error_check(resp, f) 313 | except Exception as e: 314 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 315 | 316 | 317 | # ORDERS 318 | 319 | def SendOrder(self, symbol, direction, pricetype, price, lot, sms, email, subAccount): 320 | """ 321 | :String symbol: Sembol Kodu 322 | :String direction: İşlem Yönü: BUY / SELL (Aliş/Satiş) 323 | :String pricetype: Emir Tipi: piyasa/limit 324 | :String price: Emir tipi limit ise fiyat girilmelidir. (Örn. 1.98 şeklinde girilmelidir.) 325 | :String lot: Emir Adeti 326 | :Bool sms: Sms Gönderim 327 | :Bool email: Email Gönderim 328 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 329 | 330 | Örnek Body: 331 | { 332 | "symbol": "TSKB", 333 | "direction": "BUY", 334 | "pricetype": "limit", 335 | "price": "2.01", 336 | "lot": "1", 337 | "sms": True, 338 | "email": False, 339 | "Subaccount": "" 340 | } 341 | """ 342 | try: 343 | end_point = URL_SENDORDER 344 | payload = { 345 | "symbol": symbol, 346 | "direction": direction, 347 | "pricetype": pricetype, 348 | "price": price, 349 | "lot": lot, 350 | "sms": sms, 351 | "email": email, 352 | "subAccount": subAccount 353 | } 354 | resp = self.post(end_point, payload) 355 | try: 356 | data = resp.json() 357 | return data 358 | except: 359 | f = inspect.stack()[0][3] 360 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 361 | 362 | print(resp.text) 363 | 364 | except Exception as e: 365 | f = inspect.stack()[0][3] 366 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 367 | 368 | 369 | def ModifyOrder(self, id, price, lot, viop, subAccount): 370 | """ 371 | :String id: Emrin ID’ si 372 | :String price: Düzeltilecek Fiyat 373 | :String lot: Lot Miktari (Viop emri ise girilmelidir.) 374 | :Bool viop: Emrin Viop emri olduğunu belirtir. “Viop emri ise true olmalidir.” 375 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 376 | 377 | Örnek Body 378 | { 379 | "id":"001VEV", 380 | "price":"2.04", 381 | "lot":"0", 382 | "viop":false, 383 | "subAccount":"" 384 | } 385 | """ 386 | try: 387 | end_point = URL_MODIFYORDER 388 | payload = { 389 | 'id': id, 390 | 'price': price, 391 | 'lot': lot, 392 | 'viop': viop, 393 | 'subAccount': subAccount 394 | } 395 | resp = self.post(end_point, payload) 396 | try: 397 | data = resp.json() 398 | return data 399 | except: 400 | f = inspect.stack()[0][3] 401 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 402 | 403 | print(resp.text) 404 | 405 | except Exception as e: 406 | f = inspect.stack()[0][3] 407 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 408 | 409 | 410 | def DeleteOrder(self, id, subAccount): 411 | """ 412 | :String id: Emrin ID’ si 413 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 414 | 415 | Örnek Body 416 | { 417 | "id":"001VEV", 418 | "subAccount":"" 419 | } 420 | """ 421 | try: 422 | end_point = URL_DELETEORDER 423 | payload = { 424 | 'id': id, 425 | 'subAccount': subAccount 426 | } 427 | resp = self.post(end_point, payload) 428 | try: 429 | data = resp.json() 430 | return data 431 | except: 432 | f = inspect.stack()[0][3] 433 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 434 | 435 | print(resp.text) 436 | 437 | except Exception as e: 438 | f = inspect.stack()[0][3] 439 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 440 | 441 | 442 | def DeleteOrderViop(self, id, adet, subAccount): 443 | """ 444 | :String id: Emrin ID’ si 445 | :String adet: İptal edilecek adet 446 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 447 | 448 | Örnek Body 449 | { 450 | "id":"001VEV", 451 | "adet":"1", 452 | "subAccount":"" 453 | } 454 | """ 455 | try: 456 | end_point = URL_DELETEORDER 457 | payload = { 458 | 'id': id, 459 | 'adet': adet, 460 | 'subAccount': subAccount 461 | } 462 | resp = self.post(end_point, payload) 463 | try: 464 | data = resp.json() 465 | return data 466 | except: 467 | f = inspect.stack()[0][3] 468 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 469 | 470 | print(resp.text) 471 | 472 | except Exception as e: 473 | f = inspect.stack()[0][3] 474 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 475 | 476 | 477 | def GetEquityOrderHistory(self, id, subAccount): 478 | """ 479 | :String id: Emrin ID’ si 480 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 481 | 482 | Örnek Body 483 | { 484 | "id":"001VEV", 485 | "subAccount":"" 486 | } 487 | """ 488 | try: 489 | end_point = URL_GETEQUITYORDERHISTORY 490 | payload = { 491 | 'id': id, 492 | 'subAccount': subAccount 493 | } 494 | resp = self.post(end_point, payload) 495 | try: 496 | data = resp.json() 497 | return data 498 | except: 499 | f = inspect.stack()[0][3] 500 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 501 | 502 | print(resp.text) 503 | 504 | except Exception as e: 505 | f = inspect.stack()[0][3] 506 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 507 | 508 | 509 | def GetViopOrderHistory(self, id, subAccount): 510 | """ 511 | :String id: Emrin ID’ si 512 | :String subAccount: Alt Hesap Numarasi “Boş gönderilebilir. Boş gönderilir ise Aktif Hesap Bilgilerini getirir.” 513 | 514 | Örnek Body 515 | { 516 | "id":"001VEV", 517 | "subAccount":"" 518 | } 519 | """ 520 | try: 521 | f = inspect.stack()[0][3] 522 | end_point = URL_GETVIOPORDERHISTORY 523 | payload = { 524 | 'id': id, 525 | 'subAccount': subAccount 526 | } 527 | resp = self.post(end_point, payload) 528 | try: 529 | data = resp.json() 530 | return data 531 | except: 532 | f = inspect.stack()[0][3] 533 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 534 | 535 | print(resp.text) 536 | 537 | except Exception as e: 538 | f = inspect.stack()[0][3] 539 | print(f"{f}() fonsiyonunda hata oluştu: {e}") 540 | 541 | # TOOLS 542 | 543 | def GetIsAlive(self): 544 | try: 545 | resp = self.GetSubAccounts(silent=True) 546 | return resp["success"] 547 | except: 548 | return False 549 | 550 | def error_check(self, resp, f, silent=False): 551 | try: 552 | if resp.status_code == 200: 553 | data = resp.json() 554 | return data 555 | else: 556 | if not silent: 557 | print(f"Error kodu: {resp.status_code}") 558 | 559 | print(resp.text) 560 | 561 | return False 562 | except: 563 | if not silent: 564 | print(f"{f}() fonksiyonunda veri tipi hatasi. Veri, json formatindan farkli geldi:") 565 | 566 | print(resp.text) 567 | 568 | return False 569 | 570 | def encrypt(self, text): 571 | iv = b'\0' * 16 572 | key = base64.b64decode(self.api_code.encode('utf-8')) 573 | cipher = AES.new(key, AES.MODE_CBC, iv) 574 | bytes = text.encode() 575 | padded_bytes = pad(bytes, 16) 576 | r = cipher.encrypt(padded_bytes) 577 | return base64.b64encode(r).decode("utf-8") 578 | 579 | def make_checker(self, endpoint, payload): 580 | if len(payload) > 0: 581 | body = json.dumps(payload).replace(' ', '') 582 | else: 583 | body = "" 584 | data = self.api_key + self.api_hostname + endpoint + body 585 | checker = hashlib.sha256(data.encode('utf-8')).hexdigest() 586 | return checker 587 | 588 | def _request(self, method, url, endpoint, payload, headers): 589 | global last_request, LOCK 590 | while LOCK: 591 | time.sleep(0.01) 592 | LOCK = True 593 | try: 594 | response = "" 595 | if method == "POST": 596 | t = time.time() 597 | diff = t - last_request 598 | wait_for = last_request > 0.0 and diff < 5.0 # son işlemden geçen süre 1 saniyeden küçükse bekle 599 | if wait_for: 600 | time.sleep(5 - diff + 0.01) 601 | response = requests.post(url + endpoint, json=payload, headers=headers) 602 | last_request = time.time() 603 | finally: 604 | LOCK = False 605 | return response 606 | 607 | def post(self, endpoint, payload, login=False): 608 | url = self.api_url 609 | if not login: 610 | checker = self.make_checker(endpoint, payload) 611 | headers = {"APIKEY": self.api_key, 612 | "Checker": checker, 613 | "Authorization": self.hash 614 | } 615 | else: 616 | headers = {"APIKEY": self.api_key} 617 | resp = self._request("POST", url, endpoint, payload=payload, headers=headers) 618 | return resp 619 | 620 | is_alive = property(GetIsAlive) 621 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # USER INFO 2 | MY_API_KEY='API-KEY' #API Key'inizi Buraya Giriniz 3 | MY_USERNAME = "TC veya Denizbank Kullanici Adi" #TC veya Denizbank Kullanıcı Adınızı Buraya Giriniz 4 | MY_PASSWORD = "Şifre" #Denizbank İnternet Bankacılığı Şifrenizi Buraya Giriniz 5 | 6 | # URLS 7 | hostname = "www.algolab.com.tr" 8 | api_hostname = f"https://{hostname}" 9 | api_url = api_hostname + "/api" 10 | socket_url = f"wss://{hostname}/api/ws" 11 | 12 | # ORDER STATUS 13 | ORDER_STATUS = {0: "Bekleyen", 14 | 1: "Teslim Edildi", 15 | 2: "Gerçekleşti", 16 | 3: "Kismi Gerçekleşti", 17 | 4: "İptal Edildi", 18 | 5: "Değiştirildi", 19 | 6: "Askiya Alindi", 20 | 7: "Süresi Doldu", 21 | 8: "Hata"} 22 | 23 | # Tick to OHLCV converter için takip edilmesi istenen semboller, boş olarak verilirse tüm semboller veya marketler takip edilir. 24 | TRACKED_SYMBOLS = [] 25 | TRACKED_MARKETS = [] 26 | BUFFER_SIZE = 50000 # Converter için kaç veri sayısı biriktirilip json dosyalarına aktarılmalı 27 | #Sadece IMKBH için 5000 gecikme olmadan çalışmaktadır. Tüm semboller içinse 50000 gecikme olmadan çalışmaktadır. 28 | 29 | # ENDPOINTS 30 | URL_LOGIN_USER = "/api/LoginUser" 31 | URL_LOGIN_CONTROL = "/api/LoginUserControl" 32 | URL_GETEQUITYINFO = "/api/GetEquityInfo" 33 | URL_GETSUBACCOUNTS = "/api/GetSubAccounts" 34 | URL_INSTANTPOSITION = "/api/InstantPosition" 35 | URL_TODAYTRANSACTION = "/api/TodaysTransaction" 36 | URL_VIOPCUSTOMEROVERALL = "/api/ViopCustomerOverall" 37 | URL_VIOPCUSTOMERTRANSACTIONS = "/api/ViopCustomerTransactions" 38 | URL_SENDORDER = "/api/SendOrder" 39 | URL_MODIFYORDER = "/api/ModifyOrder" 40 | URL_DELETEORDER = "/api/DeleteOrder" 41 | URL_DELETEORDERVIOP = "/api/DeleteOrderViop" 42 | URL_SESSIONREFRESH = "/api/SessionRefresh" 43 | URL_GETCANDLEDATA = "/api/GetCandleData" 44 | URL_VIOPCOLLETERALINFO = "/api/ViopCollateralInfo" 45 | URL_RISKSIMULATION = "/api/RiskSimulation" 46 | URL_GETEQUITYORDERHISTORY = "/api/GetEquityOrderHistory" # 404 Hatası alıyor 47 | URL_GETVIOPORDERHISTORY = "/api/GetViopOrderHistory" # 404 Hatası alıyor 48 | URL_CASHFLOW = "/api/CashFlow" 49 | URL_ACCOUNTEXTRE = "/api/AccountExtre" 50 | -------------------------------------------------------------------------------- /ornek.py: -------------------------------------------------------------------------------- 1 | from algolab import API 2 | from datetime import datetime, timezone, timedelta 3 | from config import * 4 | import pandas as pd, numpy as np, json, os 5 | 6 | ############################################ ENDPOINT Fonksiyonlari ################################################## 7 | 8 | ### Emir Bilgisi 9 | def send_order(): 10 | symbol=input("Lütfen Sembol Bilgisi Girin: ") 11 | print("\nLütfen Yapacağiniz işlemi giriniz?") 12 | print("'1' Alım") 13 | print("'2' Satım") 14 | direction = input("\nSeçiminiz: ") 15 | if direction == '1': 16 | direction="Buy" 17 | elif direction == '2': 18 | direction="Sell" 19 | else: 20 | print("Geçersiz seçim.") 21 | send_order() # Kullanici hatali seçim yapti, menüye dön 22 | 23 | print("\nLütfen Emir Tipi Bilgisi Girin?") 24 | print("'1' Limit") 25 | print("'2' Piyasa") 26 | pricetype = input("\nSeçiminiz: ") 27 | if pricetype == '1': 28 | pricetype="limit" 29 | elif pricetype == '2': 30 | pricetype="piyasa" 31 | else: 32 | print("Geçersiz seçim.") 33 | send_order() # Kullanici hatali seçim yapti, menüye dön 34 | 35 | lot=input("\nLütfen Lot Bilgisi Girin: ") 36 | if pricetype=='piyasa': 37 | price="" 38 | else: 39 | price=input("Lütfen Fiyat Bilgisi Girin: ") 40 | order = Conn.SendOrder(symbol=symbol, direction= direction, pricetype= pricetype, price=price, lot=lot ,sms=False,email=False,subAccount="") 41 | print("\nEmir gönderme isteği atılıyor...\n") 42 | if order: 43 | try: 44 | succ = order["success"] 45 | if succ: 46 | content = order["content"] 47 | print("Emir İletildi, Dönen cevap: " + content) 48 | else: print(order["message"]) 49 | except Exception as e: 50 | print(f"Hata oluştu: {e}") 51 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 52 | order_menu() 53 | 54 | def modify_order(): 55 | id=input("Lütfen ID Bilgisi Girin: ") 56 | print("\n Viop emri mi değiştirmek istiyorsunuz?") 57 | print("'1' Hayır") 58 | print("'2' Evet") 59 | viop = input("\nSeçiminiz: ") 60 | if viop == '1': 61 | viop=False 62 | elif viop == '2': 63 | viop=True 64 | else: 65 | print("Geçersiz seçim.") 66 | modify_order() # Kullanici hatali seçim yapti, menüye dön 67 | if viop: 68 | lot=input("Lütfen Lot Bilgisi Girin: ") 69 | else: 70 | lot="" 71 | price=input("Lütfen Yeni Fiyat Bilgisi Girin: ") 72 | modify=Conn.ModifyOrder(id=id,price=price,lot=lot,viop=viop,subAccount="") 73 | print("\nEmir değiştirme isteği atılıyor...\n") 74 | if modify: 75 | try: 76 | succ = modify["success"] 77 | if succ: 78 | content = modify["content"] 79 | print("Emir Düzeltildi") 80 | else: print(modify["message"]) 81 | except Exception as e: 82 | print(f"Hata oluştu: {e}") 83 | 84 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 85 | order_menu() 86 | 87 | def delete_order(): 88 | id=input("Lütfen ID Bilgisi Girin: ") 89 | delete=Conn.DeleteOrder(id=id,subAccount="") 90 | print("\nEmir silme isteği atılıyor...\n") 91 | if delete: 92 | try: 93 | succ = delete["success"] 94 | if succ: 95 | content = delete["content"] 96 | content_json = json.dumps(content) 97 | print("Emir Silindi, " + content_json) 98 | else: print(delete["message"]) 99 | except Exception as e: 100 | print(f"Hata oluştu: {e}") 101 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 102 | return 103 | 104 | def delete_order_viop(): 105 | id=input("Lütfen ID Bilgisi Girin: ") 106 | adet=input("Lütfen Kontrat Sayisi Girin: ") 107 | delete=Conn.DeleteOrderViop(id=id,adet=adet,subAccount="") 108 | print("\nViop Emir Silme isteği atılıyor...\n") 109 | if delete: 110 | try: 111 | succ = delete["success"] 112 | if succ: 113 | content = delete["content"] 114 | content_json = json.dumps(content) 115 | print("Emir Silindi, " + content_json) 116 | else: print(delete["message"]) 117 | except Exception as e: 118 | print(f"Hata oluştu: {e}") 119 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 120 | return 121 | 122 | ### Sembol Bilgisi 123 | def get_candle_data(): 124 | symbol=input("Lütfen Sembol Bilgisi Girin: ") 125 | period=input("Lütfen Periyot Bilgisi Girin: ") 126 | candle = Conn.GetCandleData(symbol, period) 127 | print("\nOHLCV barları verisi görüntüleme isteği atılıyor...\n") 128 | if candle: 129 | try: 130 | succ = candle["success"] 131 | if succ: 132 | ohlc = [] 133 | content = candle["content"] 134 | for i in range(len(content)): 135 | d = content[i]["date"] 136 | try: 137 | dt = datetime.strptime(d, "%Y-%m-%dT%H:%M:%S").strftime("%Y-%m-%d %H:%M:%S") 138 | except: 139 | dt = datetime.strptime(d, "%Y-%m-%dT%H:%M:%S%z").strftime("%Y-%m-%d %H:%M:%S") 140 | o = content[i]["open"] 141 | h = content[i]["high"] 142 | l = content[i]["low"] 143 | c = content[i]["close"] 144 | v = content[i]["volume"] 145 | a = content[i]["amount"] 146 | ohlc.append([dt, o, h, l, c, v, a]) 147 | # oluşturduğumuz listi pandas dataframe'e aktariyoruz 148 | df = pd.DataFrame(columns=["date", "open", "high", "low", "close", "volume", "amount"], data=np.array(ohlc)) 149 | print(df.tail()) 150 | else: print(candle["message"]) 151 | except Exception as e: 152 | print(f"Hata oluştu: {e}") 153 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 154 | return 155 | 156 | def get_equity_info(): 157 | symbol=input("Lütfen Sembol Bilgisi Girin: ") 158 | print("\nSembol bilgisi görüntüleme isteği atılıyor...\n") 159 | info=Conn.GetEquityInfo(symbol=symbol) 160 | if info: 161 | try: 162 | succ = info["success"] 163 | if succ: 164 | content = info["content"] 165 | df = pd.DataFrame(content,index=[0]) 166 | print(df) 167 | else: print(info["message"]) 168 | except Exception as e: 169 | print(f"Hata oluştu: {e}") 170 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 171 | return 172 | 173 | ### result bilgisi 174 | def get_instant_position(): 175 | print("\nPortöy görüntüleme isteği atılıyor...\n") 176 | result=Conn.GetInstantPosition() 177 | if result: 178 | try: 179 | succ = result["success"] 180 | if succ: 181 | content = result["content"] 182 | df = pd.DataFrame(content) 183 | print(df) 184 | else: print(result["message"]) 185 | except Exception as e: 186 | print(f"Hata oluştu: {e}") 187 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 188 | return 189 | 190 | def get_viop_customer_overall(): 191 | print("\n Viop overall bilgisi görüntüleme isteği atılıyor...\n") 192 | result=Conn.GetViopCustomerOverall() 193 | if result: 194 | try: 195 | succ = result["success"] 196 | if succ: 197 | content = result["content"] 198 | df = pd.DataFrame(content) 199 | print(df) 200 | else: print(result["message"]) 201 | except Exception as e: 202 | print(f"Hata oluştu: {e}") 203 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 204 | return 205 | 206 | def get_subaccounts(): 207 | print("\nAlt Hesap görüntüleme isteği atılıyor...\n") 208 | result=Conn.GetSubAccounts() 209 | if result: 210 | try: 211 | succ = result["success"] 212 | if succ: 213 | content = result["content"] 214 | df = pd.DataFrame(content) 215 | print(df) 216 | else: print(result["message"]) 217 | except Exception as e: 218 | print(f"Hata oluştu: {e}") 219 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 220 | return 221 | 222 | ### İşlem Bilgisi 223 | def get_todays_transaction(): 224 | islem=Conn.GetTodaysTransaction() 225 | print("\nGünlük işlem listesi çekme isteği atılıyor...\n") 226 | if islem: 227 | try: 228 | succ = islem["success"] 229 | if succ: 230 | content = islem["content"] 231 | df = pd.DataFrame(content) 232 | print(df) 233 | else: print(islem["message"]) 234 | except Exception as e: 235 | print(f"Hata oluştu: {e}") 236 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 237 | return 238 | 239 | def get_viop_customer_transactions(): 240 | islem=Conn.GetViopCustomerTransactions() 241 | print("\nViop Günlük İşlemleri görüntüleme isteği atılıyor...\n") 242 | if islem: 243 | try: 244 | succ = islem["success"] 245 | if succ: 246 | content = islem["content"] 247 | df = pd.DataFrame(content) 248 | print(df) 249 | else: print(islem["message"]) 250 | except Exception as e: 251 | print(f"Hata oluştu: {e}") 252 | 253 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 254 | return 255 | 256 | ### Oturum Süresi Uzatma 257 | def session_refresh(): 258 | print("\nOturum süresi uzatma isteği atılıyor...\n") 259 | islem=Conn.SessionRefresh() 260 | print(islem) 261 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 262 | return 263 | 264 | ### Yeni eklenen Endpointler 265 | def get_equity_order_history(): 266 | id=input("Lütfen ID Bilgisi Girin: ") 267 | print("\nPay emir Tarihçesi isteği atılıyor...\n") 268 | result=Conn.GetEquityOrderHistory(id=id,subAccount="") 269 | if result: 270 | try: 271 | succ = result["success"] 272 | if succ: 273 | content = result["content"] 274 | df = pd.DataFrame(content) 275 | print(df) 276 | else: print(result["message"]) 277 | except Exception as e: 278 | print(f"Hata oluştu: {e}") 279 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 280 | return 281 | 282 | def account_extre(): 283 | days=int(input("Kaç Günlük ekstre çekmek istersiniz?: ")) 284 | print("Hangi tipte ekstre çekmek istersiniz?") 285 | print("'1' Hesap Ekstresi") 286 | print("'2' Viop Ekstresi") 287 | ekstretipi = input("\nSeçiminiz: ") 288 | if ekstretipi == '1': 289 | ekstretipi="accountextre" 290 | elif ekstretipi == '2': 291 | ekstretipi="viopextre" 292 | else: 293 | print("Geçersiz seçim.") 294 | account_extre() # Kullanici hatali seçim yapti, başa dön 295 | 296 | end_date = datetime.now(timezone(timedelta(hours=3))) 297 | start_date = end_date - timedelta(days=days) 298 | print("\nEkstre çekme isteği atılıyor...\n") 299 | result = Conn.AccountExtre(start_date=start_date, end_date=end_date) 300 | if result: 301 | try: 302 | succ = result["success"] 303 | if succ: 304 | content = result['content'][ekstretipi] 305 | df = pd.DataFrame(content) 306 | print(df) 307 | else: 308 | print(result.get('message', 'Bilinmeyen bir hata oluştu.')) 309 | except Exception as e: 310 | print(f"Hata oluştu: {e}") 311 | 312 | input("Önceki menüye dönmek için herhangi bir tuşa basın: ") 313 | return 314 | 315 | def cash_flow(): 316 | print("\nNakit Akış tablosu görüntüleme isteği atılıyor...\n") 317 | result=Conn.CashFlow() 318 | if result: 319 | try: 320 | if result['success']: 321 | content = result["content"] 322 | df = pd.DataFrame(content,index=[0]) 323 | print(df) 324 | else: print(result["message"]) 325 | except Exception as e: 326 | print(f"Hata oluştu: {e}") 327 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 328 | return 329 | 330 | def get_viop_order_history(): 331 | print("\nViop emir tarihçesi görütüleme isteği atılıyor...\n") 332 | id=input("Lütfen ID Bilgisi Girin: ") 333 | result=Conn.GetViopOrderHistory(id=id,subAccount="") 334 | if result: 335 | try: 336 | succ = result["success"] 337 | if succ: 338 | content = result["content"] 339 | df = pd.DataFrame(content) 340 | print(df) 341 | else: print(result["message"]) 342 | except Exception as e: 343 | print(f"Hata oluştu: {e}") 344 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 345 | return 346 | 347 | def risk_simulation(): 348 | print("\nKredi risk simülasyonu tablosu görüntüleme isteği atılıyor...\n") 349 | result=Conn.RiskSimulation() 350 | if result: 351 | try: 352 | succ = result["success"] 353 | if succ: 354 | content = result["content"] 355 | df = pd.DataFrame(content,index=[0]) 356 | print(df) 357 | else: print(result["message"]) 358 | except Exception as e: 359 | print(f"Hata oluştu: {e}") 360 | input("Ana menüye dönmek için herhangi tuşuna basin: ") 361 | return 362 | 363 | def viop_collateral_info(): 364 | print("\nViop Teminat tablosu görüntüleme isteği atılıyor...\n") 365 | result=Conn.ViopColleteralInfo() 366 | if result: 367 | try: 368 | succ = result["success"] 369 | if succ: 370 | content = result["content"] 371 | df = pd.DataFrame(content,index=[0]) 372 | print(df) 373 | else: print(result["message"]) 374 | except Exception as e: 375 | print(f"Hata oluştu: {e}") 376 | input("\nÖnceki menüye dönmek için herhangi tuşuna basin: ") 377 | return 378 | 379 | ############################################ MENÜLER################################################## 380 | 381 | def main_menu(): 382 | while True: 383 | print("\nAna Menüye hoş geldiniz. Lütfen yapmak istediğiniz işlemi seçin:") 384 | print("'1' Emir Menüsü") 385 | print("'2' Sembol Barlarini Çekme") 386 | print("'3' Sembol Bilgisi Çekme") 387 | print("'4' Hesap Bilgisi Menüsü") 388 | print("'5' Günlük İşlemleri Çekme") 389 | print("'6' Viop Günlük İşlemleri Çekme") 390 | print("'7' Kredi Risk Simülasyonu") 391 | print("'8' Viop Teminat Bilgisi") 392 | print("'9' Hesap Ekstresi Bilgisi") 393 | print("'0' Oturum Süresi Uzatma") 394 | print("'*' Çikiş") 395 | secim = input("\nSeçiminiz: ") 396 | 397 | if secim == '1': 398 | if order_menu(): 399 | continue 400 | elif secim == '2': 401 | if get_candle_data(): 402 | continue 403 | elif secim == '3': 404 | if get_equity_info(): 405 | continue 406 | elif secim == '4': 407 | if account_menu(): 408 | continue 409 | elif secim == '5': 410 | if get_todays_transaction(): 411 | continue 412 | elif secim == '6': 413 | if get_viop_customer_transactions(): 414 | continue 415 | elif secim == '7': 416 | if risk_simulation(): 417 | continue 418 | elif secim == '8': 419 | if viop_collateral_info(): 420 | continue 421 | elif secim == '9': 422 | if account_extre(): 423 | continue 424 | elif secim == '0': 425 | if session_refresh(): 426 | continue 427 | elif secim == '*': 428 | print("Çikiş yapiliyor...") 429 | os._exit(0) # 0 başarili çikişi temsil eder 430 | else: 431 | print("Geçersiz seçim.") 432 | continue # Kullanici hatali seçim yapti, ana menüye dön 433 | 434 | def order_menu(): 435 | while True: 436 | print("\nLütfen yapmak istediğiniz işlemi seçin:") 437 | print("'1' Emir Gönder") 438 | print("'2' Emir Düzelt") 439 | print("'3' Emir Sil") 440 | print("'4' Viop Emir Sil") 441 | print("'5' Para Akişi") 442 | print("'6' Pay Emir Tarihçesi") 443 | print("'7' Viop Emir Tarihçesi") 444 | print("'0' Ana Menü") 445 | secim = input("\nSeçiminiz: ") 446 | 447 | if secim == '1': 448 | if send_order(): 449 | continue 450 | elif secim == '2': 451 | if modify_order(): 452 | continue 453 | elif secim == '3': 454 | if delete_order(): 455 | continue 456 | elif secim == '4': 457 | if delete_order_viop(): 458 | continue 459 | elif secim == '5': 460 | if cash_flow(): 461 | continue 462 | elif secim == '6': 463 | if get_equity_order_history(): 464 | continue 465 | elif secim == '7': 466 | if get_viop_order_history(): 467 | continue 468 | elif secim == '0': 469 | main_menu() 470 | else: 471 | print("Geçersiz seçim.") 472 | continue # Kullanici hatali seçim yapti, menüye dön 473 | 474 | def account_menu(): 475 | while True: 476 | print("\nLütfen yapmak istediğiniz işlemi seçin:") 477 | print("'1' Alt Hesaplari Görüntüle") 478 | print("'2' Portföy Bilgisi") 479 | print("'3' Viop Overall Bilgisi") 480 | print("'0' Ana Menü") 481 | secim = input("\nSeçiminiz: ") 482 | 483 | if secim == '1': 484 | if get_subaccounts(): 485 | continue 486 | elif secim == '2': 487 | if get_instant_position(): 488 | continue 489 | elif secim == '3': 490 | if get_viop_customer_overall(): 491 | continue 492 | elif secim == '0': 493 | main_menu() 494 | else: 495 | print("Geçersiz seçim.") 496 | continue # Kullanici hatali seçim yapti, menüye dön 497 | 498 | if __name__ == "__main__": 499 | # Login olarak, token aliyoruz 500 | try: 501 | Conn = API(api_key=MY_API_KEY, username=MY_USERNAME, password=MY_PASSWORD, auto_login=True, verbose=True) 502 | if Conn.is_alive == True: 503 | main_menu() # ana menüye dönüyoruz 504 | else: 505 | print("Giriş yapılamadı.") 506 | except Exception as e: 507 | print(f"Hata oluştu: {e}") 508 | -------------------------------------------------------------------------------- /ornek_soket.py: -------------------------------------------------------------------------------- 1 | from algolab import API 2 | from ws import AlgoLabSocket 3 | import json,time 4 | from config import * 5 | 6 | def process_msg(msg): 7 | try: 8 | t = msg["type"] 9 | content = msg["content"] 10 | print("Type: " + t +"Content: " + content) 11 | except Exception as e: 12 | print("Error processing message: ", e) 13 | 14 | if __name__ == "__main__": 15 | 16 | algo = API(api_key=MY_API_KEY, username=MY_USERNAME, password=MY_PASSWORD, auto_login=True) 17 | soket = AlgoLabSocket(algo.api_key, algo.hash, "T") 18 | soket.connect() 19 | while not soket.connected: 20 | time.sleep(0.001) 21 | 22 | data = {"Type": "T", "Symbols": ["ALL"]} 23 | soket.send(data) 24 | 25 | i = 0 26 | while soket.connected: 27 | data = soket.recv() 28 | i += 1 29 | if data: 30 | try: 31 | msg = json.loads(data) 32 | print(msg) 33 | except: 34 | print("error 1") 35 | soket.close() 36 | break 37 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.23.3 2 | pandas==1.5.0 3 | pycryptodome==3.16.0 4 | requests==2.28.1 5 | setuptools==65.6.3 6 | websocket_client==1.4.2 7 | schedule 8 | -------------------------------------------------------------------------------- /tick_to_ohlcv_converter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import asyncio 5 | import threading 6 | import time 7 | import logging 8 | import pandas as pd 9 | from datetime import datetime 10 | from algolab import API 11 | from ws import AlgoLabSocket 12 | from config import * 13 | import sys 14 | 15 | logging.basicConfig( 16 | filename="converter_logs.log", 17 | level=logging.INFO, 18 | format='%(asctime)s - %(levelname)s - %(message)s', 19 | filemode='w' 20 | ) 21 | 22 | # Constants 23 | RESAMPLE_INTERVAL = '1min' # OHLCV verilerinin yeniden örnekleme aralığı 24 | MAX_BUFFER_SIZE = BUFFER_SIZE if 'BUFFER_SIZE' in globals() else 100 # Maksimum tampon boyutu 25 | last_trade_time = None # Son işlem zamanını takip etmek için 26 | stop_session_thread = False # Oturum yenileme thread'ini kontrol etmek için 27 | first_trade_processed = False # İlk işlem işlenip işlenmediğini takip etmek için 28 | first_log_shown = False # İlk log gösterildi mi kontrolü için 29 | 30 | # Initialize API and websocket 31 | algo = API(api_key=MY_API_KEY, username=MY_USERNAME, password=MY_PASSWORD, auto_login=True, keep_alive=False) 32 | soket = None 33 | 34 | # In-memory data stores 35 | trade_data_buffer = {} # İşlem verilerini geçici olarak saklar. Format: (sembol, piyasa) -> [(tarih, fiyat, miktar),...] 36 | ohlcv_cache = {} # OHLCV verilerini önbellekte tutar. Format: (sembol, piyasa) -> DataFrame 37 | 38 | 39 | def session_refresh(): 40 | """API oturumunu ve soket bağlantısını yeniler.""" 41 | global soket 42 | try: 43 | logging.info("Starting session refresh...") 44 | 45 | if not soket.connected: 46 | logging.warning("Socket is not connected during session refresh.") 47 | return False 48 | 49 | success = algo.SessionRefresh() 50 | if not success: 51 | logging.error("API session refresh failed") 52 | return False 53 | 54 | data_request = {"Type": "H"} 55 | if not soket.send(data_request): 56 | logging.error("Failed to send heartbeat") 57 | return False 58 | 59 | logging.info("Session refresh completed successfully") 60 | return True 61 | 62 | except Exception as e: 63 | logging.error(f"Session refresh error: {e}") 64 | return False 65 | 66 | 67 | def load_or_create_ohlcv(symbol, market): 68 | """ 69 | Belirtilen sembol ve piyasa için OHLCV verilerini yükler veya yeni oluşturur. 70 | """ 71 | key = (symbol, market) 72 | if key in ohlcv_cache: 73 | return ohlcv_cache[key] 74 | 75 | candles_folder_path = os.path.join("db", "candles", market) 76 | os.makedirs(candles_folder_path, exist_ok=True) 77 | candles_path = os.path.join(candles_folder_path, f"{symbol}.json") 78 | 79 | if os.path.exists(candles_path): 80 | try: 81 | # Dosya boyutunu kontrol et 82 | if os.path.getsize(candles_path) == 0: 83 | logging.warning(f"Empty file found: {candles_path}, creating new DataFrame") 84 | raise ValueError("Empty file") 85 | 86 | with open(candles_path, 'r', encoding='utf-8') as f: 87 | data = json.load(f) 88 | 89 | if not data: # Boş liste kontrolü 90 | raise ValueError("Empty JSON data") 91 | 92 | df = pd.DataFrame(data) 93 | 94 | # Gerekli sütunların varlığını kontrol et 95 | required_columns = ["Date", "Open", "High", "Low", "Close", "Volume"] 96 | if not all(col in df.columns for col in required_columns): 97 | raise ValueError("Missing required columns") 98 | 99 | except (json.JSONDecodeError, ValueError) as e: 100 | logging.warning(f"Invalid JSON in {candles_path}, creating an empty DataFrame. Error: {e}") 101 | # Bozuk dosyayı yedekle 102 | if os.path.exists(candles_path): 103 | backup_path = candles_path + '.bak' 104 | try: 105 | os.rename(candles_path, backup_path) 106 | logging.info(f"Backed up corrupted file to {backup_path}") 107 | except Exception as e: 108 | logging.error(f"Failed to backup corrupted file: {e}") 109 | 110 | df = pd.DataFrame(columns=["Date", "Open", "High", "Low", "Close", "Volume"]) 111 | else: 112 | df = pd.DataFrame(columns=["Date", "Open", "High", "Low", "Close", "Volume"]) 113 | 114 | try: 115 | # Ensure correct dtypes 116 | df["Date"] = pd.to_datetime(df["Date"], errors='coerce') 117 | df.set_index("Date", inplace=True) 118 | 119 | # NaN değerleri temizle 120 | df = df.dropna(how='all') # Tüm değerleri NaN olan satırları sil 121 | df.fillna(0, inplace=True) # Kalan NaN değerleri 0'a çevir 122 | 123 | except Exception as e: 124 | logging.error(f"Error processing DataFrame for {symbol}-{market}: {e}") 125 | df = pd.DataFrame(columns=["Date", "Open", "High", "Low", "Close", "Volume"]) 126 | df.set_index("Date", inplace=True) 127 | 128 | ohlcv_cache[key] = df 129 | return df 130 | 131 | 132 | def process_incoming_trade(content): 133 | """ 134 | Gelen işlem verilerini işler ve tampona ekler. 135 | İlk çalıştığında bir sonraki periyodun başlangıcını bekler. 136 | 137 | Args: 138 | content (dict): İşlem verilerini içeren sözlük 139 | """ 140 | global last_trade_time, first_log_shown 141 | 142 | try: 143 | symbol = content["Symbol"] 144 | market = content["Market"] 145 | price = float(content["Price"] or 0) 146 | qty = float(content["TradeQuantity"] or 0) 147 | 148 | # Parse as UTC 149 | timestamp = pd.to_datetime(content["Date"], utc=True) 150 | # Convert to Europe/Istanbul time 151 | timestamp = timestamp.tz_convert('Europe/Istanbul') 152 | # Convert to tz-naive 153 | timestamp = timestamp.tz_localize(None) 154 | 155 | # İlk veri için bir sonraki periyodun başlangıç zamanını hesapla 156 | if last_trade_time is None: 157 | # Her zaman bir sonraki dakikaya yuvarla 158 | next_period = timestamp.ceil('1min') 159 | if not first_log_shown: 160 | logging.info(f"Waiting for next period: {next_period}") 161 | first_log_shown = True 162 | 163 | # Eğer şu anki veri bu periyoddan önceyse, kaydetme 164 | if timestamp < next_period: 165 | return 166 | 167 | last_trade_time = timestamp 168 | 169 | # Update last trade time 170 | last_trade_time = timestamp 171 | 172 | key = (symbol, market) 173 | if key not in trade_data_buffer: 174 | trade_data_buffer[key] = [] 175 | trade_data_buffer[key].append((timestamp, price, qty)) 176 | 177 | except Exception as e: 178 | logging.error(f"Error processing trade: {e}, content: {content}") 179 | 180 | def resample_and_merge_ohlcv(): 181 | """ 182 | Tamponda biriken işlem verilerini OHLCV formatına dönüştürür. 183 | 184 | İşlemler: 185 | 1. Her sembol-piyasa çifti için: 186 | - İşlem verilerini DataFrame'e dönüştürür 187 | - Belirtilen aralıkta yeniden örnekler (OHLCV) 188 | - Mevcut verilerle birleştirir 189 | 2. İşlem tamponunu temizler 190 | """ 191 | global trade_data_buffer 192 | for (symbol, market), trades in trade_data_buffer.items(): 193 | if not trades: 194 | continue 195 | 196 | try: 197 | df_temp = pd.DataFrame(trades, columns=["Date", "Price", "TradeQuantity"]) 198 | df_temp.set_index("Date", inplace=True) 199 | df_temp["Volume"] = df_temp["Price"] * df_temp["TradeQuantity"] 200 | 201 | # Resample to OHLCV 202 | ohlcv_resampled = df_temp.resample(RESAMPLE_INTERVAL).agg({ 203 | "Price": ["first", "max", "min", "last"], 204 | "Volume": "sum", 205 | "TradeQuantity": "sum" 206 | }) 207 | ohlcv_resampled.columns = ["Open", "High", "Low", "Close", "Volume", "Amount"] 208 | 209 | # Merge with existing OHLCV 210 | ohlcv_df = load_or_create_ohlcv(symbol, market) 211 | 212 | # Amount sütununu kontrol et ve gerekirse oluştur 213 | if 'Amount' not in ohlcv_df.columns: 214 | ohlcv_df['Amount'] = 0.0 215 | 216 | for idx, row in ohlcv_resampled.iterrows(): 217 | if idx in ohlcv_df.index: 218 | # Update row 219 | ohlcv_df.at[idx, 'High'] = max(ohlcv_df.at[idx, 'High'], row['High']) 220 | ohlcv_df.at[idx, 'Low'] = min(ohlcv_df.at[idx, 'Low'], row['Low']) 221 | ohlcv_df.at[idx, 'Close'] = row['Close'] 222 | ohlcv_df.at[idx, 'Volume'] = round(ohlcv_df.at[idx, 'Volume'] + row['Volume'], 2) 223 | ohlcv_df.at[idx, 'Amount'] = round(ohlcv_df.at[idx, 'Amount'] + row['Amount'], 2) 224 | else: 225 | # Add new row 226 | ohlcv_df.loc[idx] = row 227 | 228 | ohlcv_df.sort_index(inplace=True) 229 | except Exception as e: 230 | logging.error(f"Error processing data for {symbol}-{market}: {e}") 231 | 232 | trade_data_buffer.clear() 233 | 234 | 235 | def write_ohlcv_to_disk(): 236 | """ 237 | OHLCV verilerini diske JSON formatında kaydeder. 238 | 239 | İşlemler: 240 | 1. Her sembol-piyasa çifti için: 241 | - Eksik sütunları kontrol eder ve doldurur 242 | - NaN değerleri temizler 243 | - Tarih formatını düzenler 244 | - JSON dosyasına kaydeder 245 | 2. Son işlem zamanını loglar 246 | """ 247 | global last_trade_time 248 | 249 | try: 250 | now = datetime.now() 251 | 252 | for (symbol, market), df in ohlcv_cache.items(): 253 | if df.empty: 254 | logging.warning(f"OHLCV DataFrame for {symbol}-{market} is empty. Skipping write.") 255 | continue 256 | 257 | # Kontrol: Tüm sütunların eksiksiz olduğundan emin olun 258 | required_columns = ["Open", "High", "Low", "Close", "Volume"] 259 | for col in required_columns: 260 | if col not in df.columns: 261 | logging.warning(f"Missing column '{col}' in OHLCV for {symbol}-{market}. Filling with 0. Content: {df}") 262 | df[col] = 0 # Eksik sütunları sıfırlarla doldur 263 | 264 | # Kontrol: NaN değerleri tespit edip doldur 265 | if df.isnull().values.any(): 266 | logging.warning(f"NaN values detected in OHLCV for {symbol}-{market}. Applying corrections. Content: {df}") 267 | df.fillna(method="ffill", inplace=True) # Forward fill 268 | df.fillna(0, inplace=True) # Hala eksik olanları sıfırla 269 | 270 | # Dosya yollarını oluştur 271 | candles_folder_path = os.path.join("db", "candles", market) 272 | os.makedirs(candles_folder_path, exist_ok=True) 273 | candles_path = os.path.join(candles_folder_path, f"{symbol}.json") 274 | 275 | # JSON'a yazmadan önce tarih formatını kontrol et 276 | df_to_write = df.copy() 277 | df_to_write.reset_index(inplace=True) 278 | 279 | try: 280 | df_to_write["Date"] = df_to_write["Date"].apply( 281 | lambda x: x.strftime('%Y-%m-%dT%H:%M:%S') + f'.{int(x.microsecond / 1000):03d}' 282 | ) 283 | except Exception as e: 284 | logging.error(f"Error formatting Date column for {symbol}-{market}: {e}. Skipping file.") 285 | continue 286 | 287 | # JSON'a yaz 288 | with open(candles_path, 'w', encoding='utf-8') as f: 289 | json.dump(df_to_write.to_dict(orient='records'), f, indent=4, ensure_ascii=False) 290 | 291 | # Son işlem zamanı kaydını logla 292 | if last_trade_time is not None: 293 | time_diff = now - last_trade_time 294 | logging.info( 295 | f"Last trade time: {last_trade_time}, system time: {now}, " 296 | f"difference: {time_diff.total_seconds():.3f} seconds." 297 | ) 298 | else: 299 | logging.info("No trades processed yet.") 300 | except Exception as e: 301 | logging.error(f"Error writing data to disk: {e}") 302 | 303 | 304 | async def reconnect_socket(max_retries=3): 305 | """ 306 | Soket bağlantısını yeniden kurmaya çalışır. 307 | 308 | Args: 309 | max_retries (int): Maksimum deneme sayısı 310 | 311 | Returns: 312 | bool: Bağlantı başarılı ise True, değilse False 313 | """ 314 | global soket, algo 315 | for attempt in range(1, max_retries+1): 316 | try: 317 | logging.info(f"Attempting socket reconnect... Attempt: {attempt}") 318 | algo.SessionRefresh() 319 | soket = AlgoLabSocket(algo.api_key, algo.hash, "H") 320 | if soket.connect(): 321 | logging.info("Socket reconnected successfully.") 322 | data_request = {"Type": "T", "Symbols": ["ALL"]} 323 | soket.send(data_request) 324 | return True 325 | await asyncio.sleep(2) 326 | except Exception as e: 327 | logging.error(f"Reconnection attempt {attempt} failed: {e}") 328 | await asyncio.sleep(5) 329 | 330 | logging.error("All reconnection attempts failed") 331 | return False 332 | 333 | 334 | async def process_messages(): 335 | """Ana mesaj işleme döngüsü.""" 336 | global soket 337 | data_request = {"Type": "T", "Symbols": ["ALL"]} 338 | soket.send(data_request) 339 | trade_count = 0 340 | last_write_time = time.time() 341 | last_heartbeat_time = time.time() 342 | heartbeat_interval = 30 # 30 saniyede bir kontrol et 343 | 344 | while True: 345 | try: 346 | current_time = time.time() 347 | 348 | # Soket bağlantısını düzenli kontrol et 349 | if current_time - last_heartbeat_time > heartbeat_interval: 350 | if not soket.connected: 351 | logging.error(f"Socket connection lost at {datetime.now()}") 352 | if not await reconnect_socket(): 353 | logging.error("Failed to reconnect after socket loss") 354 | if trade_count > 0: 355 | resample_and_merge_ohlcv() 356 | write_ohlcv_to_disk() 357 | return False 358 | else: 359 | logging.info("Socket connection is alive") # Bağlantı durumu log 360 | last_heartbeat_time = current_time 361 | 362 | # Her 5 dakikada bir verileri diske yaz 363 | if current_time - last_write_time > 300: 364 | if trade_count > 0: 365 | resample_and_merge_ohlcv() 366 | write_ohlcv_to_disk() 367 | trade_count = 0 368 | last_write_time = current_time 369 | 370 | msg = soket.recv() 371 | if not msg: 372 | await asyncio.sleep(0.001) 373 | continue 374 | 375 | try: 376 | message = json.loads(msg) 377 | content = message.get("Content", {}) 378 | mtype = message.get("Type", "") 379 | 380 | if mtype != "O" and "Market" in content and "Symbol" in content: 381 | if (not TRACKED_MARKETS and not TRACKED_SYMBOLS) or \ 382 | (content["Market"] in TRACKED_MARKETS) or \ 383 | (content["Symbol"] in TRACKED_SYMBOLS): 384 | process_incoming_trade(content) 385 | trade_count += 1 386 | 387 | if trade_count >= MAX_BUFFER_SIZE: 388 | resample_and_merge_ohlcv() 389 | write_ohlcv_to_disk() 390 | trade_count = 0 391 | except Exception as e: 392 | logging.error(f"Error processing message: {e}, Raw: {msg}") 393 | soket.close() 394 | continue 395 | 396 | except Exception as e: 397 | logging.error(f"Error in main loop at {datetime.now()}: {e}") 398 | await asyncio.sleep(1) 399 | 400 | 401 | async def main(): 402 | """Ana program döngüsü.""" 403 | # Session refresh thread'ini başlat 404 | session_thread = threading.Thread(target=threaded_session_refresh) 405 | session_thread.daemon = True 406 | session_thread.start() 407 | 408 | try: 409 | # Ana mesaj işleme döngüsünü çalıştır 410 | await process_messages() 411 | finally: 412 | # Program sonlandığında thread'i durdur 413 | global stop_session_thread 414 | stop_session_thread = True 415 | session_thread.join(timeout=2) # Thread'in durmasını bekle 416 | 417 | 418 | def threaded_session_refresh(): 419 | """Thread olarak çalışan session refresh fonksiyonu""" 420 | global stop_session_thread 421 | while not stop_session_thread: 422 | try: 423 | session_refresh() 424 | time.sleep(120) # 60 saniye bekle 425 | except Exception as e: 426 | logging.error(f"Error in session refresh thread: {e}") 427 | time.sleep(5) # Hata durumunda 5 saniye bekle 428 | 429 | 430 | if __name__ == "__main__": 431 | """ 432 | Program başlangıç noktası. 433 | 434 | İşlemler: 435 | 1. Soket bağlantısını kurar 436 | 2. Bağlantı başarısız olursa 3 kez dener 437 | 3. Ana döngüyü başlatır 438 | 4. Hata durumunda kalan verileri kaydeder 439 | """ 440 | retry_count = 0 441 | max_retries = 3 442 | 443 | while retry_count < max_retries: 444 | try: 445 | # Initialize the websocket 446 | soket = AlgoLabSocket(algo.api_key, algo.hash, "H") 447 | 448 | if not soket.connect(): 449 | logging.error("Initial socket connection failed.") 450 | retry_count += 1 451 | time.sleep(5) 452 | continue 453 | 454 | # Run the asyncio event loop 455 | asyncio.run(main()) 456 | break 457 | 458 | except Exception as e: 459 | logging.error(f"Unexpected error in the program: {e}") 460 | retry_count += 1 461 | time.sleep(5) 462 | 463 | finally: 464 | # Save any remaining data 465 | if any(len(v) > 0 for v in trade_data_buffer.values()): 466 | resample_and_merge_ohlcv() 467 | write_ohlcv_to_disk() 468 | 469 | if retry_count >= max_retries: 470 | logging.error("Maximum retry attempts reached. Exiting program.") 471 | sys.exit(1) -------------------------------------------------------------------------------- /ws.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import hashlib, json, datetime, subprocess, ssl, socket 3 | import pandas as pd 4 | from websocket import create_connection, WebSocketTimeoutException 5 | from config import * 6 | 7 | class ConnectionTimedOutException(Exception): 8 | def __init__(self, message): 9 | self.message = message 10 | 11 | def __str__(self): 12 | return self.message 13 | 14 | class AlgoLabSocket(): 15 | def __init__(self, api_key, hash, verbose=True, callback=None): 16 | """ 17 | :String api_key: API_KEY 18 | :String hash: LoginUser'dan dönen Hash kodu 19 | :String type: T: Tick Paketi (Fiyat), D: Depth Paketi (Derinlik), O: Emir Statüsü 20 | :Obj type: callback: Soketin veriyi göndereceği fonksiyon 21 | """ 22 | self.verbose = verbose 23 | self.callback = callback 24 | self.connected = False 25 | self.arbitraj = {} 26 | self.thread_running = False 27 | self.kurum = {} 28 | self.hisse = {} 29 | self.df = pd.DataFrame(columns=["Date", "Hisse", "Yon", "Fiyat", "Lot", "Deger", "Usd", "Alici", "Satici"]) 30 | self.usdtry = 0.0 31 | self.ws = None 32 | self.api_key = api_key 33 | self.hash = hash 34 | self.data = self.api_key + api_hostname + "/ws" 35 | self.checker = hashlib.sha256(self.data.encode('utf-8')).hexdigest() 36 | self.request_time = datetime.datetime.now() 37 | self.headers = { 38 | "APIKEY": self.api_key, 39 | "Authorization": self.hash, 40 | "Checker": self.checker 41 | } 42 | 43 | def load_ciphers(self): 44 | output = subprocess.run(["openssl", "ciphers"], capture_output=True).stdout 45 | output_str = output.decode("utf-8") 46 | ciphers = output_str.strip().split("\n") 47 | return ciphers[0] 48 | 49 | def close(self): 50 | self.connected = False 51 | self.ws = None 52 | 53 | def connect(self): 54 | if self.verbose: 55 | print("Socket bağlantisi kuruluyor...") 56 | context = ssl.create_default_context() 57 | context.set_ciphers("DEFAULT") 58 | try: 59 | sock = socket.create_connection((hostname, 443)) 60 | ssock = context.wrap_socket(sock, server_hostname=hostname) 61 | self.ws = create_connection(socket_url, socket=ssock, header=self.headers) 62 | self.connected = True 63 | except Exception as e: 64 | self.close() 65 | print(f"Socket Hatasi: {e}") 66 | return False 67 | if self.verbose and self.connected: 68 | print("Socket bağlantisi başarili.") 69 | return self.connected 70 | 71 | def recv(self): 72 | try: 73 | data = self.ws.recv() 74 | except WebSocketTimeoutException: 75 | data = "" 76 | except Exception as e: 77 | print("Recv Error:", e) 78 | data = None 79 | self.close() 80 | return data 81 | def send(self, d): 82 | """ 83 | :param d: Dict 84 | """ 85 | try: 86 | data = {"token": self.hash} 87 | for s in d: 88 | data[s] = d[s] 89 | resp = self.ws.send(json.dumps(data)) 90 | except Exception as e: 91 | print("Send Error:", e) 92 | resp = None 93 | self.close() 94 | return resp 95 | --------------------------------------------------------------------------------