-
Notifications
You must be signed in to change notification settings - Fork 42
Bigz/maker orders #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| import * as anchor from "@project-serum/anchor"; | ||
| import { Provider } from "@project-serum/anchor"; | ||
| import { | ||
| Admin, | ||
| BN, | ||
| AMM_RESERVE_PRECISION, | ||
| calculateMarkPrice, | ||
| getLimitOrderParams, | ||
| PositionDirection, | ||
| ClearingHouse, | ||
| ClearingHouseUser, | ||
| ZERO, | ||
| OrderParams, | ||
| isVariant, | ||
| Markets, | ||
| initialize, | ||
| DriftEnv, | ||
| // Wallet, | ||
| } from "@drift-labs/sdk"; | ||
|
|
||
| import dotenv = require("dotenv"); | ||
| import { PublicKey, TransactionSignature, Transaction } from "@solana/web3.js"; | ||
|
|
||
| dotenv.config(); | ||
|
|
||
| async function cancelAllThenPlaceNewOrders( | ||
| clearingHouse: ClearingHouse, | ||
| clearingHouseUser: ClearingHouseUser, | ||
| orderParams: OrderParams[], | ||
| discountToken?: PublicKey, | ||
| referrer?: PublicKey | ||
| ): Promise<TransactionSignature> { | ||
| const instructions: anchor.web3.TransactionInstruction[] = []; | ||
| const userOrdersAccountExists = | ||
| await clearingHouse.userOrdersAccountExists(); | ||
|
|
||
| const orderAccount = clearingHouseUser.getUserOrdersAccount(); | ||
| let numOpenOrders = 0; | ||
| for (const order of orderAccount.orders) { | ||
| if (!isVariant(order.status, "init")) { | ||
| numOpenOrders += 1; | ||
| } | ||
| } | ||
| const markets = clearingHouse.getMarketsAccount(); | ||
|
|
||
| const markets_with_position = clearingHouseUser | ||
| .getUserPositionsAccount() | ||
| .positions.map((position) => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should filter out the markets where base asset amount is zero. Right now this will always say it's five positions? |
||
| return position.marketIndex.toString(); | ||
| }); | ||
|
|
||
| // cancel all open orders before placing new ones | ||
| // if (userOrdersAccountExists && numOpenOrders > 0) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should just assumed |
||
| // const oracles = clearingHouseUser | ||
| // .getUserPositionsAccount() | ||
| // .positions.map((position) => { | ||
| // return markets.markets[position.marketIndex.toString()].amm | ||
| // .oracle; | ||
| // }); | ||
| // console.log("canceling all open orders (", numOpenOrders, ")"); | ||
|
|
||
| // // todo: check if all orders cannot be filled at market first | ||
| // instructions.push(await clearingHouse.getCancelAllOrdersIx(oracles)); | ||
| // } | ||
|
|
||
| console.log("placing", orderParams.length, "new orders"); | ||
|
|
||
| // post list of orders | ||
| for (const orderParm of orderParams) { | ||
| const orderMarket = orderParm.marketIndex.toString(); | ||
|
|
||
| // convient check/message for too many positions/orders across markets | ||
| if ( | ||
| markets_with_position.length >= 5 && | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will never be greater than 5, can probably make it |
||
| !markets_with_position.includes(orderMarket) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the order doesnt exist in marketsWithPosition, should probably add it so we can keep track of number of positions after orders are canceled and then replaced |
||
| ) { | ||
| throw new Error( | ||
| "Cannot place an order for additional MarketIndex=" + | ||
| orderMarket + | ||
| ". The max number of cross margined positions per account is 5." | ||
| ); | ||
| } | ||
|
|
||
| instructions.push( | ||
| await clearingHouse.getPlaceOrderIx( | ||
| orderParm, | ||
| discountToken, | ||
| referrer | ||
| ) | ||
| ); | ||
| } | ||
| const tx = new Transaction(); | ||
| for (const instruction of instructions) { | ||
| tx.add(instruction); | ||
| } | ||
|
|
||
| // send all of above in single atomic transaction | ||
| let txResult = await clearingHouse.txSender.send( | ||
| tx, | ||
| [], // additionalSigners | ||
| clearingHouse.opts // transaction ConfirmOptions | ||
| ); | ||
|
|
||
| return txResult; | ||
| } | ||
|
|
||
| function constructFloatingMMSpread( | ||
| clearingHouse: ClearingHouse, | ||
| marketIndex: BN, | ||
| baseAssetAmount: BN, | ||
| postOnly: boolean | ||
| ) { | ||
| const market = clearingHouse.getMarket(marketIndex); | ||
| const limitPrice = ZERO; | ||
| // const limitPrice = market.amm.lastMarkPriceTwap; | ||
|
|
||
| // 10 bps | ||
| const offset = market.amm.lastMarkPriceTwap.div(new BN(-1000)); | ||
|
|
||
| //bid | ||
| const orderParams = getLimitOrderParams( | ||
| marketIndex, | ||
| PositionDirection.LONG, | ||
| baseAssetAmount, | ||
| limitPrice, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| 0, | ||
| postOnly, | ||
| offset, | ||
| false //ioc | ||
| ); | ||
|
|
||
| // ask | ||
| const orderParams2 = getLimitOrderParams( | ||
| marketIndex, | ||
| PositionDirection.SHORT, | ||
| baseAssetAmount, | ||
| limitPrice, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| 0, | ||
| postOnly, | ||
| offset.mul(new BN(-1)), | ||
| false //ioc | ||
| ); | ||
|
|
||
| return [orderParams, orderParams2]; | ||
| } | ||
|
|
||
| function constructFixedMMSpread( | ||
| clearingHouse: ClearingHouse, | ||
| marketIndex: BN, | ||
| baseAssetAmount: BN, | ||
| postOnly: boolean | ||
| ) { | ||
| const market = clearingHouse.getMarket(marketIndex); | ||
| const limitPrice = calculateMarkPrice(market); | ||
| const offset = limitPrice.div(new BN(10000)); // 1 bps | ||
|
|
||
| //bid | ||
| const orderParams = getLimitOrderParams( | ||
| marketIndex, | ||
| PositionDirection.LONG, | ||
| baseAssetAmount, | ||
| limitPrice.sub(offset), // price | ||
| false, // reduce only | ||
| undefined, //discount (not currently supported) | ||
| undefined, // referfee (not currently supported) | ||
| 0, // user Order Id | ||
| postOnly, | ||
| ZERO, | ||
| false //ioc | ||
| ); | ||
|
|
||
| // ask | ||
| const orderParams2 = getLimitOrderParams( | ||
| marketIndex, | ||
| PositionDirection.SHORT, | ||
| baseAssetAmount, | ||
| limitPrice.add(offset), | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| 0, | ||
| postOnly, | ||
| ZERO, | ||
| false //ioc | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to upgrade the package.json to at least use |
||
| ); | ||
|
|
||
| return [orderParams, orderParams2]; | ||
| } | ||
|
|
||
| async function makeMarket(provider: Provider, marketIndex: BN) { | ||
| const connection = provider.connection; | ||
| const sdkConfig = initialize({ env: "devnet" as DriftEnv }); //change to "mainnet-beta" for production | ||
| const clearingHousePublicKey = new PublicKey( | ||
| sdkConfig.CLEARING_HOUSE_PROGRAM_ID | ||
| ); | ||
| const clearingHouse = Admin.from( | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this shouldnt be using Admin. can we use |
||
| connection, | ||
| provider.wallet, | ||
| clearingHousePublicKey | ||
| ); | ||
| await clearingHouse.subscribe(); | ||
|
|
||
| const user = ClearingHouseUser.from( | ||
| clearingHouse, | ||
| provider.wallet.publicKey | ||
| ); | ||
| await user.subscribe(); | ||
|
|
||
| console.log( | ||
| "User Authority:", | ||
| provider.wallet.publicKey.toString(), | ||
| "| ClearingHouse ProgramID:", | ||
| clearingHousePublicKey.toString() | ||
| ); | ||
|
|
||
| // Drift Protocol Maker Order Example: | ||
|
|
||
| // The orders are placed atomically (all or nothing) and are by default Post Only (0 protocol fee if filled) | ||
| // the transaction will fail if the market moves s.t any order can be filled when recieved. this guarantees | ||
| // that the spread will be posted. | ||
|
|
||
| const baseAssetAmount = AMM_RESERVE_PRECISION; // AMM_RESERVE_PRECISION (1e13) represents 1 base asset (SOL/BTC/etc) | ||
| const postOnly = true; // 0 protocol fee (but also no price improvement) | ||
|
|
||
| // Places a Bid/Ask 1 bp from the current Mark Price for the selected Market | ||
| // | ||
| // e.g. Long 1 SOL @ <Market Price * .9999> | ||
| // e.g. Short 1 SOL @ <Market Price * 1.0001> | ||
| // ( for a $100 contract this is a 2 cent spread ) | ||
| const bidAskOrdersParams: OrderParams[] = constructFixedMMSpread( | ||
| clearingHouse, | ||
| marketIndex, | ||
| baseAssetAmount, | ||
| postOnly | ||
| ); | ||
| let tx = await cancelAllThenPlaceNewOrders( | ||
| clearingHouse, | ||
| user, | ||
| bidAskOrdersParams | ||
| ); | ||
|
|
||
| console.log(tx); | ||
|
|
||
| // await clearingHouse.cancelOrder(new BN(46)); | ||
| // await clearingHouse.cancelOrder(new BN(19)); | ||
| // await clearingHouse.cancelOrder(new BN(20)); | ||
|
|
||
| await clearingHouse.unsubscribe(); | ||
| } | ||
|
|
||
| try { | ||
| if (!process.env.ANCHOR_WALLET) { | ||
| throw new Error( | ||
| "ANCHOR_WALLET env variable must be set. (file path, e.g. ~/.config/solana/<your_wallet>.json)" | ||
| ); | ||
| } | ||
|
|
||
| // Get current price | ||
| const solMarketInfo = Markets.find( | ||
| (market) => market.baseAssetSymbol === "SOL" | ||
| ); | ||
|
|
||
| const marketIndex = solMarketInfo.marketIndex; | ||
| const rpcAddress = "https://api.devnet.solana.com"; // for devnet; https://api.mainnet-beta.solana.com for mainnet; | ||
|
|
||
| makeMarket(anchor.Provider.local(rpcAddress), marketIndex); | ||
| } catch (e) { | ||
| console.error(e); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs to be camelCase