hyperquant 1.52__tar.gz → 1.54__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hyperquant-1.52 → hyperquant-1.54}/PKG-INFO +1 -1
- {hyperquant-1.52 → hyperquant-1.54}/pyproject.toml +1 -1
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/polymarket.py +129 -72
- {hyperquant-1.52 → hyperquant-1.54}/uv.lock +1 -1
- {hyperquant-1.52 → hyperquant-1.54}/.gitignore +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/README.md +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/requirements-dev.lock +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/requirements.lock +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/__init__.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/bitget.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/bitmart.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/coinw.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/deepcoin.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lbank.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/polymarket/ctfAbi.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/polymarket/safeAbi.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lib/util.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/lighter.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/apexpro.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/bitget.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/bitmart.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/coinw.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/deepcoin.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/lighter.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/models/polymarket.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/broker/ws.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/core.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/db.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/draw.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/logkit.py +0 -0
- {hyperquant-1.52 → hyperquant-1.54}/src/hyperquant/notikit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperquant
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.54
|
|
4
4
|
Summary: A minimal yet hyper-efficient backtesting framework for quantitative trading
|
|
5
5
|
Project-URL: Homepage, https://github.com/yourusername/hyperquant
|
|
6
6
|
Project-URL: Issues, https://github.com/yourusername/hyperquant/issues
|
|
@@ -108,7 +108,10 @@ CONDITIONAL_TOKENS_SPLIT_ABI = [
|
|
|
108
108
|
},
|
|
109
109
|
]
|
|
110
110
|
DEFAULT_POLYGON_RPCS = (
|
|
111
|
-
|
|
111
|
+
"https://1rpc.io/matic",
|
|
112
|
+
"https://polygon-bor-rpc.publicnode.com",
|
|
113
|
+
"https://polygon.drpc.org",
|
|
114
|
+
# Keep historical endpoints as fallback for users with API access.
|
|
112
115
|
"https://polygon-rpc.com",
|
|
113
116
|
"https://rpc.ankr.com/polygon",
|
|
114
117
|
)
|
|
@@ -1846,14 +1849,22 @@ class Polymarket:
|
|
|
1846
1849
|
if dry_run:
|
|
1847
1850
|
results.append({**item, "tx": None, "dry_run": True})
|
|
1848
1851
|
continue
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1852
|
+
try:
|
|
1853
|
+
tx_hash = await asyncio.to_thread(
|
|
1854
|
+
self._claim_via_safe_sync,
|
|
1855
|
+
candidates,
|
|
1856
|
+
item["condition_id"],
|
|
1857
|
+
item["index_sets"],
|
|
1858
|
+
gas,
|
|
1859
|
+
verbose,
|
|
1860
|
+
)
|
|
1861
|
+
except Exception as exc:
|
|
1862
|
+
raise RuntimeError(
|
|
1863
|
+
"claim_positions failed for "
|
|
1864
|
+
f"condition_id={item.get('condition_id')} "
|
|
1865
|
+
f"index_sets={item.get('index_sets')} "
|
|
1866
|
+
f"size={item.get('size')}: {exc}"
|
|
1867
|
+
) from exc
|
|
1857
1868
|
result_row = {**item, "tx": tx_hash, "dry_run": False}
|
|
1858
1869
|
if include_receipt:
|
|
1859
1870
|
try:
|
|
@@ -1976,22 +1987,7 @@ class Polymarket:
|
|
|
1976
1987
|
last_error: Exception | None = None
|
|
1977
1988
|
w3 = None
|
|
1978
1989
|
rpc_used = None
|
|
1979
|
-
|
|
1980
|
-
try:
|
|
1981
|
-
w3 = Web3(Web3.HTTPProvider(url, request_kwargs={"timeout": 30}))
|
|
1982
|
-
with suppress(Exception):
|
|
1983
|
-
from web3.middleware import geth_poa_middleware, ExtraDataToPOAMiddleware
|
|
1984
|
-
try:
|
|
1985
|
-
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
|
|
1986
|
-
except Exception:
|
|
1987
|
-
w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
|
|
1988
|
-
rpc_used = url
|
|
1989
|
-
break
|
|
1990
|
-
except Exception as exc:
|
|
1991
|
-
last_error = exc
|
|
1992
|
-
continue
|
|
1993
|
-
if w3 is None:
|
|
1994
|
-
raise RuntimeError(f"All RPC endpoints failed: {candidates}") from last_error
|
|
1990
|
+
safe_nonce = None
|
|
1995
1991
|
|
|
1996
1992
|
pk_env = os.getenv("PK")
|
|
1997
1993
|
if pk_env:
|
|
@@ -2004,23 +2000,11 @@ class Polymarket:
|
|
|
2004
2000
|
raise RuntimeError("Safe/proxy wallet address未知, 请在 apis['polymarket'][2] 或构造函数 funder 设置")
|
|
2005
2001
|
|
|
2006
2002
|
ctf_addr = self._contracts(self.chain_id, False)["conditional_tokens"]
|
|
2007
|
-
ctf = w3.eth.contract(address=w3.to_checksum_address(ctf_addr), abi=CONDITIONAL_TOKENS_ABI)
|
|
2008
|
-
safe = w3.eth.contract(address=w3.to_checksum_address(safe_addr), abi=SAFE_ABI)
|
|
2009
2003
|
|
|
2010
2004
|
cond_bytes = bytes.fromhex(condition_id.replace("0x", ""))
|
|
2011
2005
|
if len(cond_bytes) != 32:
|
|
2012
2006
|
raise ValueError("condition_id must be 32-byte hex string")
|
|
2013
2007
|
|
|
2014
|
-
redeem_calldata = ctf.encode_abi(
|
|
2015
|
-
"redeemPositions",
|
|
2016
|
-
args=[
|
|
2017
|
-
w3.to_checksum_address(USDC_CONTRACT),
|
|
2018
|
-
bytes(32),
|
|
2019
|
-
cond_bytes,
|
|
2020
|
-
index_sets,
|
|
2021
|
-
],
|
|
2022
|
-
)
|
|
2023
|
-
|
|
2024
2008
|
safe_tx_gas = 0
|
|
2025
2009
|
base_gas = 0
|
|
2026
2010
|
gas_price = 0
|
|
@@ -2029,13 +2013,55 @@ class Polymarket:
|
|
|
2029
2013
|
value = 0
|
|
2030
2014
|
operation = 0 # CALL
|
|
2031
2015
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2016
|
+
ctf = None
|
|
2017
|
+
safe = None
|
|
2018
|
+
redeem_calldata = None
|
|
2019
|
+
for url in candidates:
|
|
2020
|
+
try:
|
|
2021
|
+
w3_candidate = Web3(Web3.HTTPProvider(url, request_kwargs={"timeout": 30}))
|
|
2022
|
+
with suppress(Exception):
|
|
2023
|
+
from web3.middleware import geth_poa_middleware, ExtraDataToPOAMiddleware
|
|
2024
|
+
try:
|
|
2025
|
+
w3_candidate.middleware_onion.inject(geth_poa_middleware, layer=0)
|
|
2026
|
+
except Exception:
|
|
2027
|
+
w3_candidate.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
|
|
2028
|
+
|
|
2029
|
+
ctf_candidate = w3_candidate.eth.contract(
|
|
2030
|
+
address=w3_candidate.to_checksum_address(ctf_addr),
|
|
2031
|
+
abi=CONDITIONAL_TOKENS_ABI,
|
|
2032
|
+
)
|
|
2033
|
+
safe_candidate = w3_candidate.eth.contract(
|
|
2034
|
+
address=w3_candidate.to_checksum_address(safe_addr),
|
|
2035
|
+
abi=SAFE_ABI,
|
|
2036
|
+
)
|
|
2037
|
+
redeem_calldata_candidate = ctf_candidate.encode_abi(
|
|
2038
|
+
"redeemPositions",
|
|
2039
|
+
args=[
|
|
2040
|
+
w3_candidate.to_checksum_address(USDC_CONTRACT),
|
|
2041
|
+
bytes(32),
|
|
2042
|
+
cond_bytes,
|
|
2043
|
+
index_sets,
|
|
2044
|
+
],
|
|
2045
|
+
)
|
|
2046
|
+
nonce_candidate = safe_candidate.functions.nonce().call()
|
|
2047
|
+
|
|
2048
|
+
w3 = w3_candidate
|
|
2049
|
+
rpc_used = url
|
|
2050
|
+
ctf = ctf_candidate
|
|
2051
|
+
safe = safe_candidate
|
|
2052
|
+
redeem_calldata = redeem_calldata_candidate
|
|
2053
|
+
safe_nonce = nonce_candidate
|
|
2054
|
+
break
|
|
2055
|
+
except Exception as exc:
|
|
2056
|
+
last_error = exc
|
|
2057
|
+
if verbose:
|
|
2058
|
+
print(f"[claim] rpc nonce probe failed: {url} -> {exc}")
|
|
2059
|
+
continue
|
|
2060
|
+
|
|
2061
|
+
if w3 is None or safe is None or ctf is None or redeem_calldata is None or safe_nonce is None:
|
|
2062
|
+
raise RuntimeError(
|
|
2063
|
+
f"无法获取 Safe nonce (tried rpc={candidates}); last_error={last_error}"
|
|
2064
|
+
) from last_error
|
|
2039
2065
|
|
|
2040
2066
|
try:
|
|
2041
2067
|
safe_tx_hash = safe.functions.getTransactionHash(
|
|
@@ -2065,43 +2091,71 @@ class Polymarket:
|
|
|
2065
2091
|
try:
|
|
2066
2092
|
acct = _A.from_key(private_key)
|
|
2067
2093
|
sender = acct.address
|
|
2068
|
-
# 使用 pending 避免重复使用已在 mempool 的 nonce 触发 replacement underpriced
|
|
2069
|
-
nonce = w3.eth.get_transaction_count(sender)
|
|
2070
|
-
gas_price_chain = w3.eth.gas_price
|
|
2071
2094
|
except Exception as exc:
|
|
2072
|
-
raise RuntimeError("获取 sender
|
|
2073
|
-
|
|
2074
|
-
tx = safe.functions.execTransaction(
|
|
2075
|
-
w3.to_checksum_address(ctf_addr),
|
|
2076
|
-
value,
|
|
2077
|
-
redeem_calldata,
|
|
2078
|
-
operation,
|
|
2079
|
-
safe_tx_gas,
|
|
2080
|
-
base_gas,
|
|
2081
|
-
gas_price,
|
|
2082
|
-
w3.to_checksum_address(gas_token),
|
|
2083
|
-
w3.to_checksum_address(refund_receiver),
|
|
2084
|
-
sig_bytes,
|
|
2085
|
-
).build_transaction(
|
|
2086
|
-
{
|
|
2087
|
-
"from": sender,
|
|
2088
|
-
"nonce": nonce,
|
|
2089
|
-
"gas": gas,
|
|
2090
|
-
"gasPrice": gas_price_chain,
|
|
2091
|
-
}
|
|
2092
|
-
)
|
|
2095
|
+
raise RuntimeError("获取 sender 地址失败") from exc
|
|
2093
2096
|
|
|
2094
|
-
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
|
|
2095
2097
|
send_errors: list[str] = []
|
|
2096
2098
|
for attempt in range(3):
|
|
2097
2099
|
try:
|
|
2100
|
+
nonce = w3.eth.get_transaction_count(sender, "pending")
|
|
2101
|
+
gas_price_chain = int(w3.eth.gas_price)
|
|
2102
|
+
if attempt > 0:
|
|
2103
|
+
# retry 时小幅提价,减少卡在同价位的概率
|
|
2104
|
+
gas_price_chain = int(gas_price_chain * (1.0 + 0.10 * attempt))
|
|
2105
|
+
|
|
2106
|
+
exec_tx = safe.functions.execTransaction(
|
|
2107
|
+
w3.to_checksum_address(ctf_addr),
|
|
2108
|
+
value,
|
|
2109
|
+
redeem_calldata,
|
|
2110
|
+
operation,
|
|
2111
|
+
safe_tx_gas,
|
|
2112
|
+
base_gas,
|
|
2113
|
+
gas_price,
|
|
2114
|
+
w3.to_checksum_address(gas_token),
|
|
2115
|
+
w3.to_checksum_address(refund_receiver),
|
|
2116
|
+
sig_bytes,
|
|
2117
|
+
)
|
|
2118
|
+
try:
|
|
2119
|
+
simulated = exec_tx.call({"from": sender})
|
|
2120
|
+
except Exception as sim_exc:
|
|
2121
|
+
simulated = None
|
|
2122
|
+
if verbose:
|
|
2123
|
+
print(f"[claim] preflight call error (continue): {sim_exc}")
|
|
2124
|
+
if simulated is False:
|
|
2125
|
+
err = (
|
|
2126
|
+
f"Safe preflight failed (execTransaction call returned false): "
|
|
2127
|
+
f"safe_nonce={safe_nonce} sender_nonce={nonce}"
|
|
2128
|
+
)
|
|
2129
|
+
send_errors.append(err)
|
|
2130
|
+
if verbose:
|
|
2131
|
+
print(f"Safe redeem attempt {attempt+1} failed: {err}")
|
|
2132
|
+
break
|
|
2133
|
+
|
|
2134
|
+
tx = exec_tx.build_transaction(
|
|
2135
|
+
{
|
|
2136
|
+
"from": sender,
|
|
2137
|
+
"nonce": nonce,
|
|
2138
|
+
"gas": gas,
|
|
2139
|
+
"gasPrice": gas_price_chain,
|
|
2140
|
+
}
|
|
2141
|
+
)
|
|
2142
|
+
|
|
2143
|
+
signed_tx = w3.eth.account.sign_transaction(tx, private_key)
|
|
2098
2144
|
raw_tx = getattr(signed_tx, "rawTransaction", None) or getattr(signed_tx, "raw_transaction", None)
|
|
2099
2145
|
if raw_tx is None: # pragma: no cover
|
|
2100
2146
|
raise AttributeError("Signed transaction missing rawTransaction/raw_transaction")
|
|
2101
2147
|
tx_hash = w3.eth.send_raw_transaction(raw_tx)
|
|
2102
2148
|
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, poll_latency=2, timeout=180)
|
|
2103
2149
|
if receipt.get("status") != 1:
|
|
2104
|
-
|
|
2150
|
+
err = (
|
|
2151
|
+
f"Safe redeemPositions reverted on-chain: tx={tx_hash.hex()} "
|
|
2152
|
+
f"safe_nonce={safe_nonce} sender_nonce={nonce}"
|
|
2153
|
+
)
|
|
2154
|
+
send_errors.append(err)
|
|
2155
|
+
if verbose:
|
|
2156
|
+
print(f"Safe redeem attempt {attempt+1} failed: {err}")
|
|
2157
|
+
# 已经上链并回执失败,继续重试通常只会制造 nonce 噪音
|
|
2158
|
+
break
|
|
2105
2159
|
if verbose:
|
|
2106
2160
|
print(
|
|
2107
2161
|
{
|
|
@@ -2162,10 +2216,13 @@ class Polymarket:
|
|
|
2162
2216
|
hourly_match = await _try_slug(hourly_slug)
|
|
2163
2217
|
if hourly_match:
|
|
2164
2218
|
return hourly_match
|
|
2165
|
-
|
|
2166
|
-
if '
|
|
2219
|
+
|
|
2220
|
+
if '-15m-' in base_slug or base_slug.endswith('-15m'):
|
|
2221
|
+
interval = 15 * 60
|
|
2222
|
+
elif '-5m-' in base_slug or base_slug.endswith('-5m'):
|
|
2167
2223
|
interval = 5 * 60
|
|
2168
2224
|
|
|
2225
|
+
|
|
2169
2226
|
now_ts = int(datetime.now(UTC).timestamp())
|
|
2170
2227
|
base_ts = (now_ts // interval) * interval
|
|
2171
2228
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|