Skip to content

Commit

Permalink
Merge branch 'main' into feature/trade_6
Browse files Browse the repository at this point in the history
# Conflicts:
#	build.gradle.kts
#	src/commonMain/kotlin/exchange.dydx.abacus/processor/input/ClosePositionInputProcessor.kt
#	src/commonMain/kotlin/exchange.dydx.abacus/state/internalstate/InternalState.kt
#	src/commonMain/kotlin/exchange.dydx.abacus/state/model/TradingStateMachine.kt
#	v4_abacus.podspec
  • Loading branch information
ruixhuang committed Aug 26, 2024
2 parents 50185be + 46665dc commit 4ddcf9b
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 62 deletions.
63 changes: 63 additions & 0 deletions .github/workflows/bump_version_on_main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Bump version
on:
push:
branches:
- prashan-testing

jobs:
update_version:
#if: github.event.pull_request.merged == true
runs-on: macos-latest
steps:
- name: checkout
uses: actions/checkout@v4
with:
# Fetch full depth, otherwise the last step overwrites the last commit's parent, essentially removing the graph.
fetch-depth: 0
token: ${{ secrets.BOT_PAT }}
ref: ${{ github.head_ref }}

- name: Import bot's GPG key for signing commits
id: import-gpg
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true

- name: Bump version
id: bump-version
run: |
# exit early if current commit was a version bump.
git show -s --format=%s | grep -q "^BUMP-VERSION" && exit 0
# search for the first line that starts with "version" in build.gradle.kts
# get the value in the quotes
VERSION=$(grep "^version = " build.gradle.kts | sed -n 's/version = "\(.*\)"/\1/p')
# increment the version number
NEW_VERSION=$(echo $VERSION | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')
#if NEW_VERSION is not empty, replace the version in build.gradle.kts and podspec
if [ -n "$NEW_VERSION" ]; then
sed -i '' "s/version = \"$VERSION\"/version = \"$NEW_VERSION\"/" build.gradle.kts
sed -i '' "s/spec.version *= *'[0-9.]*'/spec.version = '$NEW_VERSION'/" v4_abacus.podspec
# this condition gets added when kmp generates the pod, but it breaks our iOS dependency flow
sed -i '' "s/if \!Dir.exist?('build\/cocoapods\/framework\/Abacus.framework') || Dir.empty?('build\/cocoapods\/framework\/Abacus.framework')/if false/" v4_abacus.podspec
echo "Version bumped to $NEW_VERSION"
git config --global user.email ${{ steps.import-gpg.outputs.name }}
git config --global user.name ${{ steps.import-gpg.outputs.email }}
git add build.gradle.kts
git add v4_abacus.podspec
git commit -S -m "BUMP-VERSION: $NEW_VERSION"
git push
fi
env:
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
GIT_AUTHOR_NAME: ${{ steps.import-gpg.outputs.name }}
GIT_AUTHOR_EMAIL: ${{ steps.import-gpg.outputs.email }}
GIT_COMMITTER_NAME: ${{ steps.import-gpg.outputs.name }}
GIT_COMMITTER_EMAIL: ${{ steps.import-gpg.outputs.email }}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ allprojects {
}

group = "exchange.dydx.abacus"
version = "1.8.105"
version = "1.9.3"

repositories {
google()
Expand Down
14 changes: 12 additions & 2 deletions docs/Input.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ data class Input(
 val trade: [TradeInput](Input/TradeInput.md)?,
 val closePosition: [ClosePositionInput](Input/ClosePosition.md)?,
 val transfer: [TransferInput](Input/TransferInput.md)?,
 val triggerOrders: [TriggerOrdersInput](Input/TriggerOrdersInput.md)?,
 val adjustIsolatedMargin: [AdjustIsolatedMarginInput](Input/AdjustIsolatedMarginInput.md)?,
 val receiptLines: ReceiptLines?,
&emsp;val errors: Array<ValidationError>?
)
Expand All @@ -17,6 +19,8 @@ Indicating the current input:
trade
transfer
closePosition
triggerOrders
adjustIsolatedMargin

## trade

Expand All @@ -30,6 +34,14 @@ Close Position input object

Transfer state

## triggerOrders

Trigger Order Dialog input object

## adjustIsolatedMargin

Adjust Isolated Margin Dialog input object

## receiptLines

A list of receipt lines to be displayed in the receipt area
Expand All @@ -38,5 +50,3 @@ A list of receipt lines to be displayed in the receipt area

A list of errors or warning for the current input

# TradeInput

26 changes: 22 additions & 4 deletions docs/Input/AdjustIsolatedMarginInput.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# AdjustIsolatedMarginInput

data class AdjustIsolatedMarginInput(
&emsp;val type: String?, // "ADD" or "REMOVE"
&emsp;val amount: Double?,
&emsp;val market: String?,
&emsp;val type: IsolatedMarginAdjustmentType, // "ADD" or "REMOVE"
&emsp;val amount: String?,
&emsp;val amountPercent: String?,
&emsp;val amountInput: IsolatedMarginInputType?, // "AMOUNT" or "PERCENT"
&emsp;val childSubaccountNumber: Int?,
&emsp;val adjustIsolatedMarginInputOptions: AdjustIsolatedMarginInputOptions?,
&emsp;val summary: AdjustIsolatedMarginInputSummary?,
)

## market

Market

## type

ADD - Add margin to the child's isolated margin account from the parent's cross margin account
Expand All @@ -15,7 +24,16 @@ REMOVE - Remove margin from the child's isolated margin account to the parent's

Amount of USDC to remove or add

## childSubaccountNumber
## amountPercent

Percentage of available USDC to remove or add; percent of max possible position (capped by current position leverage relative to market's max leverage)

Subaccount number for the child whose margin is to be adjusted
## amountInput

Which one of the fields are entered by the user:
- AMOUNT
- PERCENT

## childSubaccountNumber

Subaccount number for the child whose margin is to be adjusted
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package exchange.dydx.abacus.calculator

import exchange.dydx.abacus.output.input.IsolatedMarginAdjustmentType
import exchange.dydx.abacus.output.input.IsolatedMarginInputType
import exchange.dydx.abacus.protocols.ParserProtocol
import exchange.dydx.abacus.utils.MARGIN_COLLATERALIZATION_CHECK_BUFFER
import exchange.dydx.abacus.utils.MAX_LEVERAGE_BUFFER_PERCENT
import exchange.dydx.abacus.utils.Numeric
import exchange.dydx.abacus.utils.mutable
import exchange.dydx.abacus.utils.safeSet
import kotlin.math.max
import kotlin.math.min

@Suppress("UNCHECKED_CAST")
internal class AdjustIsolatedMarginInputCalculator(val parser: ParserProtocol) {
Expand All @@ -21,8 +26,13 @@ internal class AdjustIsolatedMarginInputCalculator(val parser: ParserProtocol) {
IsolatedMarginAdjustmentType.valueOf(it)
} ?: IsolatedMarginAdjustmentType.Add

return if (wallet != null && isolatedMarginAdjustment != null) {
val markets = parser.asNativeMap(state["markets"])
val marketId = isolatedMarginAdjustment?.get("Market")
val market = if (marketId != null) parser.asNativeMap(markets?.get(marketId)) else null

return if (wallet != null && isolatedMarginAdjustment != null && market != null) {
val modified = state.mutable()

val parentTransferDelta = getModifiedTransferDelta(isolatedMarginAdjustment, true)
val childTransferDelta = getModifiedTransferDelta(isolatedMarginAdjustment, false)

Expand All @@ -46,16 +56,105 @@ internal class AdjustIsolatedMarginInputCalculator(val parser: ParserProtocol) {

val modifiedParentSubaccount = parser.asNativeMap(parser.value(walletPostChildSubaccountTransfer, "account.subaccounts.$parentSubaccountNumber"))
val modifiedChildSubaccount = parser.asNativeMap(parser.value(walletPostChildSubaccountTransfer, "account.subaccounts.$childSubaccountNumber"))
val modifiedIsolatedMarginAdjustment = finalize(isolatedMarginAdjustment, modifiedParentSubaccount, modifiedChildSubaccount, type)
val updatedIsolatedMarginAdjustment = calculateAmounts(isolatedMarginAdjustment, modifiedParentSubaccount, modifiedChildSubaccount, market, type)

modified["adjustIsolatedMargin"] = modifiedIsolatedMarginAdjustment
modified["adjustIsolatedMargin"] = finalize(updatedIsolatedMarginAdjustment, modifiedParentSubaccount, modifiedChildSubaccount, type)
modified["wallet"] = walletPostChildSubaccountTransfer
modified
} else {
state
}
}

private fun calculateAmounts(
adjustIsolatedMargin: Map<String, Any>,
parentSubaccount: Map<String, Any>?,
childSubaccount: Map<String, Any>?,
market: Map<String, Any>,
type: IsolatedMarginAdjustmentType,
): MutableMap<String, Any> {
val modified = adjustIsolatedMargin.mutable()
val inputType = parser.asString(modified["AmountInput"])?.let {
IsolatedMarginInputType.valueOf(it)
}

if (inputType != null) {
val notionalTotal = parser.asDouble(parser.value(childSubaccount, "notionalTotal.current")) ?: return modified
val equity = parser.asDouble(parser.value(childSubaccount, "equity.current"))
val availableCollateralToTransfer = parser.asDouble(parser.value(parentSubaccount, "freeCollateral.current"))

val baseAmount = when (type) {
IsolatedMarginAdjustmentType.Add -> availableCollateralToTransfer
IsolatedMarginAdjustmentType.Remove -> equity
}

val amountPercent = parser.asDouble(modified["AmountPercent"])
val amountValue = parser.asDouble(modified["Amount"])

val initialMarginFraction =
parser.asDouble(parser.value(market, "configs.effectiveInitialMarginFraction"))
?: return modified
val maxMarketLeverage = if (initialMarginFraction <= Numeric.double.ZERO) {
return modified
} else {
Numeric.double.ONE / initialMarginFraction
}

when (inputType) {
IsolatedMarginInputType.Amount -> {
if (baseAmount != null && baseAmount > Numeric.double.ZERO && amountValue != null) {
when (type) {
IsolatedMarginAdjustmentType.Add -> {
val percent = amountValue / baseAmount
modified.safeSet("AmountPercent", percent.toString())
}
IsolatedMarginAdjustmentType.Remove -> {
val maxRemovableAmount = baseAmount - notionalTotal / (maxMarketLeverage * MAX_LEVERAGE_BUFFER_PERCENT)
if (maxRemovableAmount > Numeric.double.ZERO) {
val percent = amountValue / maxRemovableAmount
modified.safeSet("AmountPercent", percent.toString())
} else {
modified.safeSet("AmountPercent", null)
}
}
}
} else {
modified.safeSet("AmountPercent", null)
}
}
IsolatedMarginInputType.Percent -> {
if (baseAmount != null && baseAmount >= Numeric.double.ZERO && amountPercent != null) {
when (type) {
IsolatedMarginAdjustmentType.Add -> {
// The amount to add is a percentage of all add-able margin (your parent subaccount's free collateral)
val amount = baseAmount * amountPercent
// We leave behind MARGIN_COLLATERALIZATION_CHECK_BUFFER to pass collateralization checks
val cappedAmount = min(max(baseAmount - MARGIN_COLLATERALIZATION_CHECK_BUFFER, 0.0), amount)
modified.safeSet("Amount", cappedAmount.toString())
}
IsolatedMarginAdjustmentType.Remove -> {
// The amount to remove is a percentage of all remov-able margin (100% puts you at the market's max leveage)
// leverage = notional total / equity
// marketMaxLeverage = notional total / (currentEquity - amount)
// amount = currentEquity - notionalTotal / marketMaxLeverage
val amountToRemove = baseAmount - notionalTotal / (maxMarketLeverage * MAX_LEVERAGE_BUFFER_PERCENT)
if (amountToRemove >= Numeric.double.ZERO) {
val amount = amountToRemove * amountPercent
modified.safeSet("Amount", amount.toString())
} else {
modified.safeSet("Amount", null)
}
}
}
} else {
modified.safeSet("Amount", null)
}
}
}
}
return modified
}

private fun getModifiedTransferDelta(
isolatedMarginAdjustment: Map<String, Any>,
isParentSubaccount: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,21 @@ enum class IsolatedMarginAdjustmentType {
Remove
}

@JsExport
@Serializable
enum class IsolatedMarginInputType {
Amount,
Percent
}

@JsExport
@Serializable
data class AdjustIsolatedMarginInput(
val market: String?,
val type: IsolatedMarginAdjustmentType,
val amount: String?,
val amountPercent: String?,
val amountInput: IsolatedMarginInputType?,
val childSubaccountNumber: Int?,
val adjustIsolatedMarginInputOptions: AdjustIsolatedMarginInputOptions?,
val summary: AdjustIsolatedMarginInputSummary?
Expand All @@ -128,13 +137,18 @@ data class AdjustIsolatedMarginInput(
Logger.d { "creating Adjust Isolated Margin Input\n" }

data?.let {
val market = parser.asString(data["Market"])

val type = parser.asString(data["Type"])?.let {
IsolatedMarginAdjustmentType.valueOf(it)
} ?: IsolatedMarginAdjustmentType.Add

val childSubaccountNumber = parser.asInt(data["ChildSubaccountNumber"])
val amount = parser.asString(data["Amount"])
val amountPercent = parser.asString(data["AmountPercent"])
val amountInput = parser.asString(data["AmountInput"])?.let {
IsolatedMarginInputType.valueOf(it)
}

val adjustIsolatedMarginInputOptions = AdjustIsolatedMarginInputOptions.create(
existing?.adjustIsolatedMarginInputOptions,
Expand All @@ -148,17 +162,21 @@ data class AdjustIsolatedMarginInput(
)

return if (
existing?.market != market ||
existing?.type != type ||
existing.amount != amount ||
existing.amountPercent != amountPercent ||
existing.amountInput != amountInput ||
existing.childSubaccountNumber != childSubaccountNumber ||
existing.adjustIsolatedMarginInputOptions != adjustIsolatedMarginInputOptions ||
existing.summary !== summary
) {
AdjustIsolatedMarginInput(
market,
type,
amount,
amountPercent,
amountInput,
childSubaccountNumber,
adjustIsolatedMarginInputOptions,
summary,
Expand Down
Loading

0 comments on commit 4ddcf9b

Please sign in to comment.