Imagine a strategy that can be as stable as a rock in the violent fluctuations of the digital currency market, and can bring you continuous positive returns regardless of bull or bear markets. Does it sound like a fantasy? Actually, it is not. The currency-based double short-selling fee arbitrage strategy is such an "earning effortlessly" tool.
By utilizing the unique properties of currency-based contracts and the funding rate mechanism cleverly, this strategy can not only obtain stable returns in a bull market, but also avoid risks in a bear market effectively, achieving a steady return across market period. The "cash preservation" feature of currency-based contracts allows the total value of the strategy to remain stable even if market prices fluctuate significantly. The funding rate, as the core mechanism of perpetual contracts, provides an additional source of profits for the strategy. In this article, we will deeply analyze the core logic, implementation process, and advantages and disadvantages of the currency-based short-selling strategy to help investors understand how to achieve "earning effortlessly" through this strategy in the digital currency market. Whether you are a novice in quantitative trading or an experienced investor, this strategy is worth your in-depth understanding and trial.
Currency-Based Short-Selling
Characteristics of the currency-based
The unit of the currency-based contract is measured in sheets, and the value of each sheet is fixed (for example, 1 contract of BTC is worth 100 USD, and 10 USD of ETH). This feature means that in the case of 1x leverage, even if the market price fluctuates greatly, there will be no liquidation in theory.
Profit and loss analysis
Assuming the current price is 100 USD, 10 currency-Based short contracts are opened, and their value is equal to 100 USD, which is converted into 1 unit of coin:
1. Price drop:
- The price drops to 50 USD, and the profit rate is:
profit rate = (100-50)/50=100%
The number of coins held becomes 2, and the total value remains:
2*50=100 USD
2. Price increase:
- The price rises to 200 USD, and the rate of return is:
profit rate = (100-200)/200=-50%
The number of coins held becomes 0.5, and the total value remains:
0.5*200=100 USD
Therefore, to a certain extent, the total value of short selling in the currency-based remains stable, which is a cash preservation operation. So where does the profits of the strategy come from? Let us introduce the next concept: funding rate .
Funding Rate
In the currency-based short-selling strategy, the funding rate is one of the core drivers of the strategy's returns, and its characteristics and changes affect the strategy's stability and profitability directly. By utilizing the characteristics of the funding rate properly, the strategy can maintain good performance in different market environments, but it is also necessary to pay attention to its potential limitations.
Definition and characteristics of funding rate
Funding rate is a regulatory mechanism in the perpetual contract market, which aims to balance the holding costs of both long and short parties and prevent the perpetual contract price from deviating from the spot price for a long time. In fact, if you have studied CFA, you will still remember the original name of the perpetual contract, swap. The design inspiration of the funding rate mechanism of the perpetual contract is largely derived from the Interest Rate Swap in traditional finance. In an interest rate swap, the two parties exchange interest payments regularly based on the agreed interest rate (such as fixed interest rate and floating interest rate) to hedge the risk of interest rate fluctuations. Similarly, the funding rate mechanism of the perpetual contract also balances the holding costs of both long and short parties by paying or collecting fees regularly to ensure that the gap between the contract price and the spot price is not too large.
![](https://www.fmz.com/upload/asset/28e3c938d14515cd321d5.png)
The introduction of funding rate is essentially to solve the basis problem between perpetual contracts and spot prices. When the perpetual contract price is higher than the spot price, the funding rate is positive, and the long position pays the short position; when the perpetual contract price is lower than the spot price, the funding rate is negative, and the short position pays the long position. This mechanism not only draws on the core concept of interest rate swaps, but also combines the characteristics of the digital currency market to form a unique market regulation tool. In the field of digital currency, its main features include:
1. Determined by market supply and demand : The funding rate is determined by the supply and demand relationship between longs and shorts in the market, and is the result of the game between long and short forces.
2. Periodic payment : The funding rate is paid at a certain period (such as 8 hours), and the fees are transferred between long and short positions.
3. Sentiment reflection : A positive funding rate usually indicates that market sentiment is bullish and the perpetual contract price is higher than the spot price; a negative funding rate indicates that market sentiment is bearish and the perpetual contract price is lower than the spot price.
Positive funding rate (Funding rate > 0)
- Performance : In a positive funding environment, longs need to pay fees to shorts.
- Profit logic : With the stable payment of funding rate, the strategy continues to collect funding fees by holding short positions, and even if the market price rises, it will not have a large negative impact on the profits. For example, when the funding rate is 0.02%/8 hours, holding a contract worth $10,000 can obtain daily profits:
daily profits = 10,000*0.02%*3=6USDT
This source of profits is relatively stable and has little to do with price fluctuations.
Negative funding rate (Funding rate < 0)
- Performance : When the funding rate is negative, short positions need to pay fees to long positions, and the strategy returns may be compressed or even result in losses.
- Risk point : When negative funding rates last for a long time or fluctuate greatly, such as a long-term bear market, the strategy may face higher costs due to paying funding fees, resulting in the overall return being unable to cover operating costs.
Strategy Profit Sources
As Zinan have said, in the initial stage of strategy construction, it is necessary to understand the source of profits and risk of the strategy. Based on the above, we know that the total value of currency-based short selling is to remain stable, so the source of profits is funding rate arbitrage. Some students may be curious, will the funding rate continue to bring stable positive returns? We conduct data analysis work at datadata.com:
SELECTExchange, Symbol, toDateTime(Time / 1000) ASTime, -- Convert milliseconds timestamptotimestampRate, SUM(Rate) OVER (PARTITIONBYExchange, SymbolORDERBYTime) ASCumulativeRate -- Calculate the accumulated RateFROM klines.fundingWHEREExchange = '{{exchange}}'ANDSymbol = '{{symbol}}'ORDERBYTime;
![](https://www.fmz.com/upload/asset/28d460172bb00d567c771.png)
The dynamic parameters use Binance exchange, and the contract selects the Bitcoin standard (btc_usd) contract to display the cumulative funding rate. It can be seen that from 2020 to now, the funding rate returns has shown a steady increase, with a cumulative 5-year returns of up to 50%. Although it cannot be compared with the income of hundreds or thousands, it is more stable, so we can sort out the profit source of this strategy.
In the currency-based short-selling strategy, the funding rate is the key source of profit. Since the units of currency-based contracts are fixed, even if the market price fluctuates, the change in the contract value of the short seller is usually controllable, so the funding rate becomes the main source of profit for the strategy. The following is the specific impact of the funding rate on the strategy:
1. Bull market phase (Positive funding rate)
- Market phenomenon : In a bull market, due to high market sentiment, investors generally tend to go long, resulting in an increase in long positions, thereby pushing the funding rate to a positive value.
- Profit logic : In this case, short sellers will benefit from the funding rate paid by long positions, which will become the main profit source of the strategy. Since the funding rate is positive, short positions can continue to make profits, and by utilizing the obtained funding rate, they can continue to open short positions and obtain more funding rate profits.
- Specific impact : If the funding rate is positive and stable, short positions will receive funding rates regularly and will not be affected too much by price fluctuations. Even if the market price rises, short positions may face large apparent losses on the contract, but overall, the net value of funds remains relatively stable. This is because the profit source of the strategy mainly depends on the collection of funding rates, rather than price fluctuations. Although price fluctuations may have an impact on the apparent loss of the contract, since the change in the contract value of the short position is controllable, the main profit of the funds still comes from the regular collection of funding rates, rather than market price fluctuations. This enables the strategy to offset the risk of price fluctuations to a certain extent and maintain the stable appreciation of funds.
2. Bear market phase (Negative funding rate)
- Market phenomenon : In a bear market, market prices fall rapidly and short positions usually surge, causing the funding rate to become negative, that is, shorts need to pay fees to longs. However, due to the booming digital currency market in recent years, the bear market stage is relatively rare.
- Profit logic : Although the funding rate is negative and short positions need to pay fees, the hedging characteristics of the strategy are still effective because the unit of the short contract is fixed and the contract value of the short position changes little. The sharp price fluctuations will not lead to large losses. At the same time, the burden of the funding rate is relatively controllable, and the strategy can still remain stable to a certain extent.
Through the analysis of these two market environments, it can be seen that the profit and risk of the currency-based short-selling strategy are mainly affected by the funding rate. When the funding rate is positive in the bull market, short sellers can benefit from it; while in the bear market, although the funding rate is negative, the strategy still has a strong ability to preserve value because the change in contract value is controllable.
Strategy Logical Architecture
A robust strategy framework is the key to successful implementation of a strategy. It provides a clear execution framework to ensure that the strategy can operate stably under various market conditions and effectively respond to risks and fluctuations. Here we refer to Xiaocao's U-standard multi-currency contract strategy framework and make some modifications and improvements to the currency-based.
'''backtest start: 2020-08-14 00:00:00 end: 2025-01-20 00:00:00 period: 1d basePeriod: 1d exchanges: [{"eid":"Futures_OKX","currency":"BTC_USD"}] '''import time import json # Global variables, storing data SYMBOLS = 'BTC'# SYMBOLS represents the currency to be traded, in the format of "BTC,ETH,LTC" QUOTO = 'USD'# QUOTO is the base currency, and the currency standard is USD INTERVAL = 5# INTERVAL represents the interval of the loop ICEMONEY = 2000# Iceberg order amount ROLLINGNUM = 1# Rolling profit increase quantity Info = { 'trade_symbols': SYMBOLS.split(','), # Trading currency'base_coin': QUOTO, # Base currency'ticker': {}, # Ticker data'order': {}, # Order information'account': {}, # Account information'precision': {}, # Precision information'position': {}, # Position information'time': {}, # Time-related data'count': {}, # Counter'interval': INTERVAL # Loop interval } # Initialize the strategydefInitInfo(): # Initialize time data and control the update time Info['time'] = { 'update_ticker_time': 0, # Update ticker time'update_pos_time': 0, # Update position time'update_profit_time': 0, # Update profit time'update_account_time': 0, # Update account information time'update_status_time': 0, # Update status time'last_loop_time': 0, # The time of the last main loop'loop_delay': 0, # Loop delay'start_time': time.time() # Start time } # Initialize the data of each transaction currencyfor symbol in Info['trade_symbols']: Info['account'][symbol] = { 'init_balance': 0, # Initial balance'margin_balance': 0, # Margin balance'margin_used': 0, # Margin_used'margin_free': 0, # Available margin'profit': 0, # Total profits'profit_rate': 0, # Profit rate'unrealised_profit': 0, # Unrealized profit } # Initialize account information, initial balance is 0 Info['ticker'][symbol] = {'last': 0, 'ask': 0, 'bid': 0} # ticker Info['order'][symbol] = { # order information'buy': {'id': 0, 'price': 0, 'amount': 0}, 'sell': {'id': 0, 'price': 0, 'amount': 0} } Info['position'][symbol] = { # position information'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0 } Info['precision'][symbol] = {} # The precision information is initialized to empty Info['position'][symbol] = { # position information'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0 } # Get precision informationdefGetPrecision(): # Get market information from exchanges# The backtest system needs to obtain market information before obtaining market information. The live trading system can ignore this.for symbol in Info['trade_symbols']: curcontract = symbol + '_' + QUOTO + '.swap' exchange.GetTicker(curcontract) exchange_info = exchange.GetMarkets() # Traverse all trading pairs in the marketfor pair, data in exchange_info.items(): symbol = pair.split('_')[0] # The format of perpetual contract trading pairs is BTC_USDT.swap# Check whether the trading pair is the currency we want to trade, whether the base currency matches, and whether it is a perpetual contractif symbol in Info['trade_symbols'] and pair.split('.')[0].endswith(Info['base_coin']) and pair.endswith('swap'): # Get the precision information of the trading pair Info['precision'][symbol] = { 'tick_size': data['TickSize'], # Price precision'amount_size': data['AmountSize'], # Quantity precision'price_precision': data['PricePrecision'], # Price decimal places precision'amount_precision': data['AmountPrecision'], # Number of decimal places of precision'min_qty': data['MinQty'], # Minimum order quantity'max_qty': data['MaxQty'], # Maximum order quantity'min_notional': data['MinNotional'], # Minimum transaction amount'ctVal': data['CtVal'] # Contract value, such as 1 contract represents 100 USD } Log(f"Initialize currency information: {symbol}, "f"Price precision: {Info['precision'][symbol]['tick_size']}, "f"Quantity precision: {Info['precision'][symbol]['amount_size']}, "f"Price decimal places precision: {Info['precision'][symbol]['price_precision']}, "f"Number of decimal places of precision: {Info['precision'][symbol]['amount_precision']}, "f"Minimum order quantity: {Info['precision'][symbol]['min_qty']}, "f"Maximum order quantity: {Info['precision'][symbol]['max_qty']}, "f"Minimum transaction amount: {Info['precision'][symbol]['min_notional']}, "f"Contract value: {Info['precision'][symbol]['ctVal']}") # Update ticker informationdefUpdateTicker(): # Record the current update timestamp Info['time']['update_ticker_time'] = time.time() * 1000# Use time.time() to get the current time stamp# Traverse the obtained market datafor symbol in Info['trade_symbols']: curcontract = symbol + '_' + QUOTO + '.swap' data = exchange.GetTicker(curcontract) ifnot data: Log("Failed to obtain ticker", GetLastError()) return# Update the bid, ask and last traded price of the ticker Info['ticker'][symbol]['ask'] = float(data['Sell']) # Ask price Info['ticker'][symbol]['bid'] = float(data['Buy']) # Bid price Info['ticker'][symbol]['last'] = float(data['Last']) # Last traded price# Update account informationdefUpdateAccount(): # Traverse all transaction currencies and update account informationfor symbol in Info['trade_symbols']: curcontract = symbol + '_' + QUOTO # Combine the currency type and the quoted currency to form a contract identifier exchange.SetCurrency(curcontract) # Set the current contract# Get account information account = exchange.GetAccount() # If the account information acquisition fails, log it and end the functionif account isNone: Log(curcontract, ": Failed to update account") return# Calculation account key information# 'Stocks': Available balance, 'FrozenStocks': Frozen balance, 'Equity': Total equity, 'UPnL': Unrealized profit and loss, Difference between U-Balance Info['account'][symbol]['margin_used'] = account['Equity'] - account['Stocks'] # Margin-used Info['account'][symbol]['margin_balance'] = account['Equity'] # Current account total equity Info['account'][symbol]['margin_free'] = account['Stocks'] # Current available balance Info['account'][symbol]['unrealised_profit'] = account['UPnL'] # Unrealized profit and loss# Read the account initial balance dictionary from global storage accDict = _G("init_balance") if accDict isNone: accDict = {} # If the global storage is empty, it is initialized to an empty dictionary# Initialize the account initial balance (set only on the first running)ifnot Info['account'][symbol]['init_balance']: # If the global storage has a record and the balance is greater than 0, use the record as the initial balanceif accDict and accDict.get(symbol) and accDict[symbol] > 0: Info['account'][symbol]['init_balance'] = round(accDict[symbol], 2) else: # Otherwise, the current margin balance is used as the initial balance Info['account'][symbol]['init_balance'] = Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last'] accDict[symbol] = Info['account'][symbol]['init_balance'] # Update global storage _G("init_balance", accDict) # Calculate account profit and profit rate Info['account'][symbol]['profit'] = round(Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last'] - Info['account'][symbol]['init_balance'], 2) # Current profit Info['account'][symbol]['profit_rate'] = round((100 * Info['account'][symbol]['profit']) / Info['account'][symbol]['init_balance'], 2) # Current profit margin (percent)# Update position informationdefUpdatePosition(): # Get perpetual contract position information# Call the interface to obtain the position information of the specified currency pos = exchange.GetPositions(Info['base_coin'] + ".swap") # Record the update time of position information (unit: milliseconds) Info['time']['update_pos_time'] = time.time() * 1000# Initialize position information# Create default position information for each trading currency position_info = {symbol: {'amount': 0, 'hold_price': 0, 'unrealised_profit': 0} for symbol in Info['trade_symbols']} # Traverse the acquired position information and update the position data of the corresponding currencyfor data in pos: # Extract part of the currency name (Symbol) as an identifier symbol = data['Symbol'].split("_")[0] # Filter out currencies that are not in the specified base currency or are not in the trading listifnot data['Symbol'].split(".")[0].endswith(Info['base_coin']) or symbol notin Info['trade_symbols']: continue# Update position information to distinguish between long and short positions (via the Type field) position_info[symbol] = { 'amount': data['Amount'] if data['Type'] == 0else -data['Amount'], # Longs are positive, shorts are negative'hold_price': data['Price'], # Position holding price'unrealised_profit': data['Profit'] # Unrealized profit and loss } # Initialize the position statistics for each currency# long: long position value, short: short position value, total: total position value, leverage: leverage ratiofor symbol in Info['trade_symbols']: Info['count'][symbol] = {'long': 0, 'short': 0, 'total': 0, 'leverage': 0} # Traverse the updated position informationfor symbol, info in position_info.items(): # Calculate position change deal_volume = abs(info['amount'] - Info['position'][symbol]['amount']) # Calculate the direction of change (positive number means increase in position, negative number means decrease in position) direction = 1if info['amount'] - Info['position'][symbol]['amount'] > 0else -1# If the position changes, record the transaction informationif deal_volume: # Get the transaction price (buy or sell) deal_price = Info['order'][symbol]['buy']['price'] if direction == 1else Info['order'][symbol]['sell']['price'] # Print position update log Log( symbol, "Position update:", round(Info['position'][symbol]['amount'], 1), " -> ", round(info['amount'], 1), ", Buy"if direction == 1else", Sell", ", transaction price:", deal_price, ", Cost price:", round(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']), ) # Update position information Info['position'][symbol]['amount'] = info['amount'] # Update position amount Info['position'][symbol]['hold_price'] = info['hold_price'] # Update position price Info['position'][symbol]['value'] = round(Info['position'][symbol]['amount'] * Info['precision'][symbol]['ctVal'], 2) # Position value Info['position'][symbol]['unrealised_profit'] = info['unrealised_profit'] # Update unrealized profit and loss# Counting the value of long and short positionsif Info['position'][symbol]['amount'] > 0: # If long, increase the long position value Info['count'][symbol]['long'] += abs(Info['position'][symbol]['value']) else: # If short, increase the short position value Info['count'][symbol]['short'] += abs(Info['position'][symbol]['value']) # Calculate the total value of the position (based on the latest price) Info['count'][symbol]['total'] = round((Info['count'][symbol]['long'] + Info['count'][symbol]['short']) / Info['ticker'][symbol]['last'], 2) # Calculate leverage (ratio of total position value to account margin) Info['count'][symbol]['leverage'] = round(Info['count'][symbol]['total'] / Info['account'][symbol]['margin_balance'], 2) # Order functiondefOrder(symbol, direction, price, amount, msg): pair = f"{symbol}_{Info['base_coin']}.swap"# Construct the trading pair name ret = exchange.CreateOrder(pair, direction, price, amount, msg) # Execute order operation# Determine whether the order is successfulif ret: Info['order'][symbol][direction]['id'] = ret # Record the order ID Info['order'][symbol][direction]['price'] = price # Record order price Log('Record order price: ', price, direction, Info['order'][symbol][direction]['price'], ) else: Log(f"{symbol} {direction} {price} {amount} Abnormal order") # Output exception information# Transaction functiondefTrade(symbol, direction, price, amount, msg): # Adjust price based on minimum price change price = round(price - (price % Info['precision'][symbol]['tick_size']), Info['precision'][symbol]['price_precision']) # Calculating the adjusted number of transactions amount = amount / Info['precision'][symbol]['ctVal'] # Calculate the actual number of contracts amount = round(amount - (amount % Info['precision'][symbol]['amount_size']), Info['precision'][symbol]['amount_precision']) # Limit the maximum number of transactionsif Info['precision'][symbol]['max_qty'] > 0: amount = min(amount, Info['precision'][symbol]['max_qty']) new_order = False# If the new price differs from the previous order price by more than 0.0001, place a new orderif Info['order'][symbol][direction]['price'] > 0andabs(price - Info['order'][symbol][direction]['price']) / price > 0.0001: Log('The order is already held and the order price has changed') new_order = True# If the transaction quantity is 0 or the current order ID is 0, cancel the orderif amount <= 0or Info['order'][symbol][direction]['id'] == 0: Log('New order generated') new_order = True# If a new order is neededif new_order: # If there is an existing order, cancel itif Info['order'][symbol][direction]['id'] != 0: exchange.CancelOrder(Info['order'][symbol][direction]['id']) Info['order'][symbol][direction]['id'] = 0 Info['order'][symbol][direction]['price'] = 0 Log('Order cancellation successful:', symbol) # If the latency of updating the position or ticker is too high, the order will not be placed.#if (time.time() * 1000 - Info['time']['update_pos_time'] > 2 * Info['interval'] * 1000 or # time.time() * 1000 - Info['time']['update_ticker_time'] > 2 * Info['interval'] * 1000):# Log('Position update time', time.time() * 1000, Info['time']['update_pos_time'], time.time() * 1000 - Info['time']['update_pos_time'])# Log('Ticker update time', time.time() * 1000, Info['time']['update_ticker_time'], time.time() * 1000 - Info['time']['update_ticker_time'])# Log('Latency is too high')# return# If the order amount or quantity is too small, the order will not be placed.if price * amount <= Info['precision'][symbol]['min_notional'] or amount < Info['precision'][symbol]['min_qty']: Log(f"{symbol} Order quantity is too small", price * amount) return# Execute order operation Log('order:', symbol) Order(symbol, direction, price, amount, msg) # Update state functiondefUpdateStatus(): # Update status time Info['time']['update_status_time'] = time.time() * 1000# Account information form table1 = { "type": "table", "title": "Account information", "cols": [ "Currency", "Initial equity", "Real-time equity", "Available balance", "Total return", "Rate of return" ], "rows": [], } # Traverse each trading pair and fill in the trading pair informationfor symbol in Info['trade_symbols']: table1['rows'].append([ symbol, # Currencyround(Info['account'][symbol]['init_balance'], 2), # Initial equityround(Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last'], 2), # Real-time equityround(Info['account'][symbol]['margin_free'] * Info['ticker'][symbol]['last'], 2), # Available balanceround(Info['account'][symbol]['profit'], 2), # Total profitsstr(Info['account'][symbol]['profit_rate']) + "%"# Yield ]) # Trading pair information table table2 = { "type": "table", "title": "Trading pair information", "cols": [ "Currency", "Direction", "Quantity", "Position price", "Position value", "Current price" ], "rows": [], } # Traverse each trading pair and fill in the trading pair informationfor symbol in Info['trade_symbols']: table2['rows'].append([ symbol, # Currency"LONG"if Info['position'][symbol]['amount'] > 0else"SHORT", # Direction Info['position'][symbol]['amount'], # Amountround(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']), # Position priceround(Info['position'][symbol]['value'], 2), # Position valueround(Info['ticker'][symbol]['last'], Info['precision'][symbol]['price_precision']) # Current price ]) # Output status log LogStatus( f"Initialization time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(Info['time']['start_time']))}\n", f"`{json.dumps(table1)}`\n" + f"`{json.dumps(table2)}`\n", f"Loop delay: {str(Info['time']['loop_delay']) + 'ms'}\n", f"Last execution time: {_D()}\n" ) totalprofit = 0for symbol in Info['trade_symbols']: totalprofit += Info['account'][symbol]['profit'] # Update account information every 10 secondsif time.time() * 1000 - Info['time']['update_profit_time'] > 10 * 1000: LogProfit(round(totalprofit, 3), '&') # Output profit log Info['time']['update_profit_time'] = time.time() * 1000# Update profit timedefMakeOrder(): # Traverse all trading pairsfor symbol in Info['trade_symbols']: availBal = Info['account'][symbol]['margin_free'] * Info['ticker'][symbol]['last'] #Amount available sell_price = Info['ticker'][symbol]['ask'] #Sell priceif availBal > ICEMONEY: #The available amount is greater than the number of iceberg orders, and the position is opened Trade(symbol, "sell", sell_price, ICEMONEY, symbol) # Execute a buy operationelif availBal > ROLLINGNUM * Info['precision'][symbol]['ctVal']: #The available profit is greater than the rolling increase in position quantity, and orders are placed gradually. Trade(symbol, "sell", sell_price, ROLLINGNUM * Info['precision'][symbol]['ctVal'], symbol) # Execute a buy operationdefOnTick(): # Update ticker information UpdateTicker() # Update account information UpdateAccount() # Update position information UpdatePosition() # Execute order operation MakeOrder() # Update status information UpdateStatus() defmain(): LogReset(0) # Log reset Log('Strategy start#0000ff') # Initialization information InitInfo() # Initialize currency information GetPrecision() # Get accuracy information exchange.SetMarginLevel(1) # Set leverage ratiowhileTrue: # Infinite loop loop_start_time = time.time() * 1000# Get the current time (milliseconds)# Check whether the last loop time and the set interval time have passedif time.time() * 1000 - Info['time']['last_loop_time'] > Info['interval'] * 1000: OnTick() # Calling the OnTick function# Update the last loop time Info['time']['last_loop_time'] = time.time() * 1000# Calculate the delay time of the current loop Info['time']['loop_delay'] = time.time() * 1000 - loop_start_time # Pause for 5 milliseconds to avoid excessive consumption of CPU resources Sleep(5)
1. Global variables and function description
The strategy is based on simple variable definitions and implements rolling position additions and status monitoring through modular functions.
- SYMBOLS : The trading currency (such as "BTC").
- QUOTO : Base currency, usually USD.
- INTERVAL : The time interval between strategy period.
- ICEMONEY : Initial order amount, used for iceberg orders.
- ROLLINGNUM : The number of positions added after rolling profits.
2. Core functional modules
The following is a brief description of each functional module:
1. The initialization function (InitInfo)
It is used to load trading currency information and initial account status.
2. GetPrecision information
Get the minimum order unit and contract value for each trading pair through the exchange API.
3. Update Ticker
Obtain the current market conditions regularly, including the best bid price, best ask price and the latest price.
4. Account and position updates (UpdateAccount, UpdatePosition)
Synchronize account balances and position information in real time, providing a basis for trading decisions.
5. Trading and order management (Order, Trade)
Unify order placement and execution functions, supporting limit order and market order operations.
6. Status monitoring (UpdateStatus)
Track the strategy operation status, including current profit and loss and unfulfilled orders.
3. Strategy order logic (MakeOrder)
The core of the strategy lies in the initial position building (iceberg position building) and rolling position increase (controlled by the rolling position increase parameter ROLLINGNUM). The following is a detailed description of the specific logic:
1. Initial position check : Verify whether the account balance is greater than the initial iceberg position amount (ICEMONEY). If the conditions are met, open positions in batches gradually to reduce excessive price slippage caused by one-time position opening.
2. Rolling position increase strategy : According to the profitability of the account (funding rate profits), increase the position reasonably, optimize the profits through rolling position increase, so as to improve the overall profitability of the strategy.
![](https://www.fmz.com/upload/asset/28e268428ea395c9a2bce.png)
According to the strategy backtest results, we can see that the strategy has obtained stable profits in multiple market periods, especially in the bull market where the funding rate is positive for a long time. Therefore, this strategy is very suitable for large fund management to a certain extent. Its low volatility and stable returns can meet the dual needs of large funds for risk control and return stability. At the same time, the strategy adopts 1x leverage to avoid the risk of liquidation caused by high leverage, further enhancing its security.
Analysis of Strategy Advantages and Disadvantages
Advantages
1. The strategy is simple and easy to execute.
The logic is clear and no complicated calculations are required. It is suitable for large fund management of hedge funds or individual investors.
2. Strong risk resistance
The 1x leverage can avoid the risk of liquidation, and the currency-based characteristics ensure that the value of the US dollar remains constant, regardless of large market fluctuations.
3. Stable profits
In the bull market, the funding rate profits is high and has strong scalability. The currency obtained can be used for other investments (such as staking).
Disadvantages
1. Strong dependence on currency and tickers
This is a flaw. When the funding rate of a currency is positive for a long time (shorts pay longs), such as BNB contracts, use DATADATA to select BNB currency-based contracts. We can see that due to the settings of the exchange, the funding rate is accumulated to a negative value. In addition, when the big cycle is in a long-term bear market (2022) and the funding rate is negative, the profits may not cover the cost of running the strategy.
![](https://www.fmz.com/upload/asset/28df18eb9e73509c6cf8f.png)
2. Insufficient strategy rigidity
The current strategy does not include dynamic adjustment logic, such as the lack of response measures (such as stop loss or take profit strategies) when switching between bull and bear markets.
3. Limited profit
Suitable for "earning effortlessly" to collect fees, unable to capture excess returns in large fluctuations, and in some cases, the yield is not as good as traditional bond funds.
Summary
The currency-based one-time short-selling fee arbitrage strategy fully utilizes the special properties of currency-based contracts and provides a low-risk solution for capital preservation and stable appreciation. However, in the face of different market stages, the strategy needs to have a certain degree of flexibility to cope with the fluctuations and potential risks of funding rates. Future optimization directions may include:
- Add dynamic management measures for switching between bull and bear markets;
- Adjust the pace of adding positions according to changes in funding rates.
But in essence, this strategy has some contradictions . The initial assumption of the strategy is that the digital currency market is in a long-term bull market, and shorting the currency-based contract can maintain a stable cash flow and obtain funding rate profits. However, if we assume that the market is in a long-term bull market, why not just choose to hoard coins (hlod) and wait for the steady rise of Bitcoin? Of course, for strategies that pursue stable returns, this strategy is still reliable. The goal of this article is mainly to introduce this design idea and provide a quantitative investment strategy framework, on which everyone can further improve and optimize it. I hope that this strategy can become an effective tool for digital currency quantitative investors.
References
How to Build a Universal Multi-Currency Trading strategy Quickly after FMZ Upgrade
Warm reminder : Investment is risky, so be cautious when entering the market. Investors are advised to fully understand the strategy logic and risks, reasonably allocate funds according to their own risk tolerance, and strictly control positions and leverage. The content of this article is for reference only and does not constitute any investment advice.
From: Quantitative Implementation of Currency-Based Short-Selling Fee Arbitrage Strategy