FMZ量化交易交易策略开发经验
admin
2023-07-31 14:26:05
0

目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意

国区邀请链接: https://www.myts3cards.com/cn/join/1837888   币种多,交易量大!

国际邀请链接:https://www.okx.com/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

FMZ量化交易平台邀请链接:https://www.fmz.com/

本文旨在描述一些策略开发的经验,以及一些技巧,让读者快速掌握交易策略开发的重点。

当您在一些策略设计中遇到类似的细节时,您可以立即想出一个合理的解决方案。

我们以 FMZ Quant 平台为例进行说明、测试和实践。

我们将使用 JavaScript 的策略编程语言

对于交易对象,我们以区块链资产市场(BTC、ETH等)为对象

数据采集​​和处理

通常,根据策略逻辑的不同,可能会使用以下不同的接口来获取行情数据,大部分策略逻辑都是由行情数据驱动的(当然,有些策略是不关心价格数据的,比如固定投资策略)。

  • GetTicker:获取实时报价。
    一般用于快速获取当前最新价格,“买入1”价格,“卖出1”价格。
  • GetDepth:获取订单簿的订单深度。
    一般用于获取订单簿深度的每一层的价格和挂单的大小。用于对冲策略、做市策略等。
  • GetTrade:获取市场的最新交易记录。
    一般用于分析短时间内的市场行为,分析市场的微观变化。通常用于高频策略和算法策略。
  • GetRecords:获取市场K线数据。通常用于趋势跟踪策略和计算指标。

容错

在设计策略时,初学者通常会忽略各种错误,直观地认为策略中每个部分的结果都是成立的。但事实并非如此,在策略程序的运行中,在请求行情数据时,会遇到各种意想不到的情况。

例如,一些市场接口返回未执行的数据:

var depth = exchange.GetDepth()

// depth.Asks[0].Price < depth.Bids[0].Price \"Selling 1\" price is lower than \"buying 1\" price, this situation cannot exist on the market.
// Because the selling price is lower than the buying price, the order must have been executed.
// depth.Bids[n].Amount = 0 Order book buying list \"nth\" layer, order quantity is 0
// depth.Asks[m].Price = 0 Order book selling list \"mth\" layer, the order price is 0

或者直接 exchange.GetDepth() 返回一个空值。

这样奇怪的情况还有很多。因此,有必要处理这些可预见的问题。这样的处理方案称为容错处理。

处理故障的正常方法是丢弃数据并重新获取它。

例如:

function main () {
     while (true) {
         onTick()
         Sleep(500)
     }
}

function GetTicker () {
     while (true) {
         var ticker = exchange.GetTicker()
         if (ticker.Sell > ticker.Buy) { // Take the example of fault-tolerant processing that detects whether the \"Selling 1\" price is less than the \"Buying 1\" price.
                                               // Exclude this error, the current function returns \"ticker\".
             Return ticker
         }
         Sleep(500)
     }
}

function onTick () {
     var ticker = GetTicker() // Make sure the \"ticker\" you get doesn\'t exist the situation that \"Selling 1\" price is less than the \"Buying 1\" price.
     // ... specific strategy logic
}

类似的方法可以用于其他可预见的容错过程。

设计原则是永远不能使用错误的逻辑来驱动策略逻辑。

K线数据的使用

K线数据采集,调用:

var r = exchange.GetRecords()

得到的K线数据是一个数组,比如这样:

[
    {\"Time\":1562068800000,\"Open\":10000.7,\"High\":10208.9,\"Low\":9942.4,\"Close\":10058.8,\"Volume\":6281.887000000001},
    {\"Time\":1562072400000,\"Open\":10058.6,\"High\":10154.4,\"Low\":9914.5,\"Close\":9990.7,\"Volume\":4322.099},
    ...
    {\"Time\":1562079600000,\"Open\":10535.1,\"High\":10654.6,\"Low\":10383.6,\"Close\":10630.7,\"Volume\":5163.484000000004}
]

可以看到每个大括号{}包含时间、开盘价、最高价、最低价、收盘价和成交量。

这是一个K线吧。一般K线数据用于计算移动平均线、MACD等指标。

将K线数据作为参数(原材料数据)传递,然后设置指标参数来计算指标数据的函数,我们称之为指标函数。

FMZ Quant量化交易平台上有很多指标功能。

例如,我们计算移动平均线指标。根据传递的K线数据的周期,我们计算相应周期的移动平均线。

比如传K线数据(一根K线柱代表一天),计算日均线,同理,如果传均指标函数的K线数据是1小时周期,那么计算指标为 1 小时移动平均线。

通常我们在计算指标时经常会忽略一个问题。如果我要计算5日均线指标,那么我们首先准备好日K线数据:

var r = exchange.GetRecords(PERIOD_D1) // Pass parameters to the \"GetRecords\" function \"PERIOD_D1\" specifies the day K line to be acquired.
                                       // Specific function using method can be seen at: https://www.fmz.com/api#GetRecords

有了每日K线数据,我们就可以计算出均线指标。如果我们要计算 5 日均线,那么我们必须将指标函数的指标参数设置为 5。

var ma = TA.MA(r, 5) // \"TA.MA()\" is the indicator function used to calculate the moving average indicator. The first parameter sets the daily K-line data r just obtained.
                             // The second parameter is set to 5. The calculated 5-day moving average is the same as the other indicators.

我们忽略了一个潜在的问题。如果 K 线数据中的 K 线柱数少于 5 条,如何计算出有效的 5 日均线?

答案是你无能为力。

因为移动平均线指标是一定数量K线柱的收盘价的平均值。

6e9899bf1c18d37b97596e9899bf1c18d37b9759

因此,在使用K线数据和指标函数计算指标数据之前,需要确定K线数据中K线柱的数量是否满足指标计算的条件(指标参数)。

所以在计算 5 日移动平均线之前,你必须先检查一下。完整代码如下:

function CalcMA () {
     var r = _C(exchange.GetRecords, PERIOD_D1) // _C() is a fault-tolerant function, the purpose is to avoid r being null, you can get more information at: https://www.fmz.com/api#_C
     if (r.length > 5) {
         Return TA.MA(r, 5) // Calculate the moving average data with the moving average indicator function \"TA.MA\", return it as a function return value.
     }

     Return false
}

function main () {
     var ma = CalcMA()
     Log(ma)
}

6e5029f18c426962e7816e5029f18c426962e781

回测展示:

[null,null,null,null,4228.7,4402.9400000000005, ... ]

您可以看到计算出的 5 天移动平均线指标。前四个为空,因为K线条数少于5,无法计算平均值。当你到达第5个K线柱时,你可以计算它。

判断K线更新的技巧

我们在写策略的时候,经常会有这样的场景,比如策略需要在每个K线周期完成的时候处理一些操作,或者打印一些日志。

我们如何实现这些功能?对于没有编程经验的初学者来说,可能是个比较麻烦的问题。在这里,我们为您提供解决方案。

如何判断一个K线柱周期就完成了。我们可以从K线数据中的时间属性入手。每次拿到K线数据,我们都会判断这个K线数据的最后一个K线柱的时间属性是否发生变化。如果变了,说明有新的K线柱生成(证明新生成的K线柱的上一个K线柱周期已经完成),如果没有变化,说明没有新的K线柱-line bar 生成(当前最后一个 K 线 bar 周期尚未完成)。

所以我们需要一个变量来记录K线数据的最后一个K线柱的时间。

var r = exchange.GetRecords()
var lastTime = r[r.length - 1].Time // \"lastTime\" used to record the last K-line bar time.

在实践中,通常是这样的:

function main () {
     var lastTime = 0
     while (true) {
         var r = _C(exchange.GetRecords)
         if (r[r.length - 1].Time != lastTime) {
             Log (\"New K-line bar generated\")
             lastTime = r[r.length - 1].Time // Be sure to update \"lastTime\", this is crucial.

             // ... other processing logic
             // ...
         }

         Sleep(500)
     }
}

6e4b63a61104fbb1cf426e5029f18c426962e781

可以看到在回测中,K线周期设置为每天(exchange.GetRecords函数调用时未指定参数,根据回测设置的K线周期为默认参数)。每当新的 K 线柱出现时,它都会打印一个日志。

数值计算

  • 计算访问交易所界面所花费的时间

如果您想对策略访问交易所界面所需的时间进行一定的显示或控制,您可以使用以下代码:

function main () {
     while (true) {
         var beginTime = new Date().getTime()
         var ticker = exchange.GetTicker()
         var endTime = new Date().getTime()

         LogStatus(_D(), \"GetTicker() function time-consuming:\", endTime - beginTime, \"millisecond\")
         Sleep(1000)
     }
}

简单来说就是调用GetTicker函数后记录的时间戳减去调用前的时间戳,计算出所经历的毫秒数,也就是GetTicker函数从执行到返回所用的时间。

  • 使用“Math.min / Math.max”限制数值的上下限

例如,在下达卖单的过程中,卖单的金额不得大于账户中的币数。
因为如果它大于账户中可用的硬币数量,订单将导致错误。

我们这样控制它:

例如,我们计划卖空 0.2 个硬币。

var planAmount = 0.2
var account = _C(exchange.GetAccount)
var amount = Math.min(account.Stocks, planAmount)

这样可以确保下达的订单数量不会超过账户中可用的硬币数量。

同理,Math.max用于保证某个值的下限。

  • 这通常适用于什么样的场景?

一般情况下,正常交易所对某些交易对有最低发送订单限制。如果低于最低金额,订单将被拒绝。这也会导致程序失败。

假设BTC通常最小下单数量为0.01。

交易策略有时会导致小于 0.01 的订单数量,因此我们可以使用Math.max来确保最小订单数量。

  • 订单数量、价格精准控制

可以使用_N()函数或SetPrecision函数来控制精度。

SetPrecision()功能只需设置一次,订单数量和价格值的小数位数在系统中自动截断。

功能是对_N()某个值进行小数点截断(精度控制)。

例如:

var pi = _N(3.141592653, 2)
Log(pi)

pi的值被小数位截去,保留2位小数,即:3.14

有关详细信息,请参阅 API 文档。

一些逻辑设置

  • 定时,在一定时间内执行一些操作

可以利用这样的机制,利用时间戳检测的方法,确定当前时间戳减去上一次执行定时任务的时间戳,实时计算经过的时间。当经过的时间超过某个设置的时间长度时。之后,执行新的操作。

例如,用于固定投资策略。

var lastActTime = 0
var waitTime = 1000 * 60 * 60 * 12 // number of milliseconds a day
function main () {
     while (true) {
         var nowTime = new Date().getTime()
         if (nowTime - lastActTime > waitTime) {
             Log (\"Execution Fixed\")
             // ... specific fixed investment operation, buying operation.


             lastActTime = nowTime
         }

         Sleep(500)
     }
}

这是一个简单的例子。

  • 设计策略的自动恢复机制

使用FMZ量化_G()功能,退出保存功能,方便设计退出保存进度,重启自动恢复状态的策略。

var hold = {
     Price : 0,
     Amount : 0,
}

function main () {
     if (_G(\"hold\")) {
         var ret = _G(\"hold\")
         hold.price = ret.price
         hold.amount = ret.amount
         Log(\"restore hold:\", hold)
     }

     var count = 1
     while (true) {
         // ... strategy logic
         // ... In the strategy operation, it is possible that when opening a position, then assign the position price of the open position to \"hold.price\", and the amount of open positions is assigned to \"hold.amount\" to record the position information.

         hold.price = count++ // simulate some values
         hold.amount = count/10 // Simulate some values

         Sleep(500)
     }
}

function onexit () { // Click the stop button on the robot to trigger the execution of this function. After the execution, the robot stops.
     _G(\"hold\", hold)
     Log(\"save hold:\", JSON.stringify(hold))
}

6e21184fccbecf239f636e5029f18c426962e781

可以看出,hold每次机器人停止时都会保存对象中的数据。每次重新启动数据时,读取数据并将其值hold恢复到停止前的状态。

当然,以上只是一个简单的例子。如果在实际交易策略中使用,应根据策略中需要恢复的关键数据(一般为账户信息、持仓、盈利值、交易方向等)进行设计。

此外,您还可以设置一些其他条件来恢复。

这些是制定交易策略的一些技巧,希望对初学者有所帮助!

动手实践训练是提高自己最快的方法!祝大家好运。

FMZ量化交易平台邀请链接:https://www.fmz.com/

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意,邀请链接:https://www.myts3cards.com/cn/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!。

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

买好币上币库:https://www.kucoin.com/r/1f7w3

火必所有用户现在可用了,但是要重新注册账号火币:https://www.huobi.com

全球最大交易所币安,

国区邀请链接:https://accounts.suitechsui.mobi/zh-CN/register?ref=16003031 支持86手机号码,网页直接注册。

相关内容

热门资讯

Windows 11 和 10... Windows 11/10 文件夹属性中缺少共享选项卡 – 已修复 1.检查共享选项卡是否可用 右键...
Radmin VPN Wind... Radmin VPN 是一款免费且用户友好的软件,旨在牢固地连接计算机以创建一个有凝聚力的虚拟专用网...
如何修复 Steam 内容文件... Steam 内容文件锁定是当您的 Steam 文件无法自行更新时出现的错误。解决此问题的最有效方法之...
在 Windows 11 中打... 什么是链路状态电源管理? 您可以在系统控制面板的电源选项中看到链接状态电源管理。它是 PCI Exp...
Hive OS LOLMine... 目前不清退的交易所推荐: 1、全球第二大交易所OKX欧意 国区邀请链接: https://www.m...
事件 ID 7034:如何通过... 点击进入:ChatGPT工具插件导航大全 服务控制管理器 (SCM) 负责管理系统上运行的服务的活动...
iPhone 屏幕上有亮绿色斑... iPhone 是市场上最稳定的智能手机之一,这主要归功于专为它们设计的 iOS 操作系统。然而,他们...
balenaEtcher烧录后... balenaEtcher烧录后u盘或者内存卡无法识别不能使用的解决方法想要恢复原来的方法,使用win...
在 iCloud 上关闭“查找... 如果您是 Apple 的长期用户,您肯定会遇到过 Find My 应用程序,它本机安装在 iPhon...
统信UOS每次开机后不直接进入... 统信UOS每次开机后不直接进入系统而是进入到recovery模式 按方向上键选择UOS 20 SP1...