fix: auto-scale shares to meet $1 minimum notional for cheap-side orders
When cheap side price is very low (e.g. NO at 5c), MAKER_MM_TRADE_SIZE=5 produces $0.25 notional which fails Polymarket's $1 minimum for marketable BUY orders. Auto-scale both sides to ceil($1/price) to meet the minimum, keeping YES+NO pair counts equal for clean merge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
03d3f25d09
commit
fdb613e966
@@ -692,8 +692,19 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const yesCost = targetShares * yesBid;
|
// Auto-scale shares to meet Polymarket's $1 minimum notional per side.
|
||||||
const noCost = targetShares * noBid;
|
// When cheap side price is very low (e.g. 5c), 5 shares × $0.05 = $0.25 < $1 minimum.
|
||||||
|
// Both sides scale to the same count to keep YES+NO pairs balanced for merge.
|
||||||
|
const MIN_NOTIONAL = 1.0;
|
||||||
|
const yesMinShares = Math.ceil(MIN_NOTIONAL / yesBid);
|
||||||
|
const noMinShares = Math.ceil(MIN_NOTIONAL / noBid);
|
||||||
|
const actualShares = Math.max(targetShares, yesMinShares, noMinShares);
|
||||||
|
if (actualShares > targetShares) {
|
||||||
|
logger.info(`MakerMM${tag}: auto-scaled shares ${targetShares} → ${actualShares} to meet $${MIN_NOTIONAL} notional (YES $${yesBid} × ${yesMinShares}, NO $${noBid} × ${noMinShares})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const yesCost = actualShares * yesBid;
|
||||||
|
const noCost = actualShares * noBid;
|
||||||
const totalCost = yesCost + noCost;
|
const totalCost = yesCost + noCost;
|
||||||
|
|
||||||
if (!config.dryRun) {
|
if (!config.dryRun) {
|
||||||
@@ -718,11 +729,11 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Place orders ONCE (NO repricing) ──────────────────────
|
// ── Place orders ONCE (NO repricing) ──────────────────────
|
||||||
logger.trade(`MakerMM${tag}: placing BUY — YES $${yesBid} × ${targetShares} + NO $${noBid} × ${targetShares} = $${totalCost.toFixed(2)}`);
|
logger.trade(`MakerMM${tag}: placing BUY — YES $${yesBid} × ${actualShares} + NO $${noBid} × ${actualShares} = $${totalCost.toFixed(2)}`);
|
||||||
|
|
||||||
const [yesBuy, noBuy] = await Promise.all([
|
const [yesBuy, noBuy] = await Promise.all([
|
||||||
placeLimitBuy(yesTokenId, targetShares, yesBid, tickSize, negRisk),
|
placeLimitBuy(yesTokenId, actualShares, yesBid, tickSize, negRisk),
|
||||||
placeLimitBuy(noTokenId, targetShares, noBid, tickSize, negRisk),
|
placeLimitBuy(noTokenId, actualShares, noBid, tickSize, negRisk),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
logger.info(`MakerMM${tag}: order results — YES: ${yesBuy.success ? 'OK' : 'FAIL'} (id=${yesBuy.orderId?.slice(-8) || 'none'}), NO: ${noBuy.success ? 'OK' : 'FAIL'} (id=${noBuy.orderId?.slice(-8) || 'none'})`);
|
logger.info(`MakerMM${tag}: order results — YES: ${yesBuy.success ? 'OK' : 'FAIL'} (id=${yesBuy.orderId?.slice(-8) || 'none'}), NO: ${noBuy.success ? 'OK' : 'FAIL'} (id=${noBuy.orderId?.slice(-8) || 'none'})`);
|
||||||
@@ -753,7 +764,7 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
|
|
||||||
// Use net (new) balance to determine if actually filled — not total balance
|
// Use net (new) balance to determine if actually filled — not total balance
|
||||||
if (!finalYesBuy.success && (
|
if (!finalYesBuy.success && (
|
||||||
yesNet >= targetShares * 0.5 ||
|
yesNet >= actualShares * 0.5 ||
|
||||||
yesOrderStatus === 'filled' ||
|
yesOrderStatus === 'filled' ||
|
||||||
yesOrderStatus === 'partial'
|
yesOrderStatus === 'partial'
|
||||||
)) {
|
)) {
|
||||||
@@ -762,7 +773,7 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!finalNoBuy.success && (
|
if (!finalNoBuy.success && (
|
||||||
noNet >= targetShares * 0.5 ||
|
noNet >= actualShares * 0.5 ||
|
||||||
noOrderStatus === 'filled' ||
|
noOrderStatus === 'filled' ||
|
||||||
noOrderStatus === 'partial'
|
noOrderStatus === 'partial'
|
||||||
)) {
|
)) {
|
||||||
@@ -777,7 +788,7 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
logger.warn(`MakerMM${tag}: retrying YES order (attempt ${attempt}/${maxRetries})...`);
|
logger.warn(`MakerMM${tag}: retrying YES order (attempt ${attempt}/${maxRetries})...`);
|
||||||
await cancelOrder(yesBuy.orderId);
|
await cancelOrder(yesBuy.orderId);
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
finalYesBuy = await placeLimitBuy(yesTokenId, targetShares, yesBid, tickSize, negRisk);
|
finalYesBuy = await placeLimitBuy(yesTokenId, actualShares, yesBid, tickSize, negRisk);
|
||||||
if (finalYesBuy.success) {
|
if (finalYesBuy.success) {
|
||||||
logger.success(`MakerMM${tag}: YES order succeeded on retry ${attempt}`);
|
logger.success(`MakerMM${tag}: YES order succeeded on retry ${attempt}`);
|
||||||
}
|
}
|
||||||
@@ -786,7 +797,7 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
logger.warn(`MakerMM${tag}: retrying NO order (attempt ${attempt}/${maxRetries})...`);
|
logger.warn(`MakerMM${tag}: retrying NO order (attempt ${attempt}/${maxRetries})...`);
|
||||||
await cancelOrder(noBuy.orderId);
|
await cancelOrder(noBuy.orderId);
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
finalNoBuy = await placeLimitBuy(noTokenId, targetShares, noBid, tickSize, negRisk);
|
finalNoBuy = await placeLimitBuy(noTokenId, actualShares, noBid, tickSize, negRisk);
|
||||||
if (finalNoBuy.success) {
|
if (finalNoBuy.success) {
|
||||||
logger.success(`MakerMM${tag}: NO order succeeded on retry ${attempt}`);
|
logger.success(`MakerMM${tag}: NO order succeeded on retry ${attempt}`);
|
||||||
}
|
}
|
||||||
@@ -812,7 +823,7 @@ export async function executeMakerRebateStrategy(market) {
|
|||||||
tickSize,
|
tickSize,
|
||||||
negRisk,
|
negRisk,
|
||||||
status: 'monitoring',
|
status: 'monitoring',
|
||||||
targetShares,
|
targetShares: actualShares,
|
||||||
yes: {
|
yes: {
|
||||||
tokenId: yesTokenId,
|
tokenId: yesTokenId,
|
||||||
buyPrice: yesBid,
|
buyPrice: yesBid,
|
||||||
|
|||||||
Reference in New Issue
Block a user