Repo is ready

This commit is contained in:
warproxxx
2025-03-31 12:16:51 -04:00
commit 8e500d9437
35 changed files with 6044 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# Minimum position size to trigger position merging
# Positions smaller than this will be ignored to save on gas costs
MIN_MERGE_SIZE = 20
View File
File diff suppressed because one or more lines are too long
+144
View File
@@ -0,0 +1,144 @@
import json
from sortedcontainers import SortedDict
import poly_data.global_state as global_state
import poly_data.CONSTANTS as CONSTANTS
from trading import perform_trade
import time
import asyncio
from poly_data.data_utils import set_position, set_order, update_positions
def process_book_data(asset, json_data):
global_state.all_data[asset] = {
'bids': SortedDict(),
'asks': SortedDict()
}
global_state.all_data[asset]['bids'].update({float(entry['price']): float(entry['size']) for entry in json_data['bids']})
global_state.all_data[asset]['asks'].update({float(entry['price']): float(entry['size']) for entry in json_data['asks']})
def process_price_change(asset, side, price_level, new_size):
if side == 'bids':
book = global_state.all_data[asset]['bids']
else:
book = global_state.all_data[asset]['asks']
if new_size == 0:
if price_level in book:
del book[price_level]
else:
book[price_level] = new_size
def process_data(json_data, trade=True):
event_type = json_data['event_type']
asset = json_data['market']
if event_type == 'book':
process_book_data(asset, json_data)
if trade:
asyncio.create_task(perform_trade(asset))
elif event_type == 'price_change':
side = 'bids' if json_data['side'] == 'BUY' else 'asks'
price_level = float(json_data['price'])
new_size = float(json_data['size'])
process_price_change(asset, side, price_level, new_size)
if trade:
asyncio.create_task(perform_trade(asset))
# pretty_print(f'Received book update for {asset}:', global_state.all_data[asset])
def add_to_performing(col, id):
if col not in global_state.performing:
global_state.performing[col] = set()
if col not in global_state.performing_timestamps:
global_state.performing_timestamps[col] = {}
# Add the trade ID and track its timestamp
global_state.performing[col].add(id)
global_state.performing_timestamps[col][id] = time.time()
def remove_from_performing(col, id):
if col in global_state.performing:
global_state.performing[col].discard(id)
if col in global_state.performing_timestamps:
global_state.performing_timestamps[col].pop(id, None)
def process_user_data(row):
market = row['market']
side = row['side'].lower()
token = row['asset_id']
if token in global_state.REVERSE_TOKENS:
col = token + "_" + side
if row['event_type'] == 'trade':
size = 0
price = 0
maker_outcome = ""
taker_outcome = row['outcome']
is_user_maker = False
for maker_order in row['maker_orders']:
if maker_order['maker_address'].lower() == global_state.client.browser_wallet.lower():
print("User is maker")
size = float(maker_order['matched_amount'])
price = float(maker_order['price'])
is_user_maker = True
maker_outcome = maker_order['outcome'] #this is curious
if maker_outcome == taker_outcome:
side = 'buy' if side == 'sell' else 'sell' #need to reverse as we reverse token too
else:
token = global_state.REVERSE_TOKENS[token]
if not is_user_maker:
size = float(row['size'])
price = float(row['price'])
print("User is taker")
print("TRADE EVENT FOR: ", row['market'], "ID: ", row['id'], "STATUS: ", row['status'], " SIDE: ", row['side'], " MAKER OUTCOME: ", maker_outcome, " TAKER OUTCOME: ", taker_outcome, " PROCESSED SIDE: ", side, " SIZE: ", size)
if row['status'] == 'CONFIRMED' or row['status'] == 'FAILED' :
if row['status'] == 'FAILED':
print(f"Trade failed for {token}, decreasing")
asyncio.create_task(asyncio.sleep(2))
update_positions()
else:
remove_from_performing(col, row['id'])
print("Confirmed. Performing is ", len(global_state.performing[col]))
print("Last trade update is ", global_state.last_trade_update)
print("Performing is ", global_state.performing)
print("Performing timestamps is ", global_state.performing_timestamps)
asyncio.create_task(perform_trade(market))
elif row['status'] == 'MATCHED':
add_to_performing(col, row['id'])
print("Matched. Performing is ", len(global_state.performing[col]))
set_position(token, side, size, price)
print("Position after matching is ", global_state.positions[str(token)])
print("Last trade update is ", global_state.last_trade_update)
print("Performing is ", global_state.performing)
print("Performing timestamps is ", global_state.performing_timestamps)
asyncio.create_task(perform_trade(market))
elif row['status'] == 'MINED':
remove_from_performing(col, row['id'])
elif row['event_type'] == 'order':
print("ORDER EVENT FOR: ", row['market'], " STATUS: ", row['status'], " TYPE: ", row['type'], " SIDE: ", side, " ORIGINAL SIZE: ", row['original_size'], " SIZE MATCHED: ", row['size_matched'])
set_order(token, side, float(row['original_size']) - float(row['size_matched']), row['price'])
asyncio.create_task(perform_trade(market))
else:
print(f"User date received for {market} but its not in")
+169
View File
@@ -0,0 +1,169 @@
import poly_data.global_state as global_state
from poly_data.utils import get_sheet_df
import time
import poly_data.global_state as global_state
#sth here seems to be removing the position
def update_positions(avgOnly=False):
pos_df = global_state.client.get_all_positions()
for idx, row in pos_df.iterrows():
asset = str(row['asset'])
if asset in global_state.positions:
position = global_state.positions[asset].copy()
else:
position = {'size': 0, 'avgPrice': 0}
position['avgPrice'] = row['avgPrice']
if not avgOnly:
position['size'] = row['size']
else:
for col in [f"{asset}_sell", f"{asset}_buy"]:
#need to review this
if col not in global_state.performing or not isinstance(global_state.performing[col], set) or len(global_state.performing[col]) == 0:
try:
old_size = position['size']
except:
old_size = 0
if asset in global_state.last_trade_update:
if time.time() - global_state.last_trade_update[asset] < 5:
print(f"Skipping update for {asset} because last trade update was less than 5 seconds ago")
continue
if old_size != row['size']:
print(f"No trades are pending. Updating position from {old_size} to {row['size']} and avgPrice to {row['avgPrice']} using API")
position['size'] = row['size']
else:
print(f"ALERT: Skipping update for {asset} because there are trades pending for {col} looking like {global_state.performing[col]}")
global_state.positions[asset] = position
def get_position(token):
token = str(token)
if token in global_state.positions:
return global_state.positions[token]
else:
return {'size': 0, 'avgPrice': 0}
def set_position(token, side, size, price, source='websocket'):
token = str(token)
size = float(size)
price = float(price)
global_state.last_trade_update[token] = time.time()
if side.lower() == 'sell':
size *= -1
if token in global_state.positions:
prev_price = global_state.positions[token]['avgPrice']
prev_size = global_state.positions[token]['size']
if size > 0:
if prev_size == 0:
# Starting a new position
avgPrice_new = price
else:
# Buying more; update average price
avgPrice_new = (prev_price * prev_size + price * size) / (prev_size + size)
elif size < 0:
# Selling; average price remains the same
avgPrice_new = prev_price
else:
# No change in position
avgPrice_new = prev_price
global_state.positions[token]['size'] += size
global_state.positions[token]['avgPrice'] = avgPrice_new
else:
global_state.positions[token] = {'size': size, 'avgPrice': price}
print(f"Updated position from {source}, set to ", global_state.positions[token])
def update_orders():
all_orders = global_state.client.get_all_orders()
orders = {}
if len(all_orders) > 0:
for token in all_orders['asset_id'].unique():
if token not in orders:
orders[str(token)] = {'buy': {'price': 0, 'size': 0}, 'sell': {'price': 0, 'size': 0}}
curr_orders = all_orders[all_orders['asset_id'] == str(token)]
if len(curr_orders) > 0:
sel_orders = {}
sel_orders['buy'] = curr_orders[curr_orders['side'] == 'BUY']
sel_orders['sell'] = curr_orders[curr_orders['side'] == 'SELL']
for type in ['buy', 'sell']:
curr = sel_orders[type]
if len(curr) > 1:
print("Multiple orders found, cancelling")
global_state.client.cancel_all_asset(token)
orders[str(token)] = {'buy': {'price': 0, 'size': 0}, 'sell': {'price': 0, 'size': 0}}
elif len(curr) == 1:
orders[str(token)][type]['price'] = float(curr.iloc[0]['price'])
orders[str(token)][type]['size'] = float(curr.iloc[0]['original_size'] - curr.iloc[0]['size_matched'])
global_state.orders = orders
def get_order(token):
token = str(token)
if token in global_state.orders:
if 'buy' not in global_state.orders[token]:
global_state.orders[token]['buy'] = {'price': 0, 'size': 0}
if 'sell' not in global_state.orders[token]:
global_state.orders[token]['sell'] = {'price': 0, 'size': 0}
return global_state.orders[token]
else:
return {'buy': {'price': 0, 'size': 0}, 'sell': {'price': 0, 'size': 0}}
def set_order(token, side, size, price):
curr = {}
curr = {side: {'price': 0, 'size': 0}}
curr[side]['size'] = float(size)
curr[side]['price'] = float(price)
global_state.orders[str(token)] = curr
print("Updated order, set to ", curr)
def update_markets():
received_df, received_params = get_sheet_df()
if len(received_df) > 0:
global_state.df, global_state.params = received_df.copy(), received_params
for idx, row in global_state.df.iterrows():
for col in ['token1', 'token2']:
row[col] = str(row[col])
if row['token1'] not in global_state.all_tokens:
global_state.all_tokens.append(row['token1'])
if row['token1'] not in global_state.REVERSE_TOKENS:
global_state.REVERSE_TOKENS[row['token1']] = row['token2']
if row['token2'] not in global_state.REVERSE_TOKENS:
global_state.REVERSE_TOKENS[row['token2']] = row['token1']
for col2 in [f"{row['token1']}_buy", f"{row['token1']}_sell", f"{row['token2']}_buy", f"{row['token2']}_sell"]:
if col2 not in global_state.performing:
global_state.performing[col2] = set()
+49
View File
@@ -0,0 +1,49 @@
import threading
import pandas as pd
# ============ Market Data ============
# List of all tokens being tracked
all_tokens = []
# Mapping between tokens in the same market (YES->NO, NO->YES)
REVERSE_TOKENS = {}
# Order book data for all markets
all_data = {}
# Market configuration data from Google Sheets
df = None
# ============ Client & Parameters ============
# Polymarket client instance
client = None
# Trading parameters from Google Sheets
params = {}
# Lock for thread-safe trading operations
lock = threading.Lock()
# ============ Trading State ============
# Tracks trades that have been matched but not yet mined
# Format: {"token_side": {trade_id1, trade_id2, ...}}
performing = {}
# Timestamps for when trades were added to performing
# Used to clear stale trades
performing_timestamps = {}
# Timestamps for when positions were last updated
last_trade_update = {}
# Current open orders for each token
# Format: {token_id: {'buy': {price, size}, 'sell': {price, size}}}
orders = {}
# Current positions for each token
# Format: {token_id: {'size': float, 'avgPrice': float}}
positions = {}
+320
View File
@@ -0,0 +1,320 @@
from dotenv import load_dotenv # Environment variable management
import os # Operating system interface
# Polymarket API client libraries
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, BalanceAllowanceParams, AssetType, PartialCreateOrderOptions
from py_clob_client.constants import POLYGON
# Web3 libraries for blockchain interaction
from web3 import Web3
from web3.middleware import geth_poa_middleware
from eth_account import Account
import requests # HTTP requests
import pandas as pd # Data analysis
import json # JSON processing
import subprocess # For calling external processes
from py_clob_client.clob_types import OpenOrderParams
# Smart contract ABIs
from poly_data.abis import NegRiskAdapterABI, ConditionalTokenABI, erc20_abi
# Load environment variables
load_dotenv()
class PolymarketClient:
"""
Client for interacting with Polymarket's API and smart contracts.
This class provides methods for:
- Creating and managing orders
- Querying order book data
- Checking balances and positions
- Merging positions
The client connects to both the Polymarket API and the Polygon blockchain.
"""
def __init__(self, pk='default') -> None:
"""
Initialize the Polymarket client with API and blockchain connections.
Args:
pk (str, optional): Private key identifier, defaults to 'default'
"""
host="https://clob.polymarket.com"
# Get credentials from environment variables
key=os.getenv("PK")
browser_address = os.getenv("BROWSER_ADDRESS")
# Don't print sensitive wallet information
print("Initializing Polymarket client...")
chain_id=POLYGON
self.browser_wallet=Web3.toChecksumAddress(browser_address)
# Initialize the Polymarket API client
self.client = ClobClient(
host=host,
key=key,
chain_id=chain_id,
funder=self.browser_wallet,
signature_type=2
)
# Set up API credentials
self.creds = self.client.create_or_derive_api_creds()
self.client.set_api_creds(creds=self.creds)
# Initialize Web3 connection to Polygon
web3 = Web3(Web3.HTTPProvider("https://polygon-rpc.com"))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)
# Set up USDC contract for balance checks
self.usdc_contract = web3.eth.contract(
address="0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
abi=erc20_abi
)
# Store key contract addresses
self.addresses = {
'neg_risk_adapter': '0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296',
'collateral': '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174',
'conditional_tokens': '0x4D97DCd97eC945f40cF65F87097ACe5EA0476045'
}
# Initialize contract interfaces
self.neg_risk_adapter = web3.eth.contract(
address=self.addresses['neg_risk_adapter'],
abi=NegRiskAdapterABI
)
self.conditional_tokens = web3.eth.contract(
address=self.addresses['conditional_tokens'],
abi=ConditionalTokenABI
)
self.web3 = web3
def create_order(self, marketId, action, price, size, neg_risk=False):
"""
Create and submit a new order to the Polymarket order book.
Args:
marketId (str): ID of the market token to trade
action (str): "BUY" or "SELL"
price (float): Order price (0-1 range for prediction markets)
size (float): Order size in USDC
neg_risk (bool, optional): Whether this is a negative risk market. Defaults to False.
Returns:
dict: Response from the API containing order details, or empty dict on error
"""
# Create order parameters
order_args = OrderArgs(
token_id=str(marketId),
price=price,
size=size,
side=action
)
signed_order = None
# Handle regular vs negative risk markets differently
if neg_risk == False:
signed_order = self.client.create_order(order_args)
else:
signed_order = self.client.create_order(order_args, options=PartialCreateOrderOptions(neg_risk=True))
try:
# Submit the signed order to the API
resp = self.client.post_order(signed_order)
return resp
except Exception as ex:
print(ex)
return {}
def get_order_book(self, market):
"""
Get the current order book for a specific market.
Args:
market (str): Market ID to query
Returns:
tuple: (bids_df, asks_df) - DataFrames containing bid and ask orders
"""
orderBook = self.client.get_order_book(market)
return pd.DataFrame(orderBook.bids).astype(float), pd.DataFrame(orderBook.asks).astype(float)
def get_usdc_balance(self):
"""
Get the USDC balance of the connected wallet.
Returns:
float: USDC balance in decimal format
"""
return self.usdc_contract.functions.balanceOf(self.browser_wallet).call() / 10**6
def get_pos_balance(self):
"""
Get the total value of all positions for the connected wallet.
Returns:
float: Total position value in USDC
"""
res = requests.get(f'https://data-api.polymarket.com/value?user={self.browser_wallet}')
return float(res.json()['value'])
def get_total_balance(self):
"""
Get the combined value of USDC balance and all positions.
Returns:
float: Total account value in USDC
"""
return self.get_usdc_balance() + self.get_pos_balance()
def get_all_positions(self):
"""
Get all positions for the connected wallet across all markets.
Returns:
DataFrame: All positions with details like market, size, avgPrice
"""
res = requests.get(f'https://data-api.polymarket.com/positions?user={self.browser_wallet}')
return pd.DataFrame(res.json())
def get_raw_position(self, tokenId):
"""
Get the raw token balance for a specific market outcome token.
Args:
tokenId (int): Token ID to query
Returns:
int: Raw token amount (before decimal conversion)
"""
return int(self.conditional_tokens.functions.balanceOf(self.browser_wallet, int(tokenId)).call())
def get_position(self, tokenId):
"""
Get both raw and formatted position size for a token.
Args:
tokenId (int): Token ID to query
Returns:
tuple: (raw_position, shares) - Raw token amount and decimal shares
Shares less than 1 are treated as 0 to avoid dust amounts
"""
raw_position = self.get_raw_position(tokenId)
shares = float(raw_position / 1e6)
# Ignore very small positions (dust)
if shares < 1:
shares = 0
return raw_position, shares
def get_all_orders(self):
"""
Get all open orders for the connected wallet.
Returns:
DataFrame: All open orders with their details
"""
orders_df = pd.DataFrame(self.client.get_orders())
# Convert numeric columns to float
for col in ['original_size', 'size_matched', 'price']:
if col in orders_df.columns:
orders_df[col] = orders_df[col].astype(float)
return orders_df
def get_market_orders(self, market):
"""
Get all open orders for a specific market.
Args:
market (str): Market ID to query
Returns:
DataFrame: Open orders for the specified market
"""
orders_df = pd.DataFrame(self.client.get_orders(OpenOrderParams(
market=market,
)))
# Convert numeric columns to float
for col in ['original_size', 'size_matched', 'price']:
if col in orders_df.columns:
orders_df[col] = orders_df[col].astype(float)
return orders_df
def cancel_all_asset(self, asset_id):
"""
Cancel all orders for a specific asset token.
Args:
asset_id (str): Asset token ID
"""
self.client.cancel_market_orders(asset_id=str(asset_id))
def cancel_all_market(self, marketId):
"""
Cancel all orders in a specific market.
Args:
marketId (str): Market ID
"""
self.client.cancel_market_orders(market=marketId)
def merge_positions(self, amount_to_merge, condition_id, is_neg_risk_market):
"""
Merge positions in a market to recover collateral.
This function calls the external poly_merger Node.js script to execute
the merge operation on-chain. When you hold both YES and NO positions
in the same market, merging them recovers your USDC.
Args:
amount_to_merge (int): Raw token amount to merge (before decimal conversion)
condition_id (str): Market condition ID
is_neg_risk_market (bool): Whether this is a negative risk market
Returns:
str: Transaction hash or output from the merge script
Raises:
Exception: If the merge operation fails
"""
amount_to_merge_str = str(amount_to_merge)
# Prepare the command to run the JavaScript script
node_command = f'node poly_merger/merge.js {amount_to_merge_str} {condition_id} {"true" if is_neg_risk_market else "false"}'
print(node_command)
# Run the command and capture the output
result = subprocess.run(node_command, shell=True, capture_output=True, text=True)
# Check if there was an error
if result.returncode != 0:
print("Error:", result.stderr)
raise Exception(f"Error in merging positions: {result.stderr}")
print("Done merging")
# Return the transaction hash or output
return result.stdout
+148
View File
@@ -0,0 +1,148 @@
import math
from poly_data.data_utils import update_positions
import poly_data.global_state as global_state
# def get_avgPrice(position, assetId):
# curr_global = global_state.all_positions[global_state.all_positions['asset'] == str(assetId)]
# api_position_size = 0
# api_avgPrice = 0
# if len(curr_global) > 0:
# c_row = curr_global.iloc[0]
# api_avgPrice = round(c_row['avgPrice'], 2)
# api_position_size = c_row['size']
# if position > 0:
# if abs((api_position_size - position)/position * 100) > 5:
# print("Updating global positions")
# update_positions()
# try:
# c_row = curr_global.iloc[0]
# api_avgPrice = round(c_row['avgPrice'], 2)
# api_position_size = c_row['size']
# except:
# return 0
# return api_avgPrice
def get_best_bid_ask_deets(market, name, size, deviation_threshold=0.05):
best_bid, best_bid_size, second_best_bid, second_best_bid_size, top_bid = find_best_price_with_size(global_state.all_data[market]['bids'], size, reverse=True)
best_ask, best_ask_size, second_best_ask, second_best_ask_size, top_ask = find_best_price_with_size(global_state.all_data[market]['asks'], size, reverse=False)
mid_price = (best_bid + best_ask) / 2
bid_sum_within_n_percent = sum(size for price, size in global_state.all_data[market]['bids'].items() if best_bid <= price <= mid_price * (1 + deviation_threshold))
ask_sum_within_n_percent = sum(size for price, size in global_state.all_data[market]['asks'].items() if mid_price * (1 - deviation_threshold) <= price <= best_ask)
if name == 'token2':
best_bid, second_best_bid, top_bid, best_ask, second_best_ask, top_ask = 1 - best_ask, 1 - second_best_ask, 1 - top_ask, 1 - best_bid, 1 - second_best_bid, 1 - top_bid
best_bid_size, second_best_bid_size, best_ask_size, second_best_ask_size = best_ask_size, second_best_ask_size, best_bid_size, second_best_bid_size
bid_sum_within_n_percent, ask_sum_within_n_percent = ask_sum_within_n_percent, bid_sum_within_n_percent
#return as dictionary
return {
'best_bid': best_bid,
'best_bid_size': best_bid_size,
'second_best_bid': second_best_bid,
'second_best_bid_size': second_best_bid_size,
'top_bid': top_bid,
'best_ask': best_ask,
'best_ask_size': best_ask_size,
'second_best_ask': second_best_ask,
'second_best_ask_size': second_best_ask_size,
'top_ask': top_ask,
'bid_sum_within_n_percent': bid_sum_within_n_percent,
'ask_sum_within_n_percent': ask_sum_within_n_percent
}
def find_best_price_with_size(price_dict, min_size, reverse=False):
lst = list(price_dict.items())
if reverse:
lst.reverse()
best_price, best_size = None, None
second_best_price, second_best_size = None, None
top_price = None
set_best = False
for price, size in lst:
if top_price is None:
top_price = price
if set_best:
second_best_price, second_best_size = price, size
break
if size > min_size:
if best_price is None:
best_price, best_size = price, size
set_best = True
return best_price, best_size, second_best_price, second_best_size, top_price
def get_order_prices(best_bid, best_bid_size, top_bid, best_ask, best_ask_size, top_ask, avgPrice, row):
bid_price = best_bid + row['tick_size']
ask_price = best_ask - row['tick_size']
if best_bid_size < row['min_size'] * 1.5:
bid_price = best_bid
if best_ask_size < 250 * 1.5:
ask_price = best_ask
if bid_price >= top_ask:
bid_price = top_bid
if ask_price <= top_bid:
ask_price = top_ask
if bid_price == ask_price:
bid_price = top_bid
ask_price = top_ask
# if ask_price <= avgPrice:
# if avgPrice - ask_price <= (row['max_spread']*1.7/100):
# ask_price = avgPrice
#temp for sleep
if ask_price <= avgPrice and avgPrice > 0:
ask_price = avgPrice
return bid_price, ask_price
def round_down(number, decimals):
factor = 10 ** decimals
return math.floor(number * factor) / factor
def round_up(number, decimals):
factor = 10 ** decimals
return math.ceil(number * factor) / factor
def get_buy_sell_amount(position, bid_price, row):
buy_amount = 0
sell_amount = 0
sell_amount = position
buy_amount = row['trade_size'] - position
if buy_amount > 0.7 * row['min_size'] and buy_amount < row['min_size']:
buy_amount = row['min_size']
if bid_price < 0.1:
if row['multiplier'] != '':
print(f"Multiplying buy amount by {int(row['multiplier'])}")
buy_amount = buy_amount * int(row['multiplier'])
return buy_amount, sell_amount
+34
View File
@@ -0,0 +1,34 @@
import json
from poly_utils.google_utils import get_spreadsheet
import pandas as pd
def pretty_print(txt, dic):
print("\n", txt, json.dumps(dic, indent=4))
def get_sheet_df():
all = 'All Markets'
sel = 'Selected Markets'
spreadsheet = get_spreadsheet()
wk = spreadsheet.worksheet(sel)
df = pd.DataFrame(wk.get_all_records())
df = df[df['question'] != ""].reset_index(drop=True)
wk2 = spreadsheet.worksheet(all)
df2 = pd.DataFrame(wk2.get_all_records())
df2 = df2[df2['question'] != ""].reset_index(drop=True)
result = df.merge(df2, on='question', how='inner')
wk_p = spreadsheet.worksheet('Hyperparameters')
records = wk_p.get_all_records()
hyperparams, current_type = {}, None
for r in records:
current_type = r['type'] or current_type
hyperparams.setdefault(current_type, {})[r['param']] = r['value']
return result, hyperparams
+98
View File
@@ -0,0 +1,98 @@
import asyncio # Asynchronous I/O
import json # JSON handling
import websockets # WebSocket client
import traceback # Exception handling
from poly_data.data_processing import process_data, process_user_data
import poly_data.global_state as global_state
async def connect_market_websocket(chunk):
"""
Connect to Polymarket's market WebSocket API and process market updates.
This function:
1. Establishes a WebSocket connection to the Polymarket API
2. Subscribes to updates for a specified list of market tokens
3. Processes incoming order book and price updates
Args:
chunk (list): List of token IDs to subscribe to
Notes:
If the connection is lost, the function will exit and the main loop will
attempt to reconnect after a short delay.
"""
uri = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
async with websockets.connect(uri, ping_interval=5, ping_timeout=None) as websocket:
# Prepare and send subscription message
message = {"assets_ids": chunk}
await websocket.send(json.dumps(message))
print("\n")
print(f"Sent market subscription message: {message}")
try:
# Process incoming market data indefinitely
while True:
message = await websocket.recv()
json_data = json.loads(message)
# Process order book updates and trigger trading as needed
process_data(json_data)
except websockets.ConnectionClosed:
print("Connection closed in market websocket")
print(traceback.format_exc())
except Exception as e:
print(f"Exception in market websocket: {e}")
print(traceback.format_exc())
finally:
# Brief delay before attempting to reconnect
await asyncio.sleep(5)
async def connect_user_websocket():
"""
Connect to Polymarket's user WebSocket API and process order/trade updates.
This function:
1. Establishes a WebSocket connection to the Polymarket user API
2. Authenticates using API credentials
3. Processes incoming order and trade updates for the user
Notes:
If the connection is lost, the function will exit and the main loop will
attempt to reconnect after a short delay.
"""
uri = "wss://ws-subscriptions-clob.polymarket.com/ws/user"
async with websockets.connect(uri, ping_interval=5, ping_timeout=None) as websocket:
# Prepare authentication message with API credentials
message = {
"type": "user",
"auth": {
"apiKey": global_state.client.client.creds.api_key,
"secret": global_state.client.client.creds.api_secret,
"passphrase": global_state.client.client.creds.api_passphrase
}
}
# Send authentication message
await websocket.send(json.dumps(message))
print("\n")
print(f"Sent user subscription message")
try:
# Process incoming user data indefinitely
while True:
message = await websocket.recv()
json_data = json.loads(message)
# Process trade and order updates
process_user_data(json_data)
except websockets.ConnectionClosed:
print("Connection closed in user websocket")
print(traceback.format_exc())
except Exception as e:
print(f"Exception in user websocket: {e}")
print(traceback.format_exc())
finally:
# Brief delay before attempting to reconnect
await asyncio.sleep(5)