You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
5.1 KiB

3 weeks ago
import aiohttp
from pprint import pprint
from decimal import Decimal as D
import dill as pickle
import time
import copy
import os
import json
import asyncio
from utils import *
from piecewise import *
NADEX_ROOT = "https://trade.nadex.com/iDeal" if not DEMO else "https://demo-trade.nadex.com/iDeal"
NADEX_UPD = "https://upd.nadex.com" if not DEMO else "https://demo-upd.nadex.com"
NADEX_AUTH = read_auth("nadex") if not DEMO else read_auth("nadex_demo")
NADEX_SESSION_FILE = ".nadex_session"
COMMON_HEADERS = {
"accept": "application/json; charset=UTF-8",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/json; charset=UTF-8",
"origin": "https://platform.nadex.com",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
"x-device-user-agent": "vendor=IG | applicationType=Nadex | platform=web | deviceType=phone | version=0.853.0+6a6399d3",
}
class NadexSession:
def __init__(self, s):
self.s = s
def __repr__(self):
return "nadex"
async def login(self):
self.s.headers.clear()
self.s.headers.update(COMMON_HEADERS)
self.s.cookie_jar.clear()
if os.path.exists(NADEX_SESSION_FILE):
with open(NADEX_SESSION_FILE, 'rb') as f:
self.token = pickle.load(f)
else:
print("doing new login")
async with self.s.post(
NADEX_ROOT + "/v2/security/authenticate",
json = NADEX_AUTH,
) as resp:
self.token = resp.headers["x-security-token"]
print(self.token)
print()
with open(NADEX_SESSION_FILE, 'wb') as f:
pickle.dump(self.token, f)
self.s.headers["x-security-token"] = self.token
async def get_marketinfo(self, mid, try_relog=True):
async with self.s.get(
NADEX_ROOT + "/markets/navigation/"+str(mid),
) as resp:
if resp.status==401 and try_relog:
if os.path.exists(NADEX_SESSION_FILE):
os.remove(NADEX_SESSION_FILE)
await self.login()
return await self.get_marketinfo(mid, False)
return await resp.json()
async def execute_order(self, mid, p, s, buy):
async with self.s.post(
f"{NADEX_ROOT}/orders/workingorders/dma",
json = {
"direction": "+" if buy else "-",
"epic": mid,
"lsServerName": NADEX_UPD+":443",
"orderLevel": str(D(p)/100),
"orderSize": str(s),
"orderType": "MarketLimit",
"pricePreference": None,
"timeInForce": "GoodTillCancelled",
"timeStamp": int(time.time()),
"tolerance": None,
},
) as resp:
pprint("nadex order")
pprint(resp)
pprint(await resp.json())
pprint("")
async def init_lightstreamer(self, marketids):
proc = await asyncio.create_subprocess_exec(
"node", "nadex_ws.js",
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
)
proc.stdin.write(json.dumps({
"username": NADEX_AUTH["username"].upper(),
"security_token": self.token,
"marketids": marketids,
"servername": NADEX_UPD,
}).encode())
await proc.stdin.drain()
proc.stdin.close()
await proc.stdin.wait_closed()
return proc
async def orderbook_stream(self, marketid):
breaks = {}
for market in (await self.get_marketinfo(marketid))["markets"]:
low = cents(market["instrumentName"].split(">")[1].split()[0])
low += 1
breaks[market["epic"]] = low
proc = await self.init_lightstreamer([*breaks.keys()])
book = {}
async for line in proc.stdout:
data = json.loads(line.strip().decode())
epic = data["id"]
br = breaks[epic]
asks = []
bids = []
for p, s in data["asks"]:
p = cents(p)
asks.append((conv_lim_pc(br, None).add_conditional(-100) + (-p - 100), s, p))
for p, s in data["bids"]:
p = cents(p)
bids.append(((-conv_lim_pc(br, None)).add_conditional(-100) + (p - 100), s, p))
book[epic] = Digital(
low = br,
high = None,
bids = bids,
asks = asks,
exchange = self,
market_id = epic,
)
yield [*book.values()]
async def main():
async with aiohttp.ClientSession() as rs:
s = NadexSession(rs)
await s.login()
await s.execute_order("NB.D.U500.OPT-1-16-04Nov22.IP", 600, 1, True)
# async for book in s.orderbook_stream(160809):
# pprint(book)
# pass
if __name__=="__main__":
asyncio.run(main())