/*==========================================================================*/ SCSFExport scsf_RelativeVolume(SCStudyInterfaceRef sc) { SCSubgraphRef RelativeVolume = sc.Subgraph[0]; SCSubgraphRef CumulativeVolumeRatio = sc.Subgraph[1]; SCSubgraphRef HundredLine = sc.Subgraph[2]; SCSubgraphRef AverageVolumeSubgraph = sc.Subgraph[3]; SCSubgraphRef AverageCumulativeVolumeSubgraph = sc.Subgraph[4]; SCFloatArrayRef CumulativeVolume = CumulativeVolumeRatio.Arrays[0]; SCFloatArrayRef AverageVolume = CumulativeVolumeRatio.Arrays[1]; SCFloatArrayRef AverageCumulativeVolume = CumulativeVolumeRatio.Arrays[2]; SCFloatArrayRef MedianVolumeTemp = CumulativeVolumeRatio.Arrays[3]; SCFloatArrayRef MedianCumulativeVolumeTemp = CumulativeVolumeRatio.Arrays[4]; SCFloatArrayRef MedianTemp = CumulativeVolumeRatio.Arrays[5]; SCInputRef Period = sc.Input[0]; SCInputRef AccumulateType = sc.Input[1]; SCInputRef DaySessionOnly = sc.Input[2]; SCInputRef VolumeAvergeType = sc.Input[3]; SCInputRef HighPercentThresh = sc.Input[8]; SCInputRef HighThreshColor = sc.Input[9]; SCInputRef LowPercentThresh = sc.Input[10]; SCInputRef LowThreshColor = sc.Input[11]; SCInputRef ExcludeDateList = sc.Input[12]; SCInputRef Version = sc.Input[13]; const static int CURRENT_VERSION = 2; if (sc.SetDefaults) { sc.GraphName = "Relative Volume"; sc.GraphRegion = 1; sc.ValueFormat = 1; sc.DrawZeros = 0; sc.AutoLoop = 1; RelativeVolume.Name = "Relative Volume"; RelativeVolume.DrawStyle = DRAWSTYLE_BAR; RelativeVolume.PrimaryColor = RGB(0, 128, 192); RelativeVolume.LineWidth = 3; CumulativeVolumeRatio.Name = "Cumulative Volume Ratio"; CumulativeVolumeRatio.DrawStyle = DRAWSTYLE_LINE_SKIPZEROS; CumulativeVolumeRatio.PrimaryColor = RGB(255, 128, 0); CumulativeVolumeRatio.LineWidth = 2; AverageVolumeSubgraph.Name = "Average Volume"; AverageVolumeSubgraph.DrawStyle = DRAWSTYLE_IGNORE; AverageVolumeSubgraph.PrimaryColor = RGB(0, 128, 255); AverageVolumeSubgraph.LineWidth = 1; AverageCumulativeVolumeSubgraph.Name = "Average Cumulative Volume"; AverageCumulativeVolumeSubgraph.DrawStyle = DRAWSTYLE_IGNORE; AverageCumulativeVolumeSubgraph.PrimaryColor = COLOR_GRAY; AverageCumulativeVolumeSubgraph.LineWidth = 1; HundredLine.Name = "100%"; HundredLine.DrawStyle = DRAWSTYLE_LINE; HundredLine.LineStyle = LINESTYLE_DOT; HundredLine.PrimaryColor = COLOR_GRAY; Period.Name = "Period - Days To Include"; Period.SetInt(5); Period.SetIntLimits(1, INT_MAX); AccumulateType.Name = "Accumulation Type"; AccumulateType.SetCustomInputStrings("All Days;Day Of Week"); AccumulateType.SetCustomInputIndex(0); DaySessionOnly.Name = "Day Session Only"; DaySessionOnly.SetYesNo(1); VolumeAvergeType.Name = "Volume Average Type"; VolumeAvergeType.SetCustomInputStrings("Average Volume;Median Volume"); VolumeAvergeType.SetCustomInputIndex(0); HighPercentThresh.Name = "High Percent Threshold (0-disabled, 120->120%)"; HighPercentThresh.SetFloat(120); HighPercentThresh.SetFloatLimits(0, FLT_MAX); HighThreshColor.Name = "High Threshold Color"; HighThreshColor.SetColor(COLOR_GREEN); LowPercentThresh.Name = "Low Percent Threshold (0-disabled, 80->80%)"; LowPercentThresh.SetFloat(80); LowPercentThresh.SetFloatLimits(0, FLT_MAX); LowThreshColor.Name = "Low Threshold Color"; LowThreshColor.SetColor(COLOR_RED); ExcludeDateList.Name = "Exclude Dates (comma separated YYYYMMDD)"; ExcludeDateList.SetString(""); Version.SetInt(CURRENT_VERSION); return; } if (Version.GetInt() < 2) { VolumeAvergeType.SetCustomInputIndex(0); AverageVolumeSubgraph.DrawStyle = DRAWSTYLE_IGNORE; AverageCumulativeVolumeSubgraph.DrawStyle = DRAWSTYLE_IGNORE; Version.SetInt(2); } // References to persistent variables int& LastIndex = sc.GetPersistentInt(1); int& NumExcludeDates = sc.GetPersistentInt(4); int* ExcludeDates = &sc.PersistVars->Integers[0]; int* p_LastPriorIndexes = (int *)sc.GetPersistentPointer(1); SCDateTime BarDateTime = sc.BaseDateTimeIn[sc.Index]; int BarTime = BarDateTime.GetTime(); HundredLine[sc.Index] = 100.0f; if (sc.LastCallToFunction) { if (p_LastPriorIndexes != NULL) { sc.FreeMemory(p_LastPriorIndexes); sc.SetPersistentPointer(1, NULL); } } if (p_LastPriorIndexes == NULL) { p_LastPriorIndexes = (int *)sc.AllocateMemory(Period.GetInt() * sizeof(int)); if (p_LastPriorIndexes != NULL) sc.SetPersistentPointer(1, p_LastPriorIndexes); else return; } if (sc.Index == 0) { LastIndex = 0; for (int i = 0; i < Period.GetInt(); i++) { p_LastPriorIndexes[i] = -1; } NumExcludeDates = 0; for (int TokenIndex = 0; TokenIndex<64; ++TokenIndex) ExcludeDates[TokenIndex] = 0; SCString ExcludeString = ExcludeDateList.GetString(); std::vector Tokens; ExcludeString.Tokenize(",", Tokens); for (unsigned int TokenIndex = 0; TokenIndex < Tokens.size() && NumExcludeDates<64; ++TokenIndex) { int DateInt = atoi(Tokens[TokenIndex]); if (DateInt != 0) { ExcludeDates[NumExcludeDates] = YMD_DATE(DateInt / 10000, (DateInt / 100) % 100, DateInt % 100); ++NumExcludeDates; } } CumulativeVolume[sc.Index] = sc.Volume[sc.Index]; return; } bool NoPlot = DaySessionOnly.GetYesNo() && !sc.IsDateTimeInDaySession(BarDateTime); const int TradeDate = sc.GetTradingDayDate(BarDateTime); const int PriorTradeDate = sc.GetTradingDayDate(sc.BaseDateTimeIn[sc.Index - 1]); // track cumulative volume if (NoPlot) CumulativeVolume[sc.Index] = 0; else if (TradeDate != PriorTradeDate) CumulativeVolume[sc.Index] = sc.Volume[sc.Index]; else CumulativeVolume[sc.Index] = CumulativeVolume[sc.Index - 1] + sc.Volume[sc.Index]; bool CalcMedian = VolumeAvergeType.GetIndex() == 1; if (sc.Index != LastIndex) { float SumOfBarVol = 0; float SumOfAccumVol = 0; int NumValues = 0; SCDateTime PriorDateTime = BarDateTime; int NumDaysToCalc = Period.GetInt(); for (int DaysBack = NumDaysToCalc - 1; DaysBack >= 0; --DaysBack) { if (AccumulateType.GetIndex() == 0) { PriorDateTime -= 1 * DAYS; int DayOfWeek = PriorDateTime.GetDayOfWeek(); if (DayOfWeek == SUNDAY) PriorDateTime -= 2 * DAYS; else if (DayOfWeek == SATURDAY) PriorDateTime -= 1 * DAYS; } else PriorDateTime -= 7 * DAYS; int PriorDate = PriorDateTime.GetDate(); bool ExcludePriorDate = false; for (int ExcludeIndex = 0; ExcludeIndex < NumExcludeDates; ++ExcludeIndex) { if (PriorDate == ExcludeDates[ExcludeIndex]) { ExcludePriorDate = true; break; } } if (ExcludePriorDate) continue; for (int PriorIndex = p_LastPriorIndexes[DaysBack] + 1; PriorIndex < sc.Index; PriorIndex++) { if (sc.BaseDateTimeIn[PriorIndex] < PriorDateTime) { continue; } if (sc.BaseDateTimeIn[PriorIndex] == PriorDateTime) { SumOfBarVol += sc.Volume[PriorIndex]; SumOfAccumVol += CumulativeVolume[PriorIndex]; if (CalcMedian && sc.Index >= DaysBack) { MedianVolumeTemp[sc.Index - DaysBack] = sc.Volume[PriorIndex]; MedianCumulativeVolumeTemp[sc.Index - DaysBack] = CumulativeVolume[PriorIndex]; } NumValues++; p_LastPriorIndexes[DaysBack] = PriorIndex; } // sc.BaseDateTimeIn[PriorIndex] >= PriorDateTime) break; } } if (NumValues > 0) { if (CalcMedian) { MovingMedian_S(MedianVolumeTemp, AverageVolume, MedianTemp, sc.Index, NumValues); MovingMedian_S(MedianCumulativeVolumeTemp, AverageCumulativeVolume, MedianTemp, sc.Index, NumValues); } else { AverageVolume[sc.Index] = SumOfBarVol / NumValues; AverageCumulativeVolume[sc.Index] = SumOfAccumVol / NumValues; } } LastIndex = sc.Index; } if (!NoPlot) { // express relative and avg accumulated volume as percentages if (AverageVolume[sc.Index] != 0) RelativeVolume[sc.Index] = (sc.Volume[sc.Index] / AverageVolume[sc.Index]) * 100.0f; if (AverageCumulativeVolume[sc.Index] != 0) CumulativeVolumeRatio[sc.Index] = (CumulativeVolume[sc.Index] / AverageCumulativeVolume[sc.Index]) * 100.0f; AverageVolumeSubgraph[sc.Index] = AverageVolume[sc.Index]; AverageCumulativeVolumeSubgraph[sc.Index] = AverageCumulativeVolume[sc.Index]; // finally color bars if (RelativeVolume[sc.Index] <= LowPercentThresh.GetFloat() && LowPercentThresh.GetFloat() != 0) RelativeVolume.DataColor[sc.Index] = LowThreshColor.GetColor(); else if (RelativeVolume[sc.Index] >= HighPercentThresh.GetFloat() && HighPercentThresh.GetFloat() != 0) RelativeVolume.DataColor[sc.Index] = HighThreshColor.GetColor(); else RelativeVolume.DataColor[sc.Index] = RelativeVolume.PrimaryColor; } }