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
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())
|
||
|
|
|
||
|
|
|