Firetron’s Hedged DCA Dipper

1 334 Views 3 Comments 2 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 1 month, 3 weeks ago by Firetron. Reason: Added missing period at end of sentence
    • This topic was modified 1 month, 3 weeks ago by Firetron. Reason: Added hyperlinks to commands
    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',
    }
    
    --  ------------------------------------
    --    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
    
    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)
    
    --  ========================================================
    --    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 = 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 = 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