0bps

Strategy vault / Other

Value 0418

Set an investment amount, such as 10,000 yuan. Set a value ratio between cash and Bitcoin, such as 50:50. According to the current price, always maintain the value ratio between cash and Bitcoin. For example, if the…

JavaScriptOther
Author
kakababy
Complexity
Intermediate · 222 lines
Parameters
7

Set an investment amount, such as 10,000 yuan. Set a value ratio between cash and Bitcoin, such as 50:50. According to the current price, always maintain the value ratio between cash and Bitcoin.

For example, if the initial capital is 10,000 yuan, the ratio of capital to Bitcoin is set to 30:70, and 7,000 yuan of Bitcoin is purchased in the first transaction (assuming the currency price is 1,000 yuan, and 7 coins are purchased), the remaining capital is 3,000 yuan, and the maintenance ratio is30:70.

In the next trading cycle, assuming that the currency price changes to 1,500 yuan, the total value becomes 1,5007 + 3,000 = 13,500. The funds in hand should be kept at 13,500 0.7, the remaining Bitcoins in hand are 7-0.7=6.3, and the currency value is 6.31500 = 9450. The ratio of funds to Bitcoin value is4050:9450 = 30:70.

Similarly, when the coin price falls, buy to maintain the proportion.

Parameters

NameDefaultWhat it controls
UseAccounttrueUse all funds in the account
InitMoney10000Initial capital amount.
InitStock5Initial number of coins.
StockRatio0.418Coin value as a proportion of total value
InvestIntervaltrueInvestment interval.
ErrorInterval300Error retry interval.
SlidePrice0.01slippage

Source JavaScript

var initAccount = null;
var initPrice = 0;
var stockHold = 0;
var moneyHold = 0;
var lastOrderID = null;
var prices = [];

function AdjustFloat(v) {
    return Math.floor(v * 1000) / 1000;
}

function GetAccount() {
    var account = null;
    while (!(account = exchange.GetAccount())) {
        Log('Get Account Error');
        Sleep(ErrorInterval);
    }
    return account;
}

function GetCurrentPrice() {
    var ticker = null;
    while (!(ticker = exchange.GetTicker())) {
        Log('Get Ticker Error');
        Sleep(ErrorInterval);
    }
    return AdjustFloat(ticker.Last);
}

function GetOrders() {
    var orders = null;
    while (!(orders = exchange.GetOrders())) {
        Log('Get Orders Error');
        Sleep(ErrorInterval);
    }
    return orders;
}

function CancelPendingOrders() {
    while (true) {
        var orders = GetOrders();
        if (orders.length === 0) {
            return;
        }

        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id);
            if (i < (orders.length - 1)) {
                Sleep(ErrorInterval);
            }
        }
    }
}

function GetStatus() {
    var price = GetCurrentPrice();
    var initStockValue = InitStock + InitMoney / initPrice;
    var initMoneyValue = InitMoney + InitStock * initPrice;
    var stockValueNow = stockHold + moneyHold / price;
    var moneyValueNow = stockHold * price + moneyHold;
    var stockEarned = stockValueNow - initStockValue;
    var moneyEarned = moneyValueNow - initMoneyValue;
    var averagePrice = 0;
    var alpha = (stockHold - InitStock) * (price - initPrice);
    var beta = moneyEarned - alpha;

    var sum = 0;
    if (prices.length > 0) {
        for (var i = prices.length - 1; i >= 0; i--) {
            sum += prices[i];
        }
        averagePrice = sum / prices.length;
    }

    var logString = 'Stock Holding:' + AdjustFloat(stockHold) + '\n';
    logString += 'Money Holding:' + AdjustFloat(moneyHold) + '\n';
    logString += 'Stock Earned:' + AdjustFloat(stockEarned) + '\n';
    logString += 'Money Earned:' + AdjustFloat(moneyEarned) + '\n';
    logString += 'History Average price:' + averagePrice + '\n';
    logString += 'Current Price:' + price + '\n';
    logString += 'Alpha:' + alpha + '\n';
    logString += 'Beta:' + beta;

    LogProfit(moneyEarned);

    return logString;
}

function CaculateHoldings() {
    CancelPendingOrders();

    if (lastOrderID) {
        var order = exchange.GetOrder(lastOrderID);
        Log('last order:', order);
        if (order.Status === ORDER_STATE_CLOSED) {
            if (order.Type === ORDER_TYPE_BUY) { //Buy
                stockHold += order.DealAmount;
                moneyHold -= order.DealAmount * order.Price;
                Log("Order Buy. stockHold +=:", order.DealAmount, ',Money -=:', order.DealAmount * order.Price);
            } else { //Sell
                stockHold -= order.DealAmount;
                moneyHold += order.DealAmount * order.Price;
                Log("Order Sell. stockHold -=:", order.DealAmount, ',Money +=:', order.DealAmount * order.Price);
            }
        }
    }
}

function OnTick() {
    var currentPrice = GetCurrentPrice();
    prices.push(currentPrice);
    //Log('History prices:',prices);

    var stockValue = 0;
    var totalValue = 0;
    var ratio = 0;

    stockValue = stockHold * currentPrice;
    totalValue = stockValue + moneyHold;

    ratio = stockValue / totalValue;
    Log('Current Price:', currentPrice);
    Log('stockHold:', stockHold);
    Log('moneyHold:', moneyHold);
    Log('stockValue:', stockValue);
    Log('Current Ratio:', ratio);

    if (ratio > StockRatio) { //Sell
        Log('Current ratio > StockRatio');
        var sellAmt = (stockValue - totalValue * StockRatio) / (currentPrice - SlidePrice);
        lastOrderID = exchange.Sell(currentPrice - SlidePrice, sellAmt);
    } else { //Buy
        Log('Current ratio < StockRatio');
        var buyAmt = (totalValue * StockRatio - stockValue) / (currentPrice + SlidePrice);
        lastOrderID = exchange.Buy(currentPrice + SlidePrice, buyAmt);
    }
    Log('Order ID:', lastOrderID);
    CaculateHoldings();

}

function main() {
    if (InitStock < 0) {
        Log('Stock less than zero.');
        return;
    }

    if (InitMoney < 0) {
        Log('Money less than zero.');
    }

    //if(InvestInterval < 0){
    //    Log('InvestInterval less than zero.');
    //}

    if (ErrorInterval < 0) {
        Log('ErrorInterval less than zero.');
    }

    if (StockRatio < 0 || StockRatio > 1) {
        Log('StockRatio should be a number from 0 to 1.');
    }

    EnableLogLocal(true);
    SetFailover(true);
    exchange.IO("websocket");

    Log(exchange.GetName(), exchange.GetCurrency());

    initAccount = _G('InitAccount');
    if (initAccount === null) {
        initAccount = GetAccount();
        _G('InitAccount', initAccount);
    }
    Log('InitAccount', initAccount);

    initPrice = _G('InitPrice');
    if (initPrice === null) {
        initPrice = GetCurrentPrice();
        _G('InitPrice', initPrice);
    }
    Log('InitPrice', initPrice);

    if (UseAccount) {
        InitMoney = initAccount.Balance + initAccount.FrozenBalance;
        InitStock = initAccount.Stocks + initAccount.FrozenStocks;
    }
    Log('InitMoney:', InitMoney);
    Log('InitStock:', InitStock);

    stockHold = _G('StockHold');
    if (stockHold === null) {
        stockHold = InitStock;
        Log('Set Stock Hold', stockHold);
    }

    moneyHold = _G('MoneyHold');
    if (moneyHold === null) {
        moneyHold = InitMoney;
        Log('Set Money Hold', moneyHold);
    }

    if (_G('Prices') !== null) {
        prices = _G('Prices');
    }

    while (true) {
        OnTick();
        LogStatus(GetStatus());
        Sleep(InvestInterval * 1000 * 60);
    }
}

function onexit() {
    _G('StockHold', stockHold);
    _G('MoneyHold', moneyHold);
    //_G('Prices',prices);
    Log('Set Stock Hold', stockHold);
    Log('Set Money Hold', moneyHold);
    Log('Set prices:', prices);
    Log('Robot Stopped!#ff0000@');
}

Published by kakababy on the FMZ strategy square · last modified 2016-02-14. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Value-0418.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open