Firetron’s Hedged DCA Dipper

1 588 Views 3 Comments 4 months ago
  • Runs a long and a short each doing dollar cost averaging strategy.
    Expands positions on an interval and exits whenever there is a profit.
    Only expands a position when its profit is less than a trigger.

    Custom Command Dependencies:
    Firetron’s CurrentVsEntry
    Firetron’s FormatRoundedPercent
    Firetron’s FormatRoundedQuoteCurrency
    Firetron’s ReportMaxRiskPoint
    Firetron’s ReportOpenPositions
    Firetron’s TrueOnInterval

    • This topic was modified 3 months, 2 weeks ago by Firetron. Reason: Added missing period at end of sentence
    • This topic was modified 3 months, 2 weeks ago by Firetron. Reason: Added hyperlinks to commands
    • This topic was modified 1 month, 1 week ago by Derrick.
    • This topic was modified 1 month, 1 week ago by Firetron. Reason: Added option for ROI based profit trigger
    • This topic was modified 1 month ago by Team HaasScripts.
    HaasScript Code
    --  ============================================================================
    --    Firetron's Hedged DCA Dipper
    --
    --    Runs a long and a short each doing dollar cost averaging strategy.
    --    Expands positions on an interval and exits whenever there is a profit.
    --    Only expands a position when its profit is less than a trigger.
    --
    --    Custom Command Dependencies:
    --    Firetron's CurrentVsEntry
    --    Firetron's FormatRoundedPercent
    --    Firetron's FormatRoundedQuoteCurrency
    --    Firetron's ReportMaxRiskPoint
    --    Firetron's ReportOpenPositions
    --    Firetron's TrueOnInterval
    --
    --    Discord:  @FiretronP75
    --    BTC Tips: 14WLDZsrhshcP6qvBarKW8ABACv3iUXEro
    --    ETH Tips: 0xfaaac99fbf11f8f4abc4b3bf079cb2c7a43b5f87
    --  ============================================================================
    
    --  ========================================================
    --    Configuration
    --  ========================================================
    
    EnableHighSpeedUpdates()
    HideOrderSettings()
    HideTradeAmountSettings()
    
    --  ========================================================
    --    Variables
    --  ========================================================
    
    local logHRule = '------------------------------------------------------------';
    
    --  ------------------------------------
    --    Enumerations
    --  ------------------------------------
    
    local booleanOption = {
      no  = 'No',
      yes = 'Yes',
    }
    
    local ProfitType = {
      marketChange = 'Market Change',
      positionROI  = 'Position ROI',
    }
    
    --  ------------------------------------
    --    Positions
    --  ------------------------------------
    
    local longPositionId  = Load('longPositionId',  '')
    local shortPositionId = Load('shortPositionId', '')
    
    --  ========================================================
    --    Inputs
    --  ========================================================
    
    local group   = ''
    local label   = ''
    local tooltip = ''
    
    --  ------------------------------------
    --    Testing
    --  ------------------------------------
    
    local fee               = Fee()
    local isVerbose         = booleanOption.no
    local verbosityInterval = 60
    
    group = ' Testing'
    
    label   = 'Fee Percentage'
    tooltip = 'For backtests and simulated trading.'
    fee     = Input(label, fee, tooltip, group)
    
    label     = 'Verbose Logging'
    tooltip   = 'Log extra details. Will run slower.'
    isVerbose = InputOptions(label, isVerbose, booleanOption, tooltip, group)
    
    label             = 'Verbose Logging Interval'
    tooltip           = 'Time between verbose logging.'
    verbosityInterval = InputInterval(label, verbosityInterval, tooltip, group)
    
    --  ------------------------------------
    --    Main
    --  ------------------------------------
    
    local expandBy         =  MinimumTradeAmount()
    local expansionTrigger = -5
    local interval         =  360
    local profitTrigger    =  5
    local profitType    = ProfitType.positionROI
    
    group = 'Main'
    
    label    = 'Expand By'
    tooltip  = 'Number of contracts to expand by each interval.'
    expandBy = Input(label, expandBy, tooltip, group)
    
    label            = 'Expansion Trigger'
    tooltip          = 'Only expand when percent profit is below this. Ignored if set higher than Profit Trigger.'
    expansionTrigger = Input(label, expansionTrigger, tooltip, group)
    
    label    = 'Interval'
    tooltip  = 'Time between position expansions.'
    interval = InputInterval(label, interval, tooltip, group)
    
    label         = 'Profit Trigger'
    tooltip       = 'Percent profit that will trigger an exit.'
    profitTrigger = Input(label, profitTrigger, tooltip, group)
    
    label      = 'Profit Type'
    tooltip    = 'Calculate profit using either position ROI or simple change in market price. In other words, you are specifying whether or not your profit trigger is taking leverage into account or not.'
    profitType = InputOptions(label, profitType, ProfitType, tooltip, group)
    
    --  ========================================================
    --    Functions
    --  ========================================================
    
    --  ------------------------------------
    --    Debug
    --  ------------------------------------
    
    function GetDebugInfo ()
    
      if isVerbose == booleanOption.no then
        return {
          isVerbose         = false,
          isVerboseInterval = false,
        }
      end
    
      local currentPrice = CurrentPrice()
    
      if not CC_TrueOnInterval(verbosityInterval) then
        return {
          baseCurrency      = BaseCurrency(),
          currentAsk        = CC_FormatRoundedQuoteCurrency(currentPrice.ask),
          currentBid        = CC_FormatRoundedQuoteCurrency(currentPrice.bid),
          isVerbose         = true,
          isVerboseInterval = false,
        }
      end
    
      return {
        baseCurrency      = BaseCurrency(),
        currentAsk        = CC_FormatRoundedQuoteCurrency(currentPrice.ask),
        currentBid        = CC_FormatRoundedQuoteCurrency(currentPrice.bid),
        isVerbose         = true,
        isVerboseInterval = true,
      }
    
    end
    
    --  ----------------
    
    function ResetSafeLog ()
    
      Save('lastLog', '')
    
    end
    
    --  ----------------
    
    function SafeLog (text)
    
      if text == Load('lastLog', '') then return end
    
      Log(text)
      Save('lastLog', text)
    
    end
    
    --  ----------------
    
    function SafeLogWarning (text)
    
      if text == Load('lastLog', '') then return end
    
      LogWarning(text)
      Save('lastLog', text)
    
    end
    
    --  ------------------------------------
    --    Exiting
    --  ------------------------------------
    
    function Exit ()
    
      local debugInfo = GetDebugInfo()
    
      ExitCheckLong( debugInfo)
      ExitCheckShort(debugInfo)
    
    end
    
    --  ----------------
    
    function ExitCheckLong (debugInfo)
    
      local longProfit
    
      if longPositionId != '' then
        longProfit = profitType == ProfitType.positionROI and GetPositionROI(longPositionId) or CC_CurrentVsEntry(longPositionId)
      end
    
      if longPositionId == '' then
        if debugInfo.isVerboseInterval then
          SafeLog(logHRule)
          SafeLog('No long position.')
        end
      elseif longProfit >= profitTrigger then
        if debugInfo.isVerbose then
          SafeLog(logHRule)
        end
        ExitLong()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif debugInfo.isVerboseInterval then
        SafeLog(logHRule)
        SafeLog('Not exiting long.')
        SafeLog('Long profit is '..CC_FormatRoundedPercent(longProfit))
        SafeLog(debugInfo.baseCurrency..' bid is @ '..debugInfo.currentBid)
      end
    
    end
    
    --  ----------------
    
    function ExitCheckShort (debugInfo)
    
      local shortProfit
    
      if shortPositionId != '' then
        shortProfit = profitType == ProfitType.positionROI and GetPositionROI(shortPositionId) or CC_CurrentVsEntry(shortPositionId)
      end
    
      if shortPositionId == '' then
        if debugInfo.isVerboseInterval then
          SafeLog(logHRule)
          SafeLog('No short position.')
        end
      elseif shortProfit >= profitTrigger then
        if debugInfo.isVerbose then
          SafeLog(logHRule)
        end
        ExitShort()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif debugInfo.isVerboseInterval then
        SafeLog(logHRule)
        SafeLog('Not exiting short.')
        SafeLog('Short profit is '..CC_FormatRoundedPercent(shortProfit))
        SafeLog(debugInfo.baseCurrency..' ask is @ '..debugInfo.currentAsk)
      end
    
    end
    
    --  ----------------
    
    function ExitLong ()
    
      local parameters = {
        positionId = longPositionId,
        type = MarketOrderType,
      }
    
      SafeLogWarning('Taking profit on long.')
      PlaceExitPositionOrder(parameters);
      Save('longPositionId', '')
    
    end
    
    --  ----------------
    
    function ExitShort ()
    
      local parameters = {
        positionId = shortPositionId,
        type = MarketOrderType,
      }
    
      SafeLogWarning('Taking profit on short.')
      PlaceExitPositionOrder(parameters);
      Save('shortPositionId', '')
    
    end
    
    --  ------------------------------------
    --    Going
    --  ------------------------------------
    
    function Go ()
    
      local debugInfo = GetDebugInfo()
    
      if debugInfo.isVerbose then
        SafeLog(logHRule)
      end
    
      GoCheckLong( debugInfo)
      GoCheckShort(debugInfo)
    
    end
    
    --  ----------------
    
    function GoCheckLong (debugInfo)
    
      local longProfit
    
      if longPositionId != '' then
        longProfit = CC_CurrentVsEntry(longPositionId)
      end
    
      if longPositionId == '' then
        longPositionId = NewGuid()
        Save('longPositionId', longPositionId)
        GoLong()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif longProfit <= expansionTrigger then
        GoLong()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif debugInfo.isVerboseInterval then
        SafeLog('Not going long.')
        SafeLog('Long profit is '..CC_FormatRoundedPercent(longProfit))
        SafeLog(debugInfo.baseCurrency..' bid is @ '..debugInfo.currentBid)
      end
    
    end
    
    --  ----------------
    
    function GoCheckShort (debugInfo)
    
      local shortProfit
    
      if shortPositionId != '' then
        shortProfit = CC_CurrentVsEntry(shortPositionId)
      end
    
      if shortPositionId == '' then
        shortPositionId = NewGuid()
        Save('shortPositionId', shortPositionId)
        GoShort()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif shortProfit <= expansionTrigger then
        GoShort()
        if debugInfo.isVerbose then ResetSafeLog() end
      elseif debugInfo.isVerboseInterval then
        SafeLog('Not going short.')
        SafeLog('Short profit is '..CC_FormatRoundedPercent(shortProfit))
        SafeLog(debugInfo.baseCurrency..' ask is @ '..debugInfo.currentAsk)
      end
    
    end
    
    --  ----------------
    
    function GoLong ()
    
      local parameters = {
        type = MarketOrderType,
        positionId = longPositionId,
      }
    
      PlaceGoLongOrder(1, expandBy, parameters)
    
    end
    
    --  ----------------
    
    function GoShort ()
    
      local parameters = {
        type = MarketOrderType,
        positionId = shortPositionId,
      }
    
      PlaceGoShortOrder(1, expandBy, parameters)
    
    end
    
    --  ========================================================
    --    Execution
    --  ========================================================
    
    SetFee(fee)
    
    CC_ReportOpenPositions()
    CC_ReportMaxRiskPoint()
    
    Exit()
    OptimizedForInterval(interval, Go)
    • #1157
      Firetron
      Basic
      Up
      2
      Down

      Named “Dipper” because if you set the Expansion Trigger to 0% or less then it only “buys the dips”.

    • #1165
      Firetron
      Basic
      Up
      2
      Down

      Decent setting for BTC:

      Expand By: 0.01
      Expansion Trigger: -5
      Interval: 5 minutes
      Profit Trigger: 2
      
    • #1175
      Firetron
      Basic
      Up
      1
      Down

      Better setting for BTC:

      Expand By: 0.01
      Expansion Trigger: -5
      Interval: 4 hour
      Profit Trigger: 5
      
Login or Register to Comment

Unlock your crypto trading potential

Create a free account and enjoy everything we have to offer.

Join for Free