mm rewards (#591)

* mm rewards wip

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* update

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Rename rewards.ts to mm-rewards-calculator.ts

---------

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2023-06-16 08:31:33 +02:00 committed by GitHub
parent 0281a1b8ed
commit c68b1b22cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 162 additions and 0 deletions

View File

@ -0,0 +1,162 @@
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { BookSide, PerpMarket } from '../src/accounts/perp';
import { MangoClient } from '../src/client';
import { MANGO_V4_ID } from '../src/constants';
const { MB_CLUSTER_URL } = process.env;
const GROUP_PK = '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX';
async function buildClient(): Promise<MangoClient> {
const clientKeypair = new Keypair();
const options = AnchorProvider.defaultOptions();
const connection = new Connection(MB_CLUSTER_URL!, options);
const clientWallet = new Wallet(clientKeypair);
const clientProvider = new AnchorProvider(connection, clientWallet, options);
return await MangoClient.connect(
clientProvider,
'mainnet-beta',
MANGO_V4_ID['mainnet-beta'],
{
idsSource: 'get-program-accounts',
},
);
}
function doBin(
bs: BookSide,
direction: 'bids' | 'asks',
range: {
start: number;
end: number;
scoreMultiplier: number;
queueMultiplier: number;
},
): Map<string, { size: number; score: number }> {
const bin = new Map<string, number>();
const binWithScore = new Map();
const best = bs.best();
if (!best) {
return binWithScore;
}
const bestPrice = best?.price;
const binStart =
bestPrice +
(((direction == 'bids' ? -1 : 1) * range.start) / 10000) * bestPrice;
const binEnd =
bestPrice +
(((direction == 'bids' ? -1 : 1) * range.end) / 10000) * bestPrice;
let lastSeenPrice = best.price;
let queuePosition = 0; // TODO unused
for (const item of bs.items()) {
if (lastSeenPrice != item.price) {
lastSeenPrice = item.price;
queuePosition = 0;
} else {
queuePosition = queuePosition + 1;
}
if (direction == 'bids' ? item.price <= binEnd : item.price >= binEnd) {
break;
}
if (direction == 'bids' ? item.price > binStart : item.price < binStart) {
continue;
}
bin.set(
item.owner.toBase58(),
(bin.get(item.owner.toBase58()) ?? 0) + item.size,
);
}
for (const key of bin.keys()) {
const size = bin.get(key);
if (!size) {
continue;
}
binWithScore.set(key, {
size,
score: size * range.scoreMultiplier,
});
}
return binWithScore;
}
function doSide(bs: BookSide, direction: 'bids' | 'asks'): Map<string, number> {
const bins: Map<string, { size: number; score: number }>[] = [];
for (const range of [
// Range end is exclusive, and start in inclusive
{ start: 0, end: 1, scoreMultiplier: 100, queueMultiplier: 1.25 },
{ start: 1, end: 5, scoreMultiplier: 50, queueMultiplier: 1.25 },
{ start: 5, end: 10, scoreMultiplier: 20, queueMultiplier: 1.25 },
{ start: 10, end: 20, scoreMultiplier: 7.5, queueMultiplier: 1.25 },
{ start: 20, end: 50, scoreMultiplier: 5, queueMultiplier: 1.25 },
{ start: 50, end: 100, scoreMultiplier: 2.5, queueMultiplier: 1.25 },
]) {
bins.push(doBin(bs, direction, range));
}
const aggr = new Map();
for (const bin of bins) {
for (const accountPk of bin.keys()) {
const value = bin.get(accountPk);
if (!value) {
continue;
}
const binScore = value.score;
aggr.set(accountPk, (aggr.get(accountPk) ?? 0) + binScore);
}
}
return aggr;
}
async function doMarket(
client: MangoClient,
pm: PerpMarket,
): Promise<Map<string, number>> {
const bidsAggr = doSide(await pm.loadBids(client, true), 'bids');
const asksAggr = doSide(await pm.loadAsks(client, true), 'asks');
const marketAggr = new Map();
const marketAggrNorm = new Map();
for (const accountPk of bidsAggr.keys()) {
const score = bidsAggr.get(accountPk);
if (!score) {
continue;
}
marketAggr.set(accountPk, (marketAggr.get(accountPk) ?? 0) + score);
}
for (const accountPk of asksAggr.keys()) {
const score = asksAggr.get(accountPk);
if (!score) {
continue;
}
marketAggr.set(accountPk, (marketAggr.get(accountPk) ?? 0) + score);
}
const scoreSum = Array.from(marketAggr.values()).reduce((a, b) => a + b, 0);
for (const key of marketAggr.keys()) {
marketAggrNorm.set(key, (marketAggr.get(key) / scoreSum) * 100);
}
return marketAggrNorm;
}
async function main(): Promise<void> {
const client = await buildClient();
const group = await client.getGroup(new PublicKey(GROUP_PK));
for (const pm of group.perpMarketsMapByMarketIndex.values()) {
console.log(pm.name, await doMarket(client, pm));
}
}
main();