VBA excel - excel creating empty csv files when using application.ontime - excel

I got a macro that runs every 30 seconds using Application.Ontime. Every iteration creates a new csv file containing 8 columns and between 50 to 100 rows. The Application.Ontime normally runs from 8am to 5pm.
The problem is that sometimes during the day the macro just stop storing data in the csv files but still creates csv files. Hence, it still creates csv files but without any data in it.
EDIT:
The files that are created contain headers (StdTenorArray(0))
The variable StdXXXXXX is defined in another macro (button) and is a global variable
Here is the code:
Sub RunOnTime()
Application.CutCopyMode = False
Set ThisWkb = ThisWorkbook
dTime = Now + TimeSerial(0, 0, 30)
Application.OnTime dTime, "RunOnTime"
Call csvFileArray
Set ThisWkb = Nothing
End Sub
The above code calls this macro:
Sub csvFileArray()
Dim StdTenorArray(), ArkArr(5) As Variant
Dim FileName As String
Dim StdTenorCnt, h, j As Long
Set ThisWkb = ThisWorkbook
Application.CutCopyMode = False
ArkArr(1) = "XXXXXXctb"
ArkArr(2) = "XXXXXctb"
ArkArr(3) = "XXXXctb"
ArkArr(4) = "XXXctb"
ArkArr(5) = "XXctb"
ReDim StdTenorArray(ThisWkb.Sheets(ArkArr(1)).Range("B" & Rows.Count).End(xlUp).Row + ThisWkb.Sheets(ArkArr(2)).Range("B" & Rows.Count).End(xlUp).Row + ThisWkb.Sheets(ArkArr(3)).Range("B" & Rows.Count).End(xlUp).Row + ThisWkb.Sheets(ArkArr(4)).Range("B" & Rows.Count).End(xlUp).Row + ThisWkb.Sheets(ArkArr(5)).Range("B" & Rows.Count).End(xlUp).Row)
'Standard tenors
StdTenorCnt = 1
If StdXXXXXX = True Then
For j = 5 To 29
If UCase(ThisWkb.Sheets(ArkArr(1)).Cells(j, 4)) = True _
And WorksheetFunction.IsNumber(ThisWkb.Sheets(ArkArr(1)).Cells(j, 10)) = True _
And WorksheetFunction.IsNumber(ThisWkb.Sheets(ArkArr(1)).Cells(j, 11)) = True _
And IsDate(ThisWkb.Sheets(ArkArr(1)).Cells(j, 7)) = True _
And IsDate(ThisWkb.Sheets(ArkArr(1)).Cells(j, 8)) = True Then
StdTenorArray(StdTenorCnt) = "" & ThisWkb.Sheets(ArkArr(1)).Cells(j, 5) & ";" & Format(ThisWkb.Sheets(ArkArr(1)).Cells(j, 7), "yyyymmdd") & ";" & Format(ThisWkb.Sheets(ArkArr(1)).Cells(j, 8), "yyyymmdd") & ";" & ThisWkb.Sheets(ArkArr(1)).Cells(j, 9) & ";" & Replace(Format(ThisWkb.Sheets(ArkArr(1)).Cells(j, 10), "##0.00"), ",", ".") & ";" & Replace(Format(ThisWkb.Sheets(ArkArr(1)).Cells(j, 11), "##0.00"), ",", ".") & ";" & ThisWkb.Sheets(ArkArr(1)).Cells(j, 6) & ";JPD"
StdTenorCnt = StdTenorCnt + 1
End If
Next j
End I.
.
.
'more storing in the array like the part above
.
.
StdTenorArray(0) = "Symbol;SpotDate;ValueDate;Removed;Bid;Offer;Tenor;Channel"
Set fs = CreateObject("Scripting.FileSystemObject")
'test
app_path = ThisWkb.Path
Set a = fs.CreateTextFile("" & app_path & "\Test\" & Strings.Format(Now(), "dd.mm.yyyy") & " " & Strings.Format(Now(), "hh.mm.ss") & "." & Strings.Right(Strings.Format(Timer(), "#0.00"), 2) & ".csv", True)
For j = 0 To StdTenorCnt - 1
a.WriteLine ("" & StdTenorArray(j) & "")
Next j
a.Close
ThisWkb.Sheets("DKK").Cells(1, 27) = "" & Strings.Format(Now(), "hh:mm:ss") & ":" & Strings.Right(Strings.Format(Timer(), "#0.00"), 2) & ""
ReDim StdTenorArray(0)
Set fs = Nothing
Set a = Nothing
Set ThisWkb = Nothing
Application.CutCopyMode = False
End Sub
Hope someone have a solution to this problem or maybe can point me in the right direction.
Have a nice weekend.
\Kristian

Related

Run time error 1004 when trying to input hyperlinks into cells

I seem to have no problem adding a hyperlink into one cell but when I try and add into multiple cells there is a problem. I have also tried using .formula method and writing out the =HYPERLINK formula but that encountered the same issue... any help would be greatly appreciated!
With Sheets(sheetName)
.Hyperlinks.Add Anchor:=.Range("B1"), _
Address:=folderName, _
TextToDisplay:="Client"
End With
For i = 0 To lastRow - 2
If reportRequired(i) = "Yes" Then
fileName = folderName + "\" + clients(i) + ".docx"
With Sheets(sheetName)
.Hyperlinks.Add Anchor:=.Range(Cells(i + 2, 2)), _
Address:=fileName, _
TextToDisplay:=clients(i)
End With
End If
Next i
Using the hyperlink formula I tried this way as well:
For i = 0 To lastRow - 2
If reportRequired(i) = "Yes" Then
fileName = folderName + "\" + clients(i) + ".docx"
Sheets(sheetName).Range(Cells(i + 2, 2)).formula = "=HYPERLINK(" + fileName + """ + clients(i) + """ + ")"
End If
Next i

Excel VBA can't save file

This is my code but I have a problem saving a file.
Private o As Integer
Public Sub Procedure1()
o = 1
End Sub
Sub dural()
Location = Sheets("uitleg").Range("A2").Value
Totallocation = Location & "\"
Debug.Print (Totallocation)
checkNum = Sheets("FunBelgium").Range("A1").Value
Debug.Print (checkNum)
lRow = Range("A65536").End(xlUp).Row 'finds last row, assumes contiguous data
j = 1 'first row for your output
For i = 1 To lRow
If Range("A" & i).Value = checkNum Then
Sheets("Output").Range("A" & j & ":N" & j).Value = Sheets("FunBelgium").Range("A" & i & ":N" & i).Value
Rows([i]).EntireRow.Delete
j = j + 1 'advances output row counter if checkNum is found
End If
Next
o = o + 1
Application.ScreenUpdating = True
Sheets("Export").Activate
ActiveSheet.Copy
Thisfile = ActiveSheet.Range("J2").Value
With ActiveSheet.UsedRange
.Copy
.PasteSpecial xlValues
.PasteSpecial xlFormats
End With
Application.CutCopyMode = False
ActiveWorkbook.SaveAs Filename:=Totallocation & Thisfile, FileFormat:=xlCSV, CreateBackup:=True
'ActiveSheet.SaveAs Filename:="C:\Users\sgouman\Downloads\Bernd\" & Thisfile & ".csv"
Application.ScreenUpdating = True
ActiveWorkbook.Close
Sheets("FunBelgium").Activate
If Cells(1, 1) = "" Then
Sheets("Output").Cells.ClearContents
Exit Sub
Else:
Debug.Print ("niet leeg")
Sheets("Output").Cells.ClearContents
j = 0
Call dural
End If
End Sub
So the debug for totallocation is this:
C:\Users\sgouman\Downloads\Bernd\
But I get an 1004 error. If I just manually copy in that file location in the activeworkbook.saveas it works fine.
I believe this is the issue:
Totallocation = Location & "\"
Please replace by this:
Totallocation = Location & "\\"
Reason: the "\" character is a special character, giving another meaning to the next one (e.g. "\n" is newline, "\t" is tab character, ...).
I tried on my PC and there everything is working fine, please debug your VBA code to the "Save" line, and in the immediate window, launch following commands and let us know the results:
?totalLocation
?ThisFile
?totalLocation & Thisfile
This should show you what the filenames look like.
By the way, are you sure your directory is not read-only? Are you even sure that this is the line, causing the issue?

SaveAs failing despite not changing the code

I have a function in a larger macro that helps reformat and clean up some data from a specific measurement file so that it can be used by the rest of the macro. I recently needed to update some of the data clean-up & reformatting that the function does based on guidance from the department that uses the macro. Those changes work fine, but now the .SaveAs is failing on Error 1004 "SaveAs method of object '_Workbook' failed".
I compared the old & new versions in a text comparison program (UltraCompare) and the changes definitely shouldn't impact the SaveAs. If I stop the macro at the point just before SaveAs and manually save that works successfully, so nothing in the file itself is blocking the save, nor is it a permissions change I didn't know about (which is extra not likely since the test folder is a child of my Desktop).
To go through some of the answers I've seen to other questions on this error
I don't use ActiveWorkbook to save, I create the workbook when setting a workbook variable
I don't use a date in the save as file name
There are no hyperlinks in the workbook
Excel doesn't throw a prompt, and alerts are left on prior to the SaveAs line
As mentioned above, the save is to a folder off my Desktop, so network drive mapping involved
Some additional things I've tried:
During debug, creating a new variable immediately prior to the .SaveAs line & populating it with a new file name in the same folder, and using that in the .SaveAs in place of the replace
Again with a new variable prior to .SaveAs that specifies a different folder
Specifying FileFormat:=51
All that said, here's the code, if anyone has ideas I'm game:
Function MergeCDC(sw As StatWin, fpath As String, BadDateRef As Range, Optional FromComb As Boolean = False) As Boolean
'StatWin is a custom form with a text box for printing status text to the user & a progress bar. fpath is the full file path of the file to be used as a string (folder path & file name including file extension)
'BadDateRef is a cell in the workbook that holds this function that holds the date 1/1/1900 which is used by the file being processed to indicate no date (i.e. the field should be null, but the DBAs
'decided to be weird so we have to deal with it)
'FromComb is a way to know if this function was called by a specific other function, so that run time tracking can be handled correctly
'Check if we're blocked on CDC (this prevents the function from trying to run again if it's called a second (or greater) time after failing)
If sw.CDCBlock Then
MergeCDC = False
Exit Function
End If 'else continue
Dim src As Workbook
Set src = Workbooks.Open(fpath) 'No need to check if the CDC workbook is present as that was done prior to this function being invoked
Dim ry As Worksheet
Dim ytd As Worksheet
Dim m As Workbook
Set m = Workbooks.Add
Dim ms As Worksheet
Set ms = m.Worksheets(1)
Dim ret As Boolean
ret = False
Dim c As Long
Dim r As Long
Dim ryc As Long
Dim temp() As Long
Dim msc As Long
Dim z As Integer
Dim yfnd As Boolean
Dim rfnd As Boolean
'Update the RunStat sheet such that we track CDC data merge as it's own item
If FromComb Then
sw.RStat.Range("A" & sw.StatRow + 2).Value = sw.RStat.Range("A" & sw.StatRow + 1).Value
sw.RStat.Range("B" & sw.StatRow + 2).Value = sw.RStat.Range("B" & sw.StatRow + 1).Value 'Bump start time for combined list being created
sw.RStat.Range("A" & sw.StatRow + 1).Value = sw.RStat.Range("A" & sw.StatRow).Value 'bump start for creation of combined source file
sw.RStat.Range("B" & sw.StatRow + 1).Value = sw.RStat.Range("B" & sw.StatRow).Value
Else
sw.RStat.Range("A" & sw.StatRow + 1).Value = sw.RStat.Range("A" & sw.StatRow).Value 'bump start for creation of CDC list
sw.RStat.Range("B" & sw.StatRow + 1).Value = sw.RStat.Range("B" & sw.StatRow).Value
End If
sw.RStat.Range("A" & sw.StatRow).Value = "CDC Merge"
sw.RStat.Range("B" & sw.StatRow).Value = Now()
'Determine which sheet is which
z = 1
yfnd = True
rfnd = True
Do While z <= src.Worksheets.Count And (yfnd Or rfnd)
If InStr(1, UCase(src.Worksheets(z).Name), "YTD") > 0 Then
yfnd = False
Set ytd = src.Worksheets(z)
ElseIf InStr(1, UCase(src.Worksheets(z).Name), "RY") > 0 Then
rfnd = False
Set ry = src.Worksheets(z)
End If
z = z + 1
Loop
'Check we found both sheets
If rfnd Or yfnd Then
Call Err("Unable to locate the RY and/or YTD worksheets in the Unedited CDC file. Please update the file such that the YTD worksheet includes 'YTD' in its name, and the RY" _
& " worksheet includes 'RY' in its name. This error prevents any list utilizing CDC data from being completed.", sw)
MergeCDC = False
sw.CDCBlock = True
Exit Function
End If 'else continue as normal
'Prep the two worksheets
temp = CDCPrep(ry, True, sw)
ryc = temp(0)
r = temp(1) 'CDCPrep returns the first BLANK row so we will use r as the row to paste to when pasting YTD data
'Prep of RY successful?
If temp(0) <> -1 Then
temp = CDCPrep(ytd, False, sw)
Else
'Close the new workbook without saving
m.Close SaveChanges:=False
End If
'Continue?
If temp(0) <> -1 Then
'Copy the entirety of Rolling Year data
ry.Range("A1:" & ColNumToStr(ryc) & r - 1).Copy
ms.Range("A1").PasteSpecial xlPasteAll
'Start merging in the YTD data. Since we can't assume the columns are in the same order we'll start iterating through the RY columns and copying one column at a time from YTD
c = 0
Do While ms.Range("A1").Offset(0, c).Value <> ""
'Find the matching column in YTD
msc = 0
Dim fnd As Boolean
fnd = False
Do While ytd.Range("A1").Offset(0, msc).Value <> "" And fnd = False
If ytd.Range("A1").Offset(0, msc).Value = ms.Range("A1").Offset(0, c).Value Then
'Found the column. Copy it's data
fnd = True
ytd.Range(ColNumToStr(msc + 1) & "2:" & ColNumToStr(msc + 1) & temp(1)).Copy
Else
msc = msc + 1
End If
Loop
'Did we find a match?
If fnd Then
'Paste the data
ms.Range("A" & r).Offset(0, c).PasteSpecial xlPasteAll
Else
Call Err("Unable to locate the " & ms.Range("A1").Offset(0, c).Value & " column in the Yr To Date data. The list will be generated, but will be missing these values for items found only" _
& " in the Yr To Date data.", sw)
End If
c = c + 1
Loop
'Get the last row of data so we can sort the merged data
r = r + temp(1)
'Check that is the last row
Do While ms.Range("A" & r).Value <> "" And r < 600000 'ridiculously high value, but serves as a fail-safe to keep from hitting end of sheet and not having found data end
r = r + 1
Loop
'Sort the data and remove duplicates according to the current month (Jan - Jun: RY rows preferred to YTD; Jul - Dec: YTD preferred)
If Month(sw.CurDate) < 7 Then
'RY preferred
ms.Sort.SortFields.Clear
ms.Sort.SortFields.Add Key:=Range _
("A2:A" & r), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ms.Sort.SortFields.Add Key:=Range _
("B2:B" & r), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ms.Sort
.SetRange Range("A1:" & ColNumToStr(c + 1) & r + temp(1))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Else
'YTD preferred
ms.Sort.SortFields.Clear
ms.Sort.SortFields.Add Key:=Range _
("A2:A" & r), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
ms.Sort.SortFields.Add Key:=Range _
("B2:B" & r), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortNormal
With ms.Sort
.SetRange Range("A1:" & ColNumToStr(c + 1) & r + temp(1))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End If
ms.Range("A1:" & ColNumToStr(c + 1) & r + temp(1)).RemoveDuplicates Columns:=1, Header:=xlYes
'Delete the MergeKey & Source columns
ms.Range("A:B").Delete Shift:=xlLeft
'In order to be processed correctly by other functions later certain target values (Last Test Date, Last Test Value) need to be inserted as new SubMeasures (i.e. new rows)
Dim i As Long
Dim ik As String
Dim sm As String
Dim nc As String
Dim ltd As String
Dim ltv As String
Dim td As String
i = 0
fnd = True
'To add the rows we need to be able to tell when we're on the first row of data for a particular item. Meaning we need to know the column holding ItemKey
Do While ms.Range("A1").Offset(0, i).Value <> "" And fnd
Select Case LCase(ms.Range("A1").Offset(0, i).Value)
Case "itemkey"
mk = ColNumToStr(i + 1)
Case "submeasure"
sm = ColNumToStr(i + 1)
Case "numercnt"
nc = ColNumToStr(i + 1)
Case "date1"
ltd = ColNumToStr(i + 1)
Case "last_val"
ltv = ColNumToStr(i + 1)
Case "terminationdate"
td = ColNumToStr(i + 1)
End Select
i = i + 1
If sm <> "" And ik <> "" And td <> "" And ltd <> "" And nc <> "" And ltv <> "" Then
fnd = False
End If
Loop
If fnd Then
'Couldn't find the needed columns. Report the error
Call Err("Unable to locate the one or more of the following columns in the MergedCDC file: ItemKey, SubMeasure, NumerCnt, TerminationDate, Last Test Date, Last Test Value. This will prevent adding" _
& " rows for Last Test Value & Last Test Date, which will in turn mean those columns will not be correctly populated in any list based on CDC data. All other values from" _
& " the CDC data should be correct though.", sw)
Else
'Add the rows
Dim PM As String
i = 2
Do While ms.Range(mk & i).Value <> ""
If InStr(1, PM, "|" & ms.Range(mk & i).Value & "|") = 0 Then
'First row for this item set all Term Date values are set to the MAX Term Date value for the item. Also determine if they're non-compliant on any measure
Dim y As Integer
Dim tdv As Date
Dim ncv As Integer
y = 0
tdv = DateSerial(1900, 1, 1)
ncv = 1 'Start # 1 so that if any row is non-compliant we can change ncv then (as opposed to having to make sure ALL rows are compliant before setting ncv to 1)
Do While ms.Range(mk & i + y).Value = ms.Range(mk & i).Value
If ms.Range(td & i + y).Value > tdv Then
tdv = ms.Range(td & i + y).Value
End If 'else the term date is older than tdv, and we want to standardize to the max term date, so leave tdv alone
If ms.Range(nc & i + y).Value < ncv Then
ncv = 0
ElseIf ms.Range(sm & i + y).Value = "Tested" Then
'Check if the Test Value = 0 and if the Last Test Date is valid
If (ms.Range(ltd & i + y).Value = DateSerial(1900, 1, 1) Or ms.Range(ltd & i + y).Value = "" Or ms.Range(ltd & i + y).Value = BadDateRef.Value) _
And ms.Range(lbg & i + y).Value = 0 Then
'The value is 0 and the date isn't valid, that means the item wasn't actually tested (in effect if not actuality). Set this row to not tested & update ncv
ms.Range(nc & i + y).Value = 0
ncv = 0
End If 'else the item was tested, the compliance value stays the same, which means ncv doesn't need changed
End If 'Else row indicates item is compliant, which is the default, so no action needed
y = y + 1
Loop
'Replace Term Date values that aren't TDV with TDV (technically, we also replace the row that set TDV, but with the same value)
If tdv <> DateSerial(1900, 1, 1) Then
y = 0
Do While ms.Range(mk & i + y).Value = ms.Range(mk & i).Value
ms.Range(td & i + y).Value = tdv
y = y + 1
Loop
Else
'No actual date found for TDV, just clear the cells setting the format to General so that Excel doesn't re-fill in 1/1/1900
y = 0
Do While ms.Range(mk & i + y).Value = ms.Range(mk & i).Value
ms.Range(td & i + y).NumberFormat = "General"
ms.Range(td & i + y).ClearContents
y = y + 1
Loop
End If
'Copy the current row & insert two copies of it below the current row
ms.Range(i & ":" & i).Copy
ms.Range(i + 1 & ":" & i + 1).Insert Shift:=xlDown
ms.Range(i & ":" & i).Copy
ms.Range(i + 1 & ":" & i + 1).Insert Shift:=xlDown
'Change the SubMeasure cells appropriately
ms.Range(sm & i + 1).Value = "Last Test Date"
ms.Range(sm & i + 2).Value = "Last Test Val"
'Set the compliance cnt value. If the item's last value is 0 AND there is no Last Test Date value, the numercnt value for the two added rows should be 0 so that date & value
' appear (as even though they're compliant, they probably shouldn't be marked as such due to lack of proof). If the value is non-0 then set based on ncv
If ms.Range(lbg & i).Value = 0 & ms.Range(ltd & i + y).Value = "" Then
ms.Range(nc & i + 1).Value = 0
ms.Range(nc & i + 2).Value = 0
Else
ms.Range(nc & i + 1).Value = ncv
ms.Range(nc & i + 2).Value = ncv
End If
'Add the item to PM, a delimited string of ItemKeys for processed items that lets us check if we've already seen a row for this item
PM = PM & "|" & ms.Range(mk & i).Value & "|"
'Add 2 to i (this way the additional incrementing of i below results in us looking at row i + 3, which was the row that had been immediately below row i before we added the two new rows)
i = i + 2
End If 'else proceed to the next row, which happens anyway
i = i + 1
Loop
End If
'Clear out compliant rows so that MergedCDC processes through MFPRocessor (a seperate function that we're setting up the CDC data to go through) like any other source file
'(submeasure present = item non-compliant on measure)
i = 2
Do While ms.Range(mk & i).Value <> ""
If ms.Range(nc & i).Value = 1 Then
ms.Range(i & ":" & i).Delete Shift:=xlUp
Else
i = i + 1
End If
Loop
'Remove 1/1/1900 values from Last Test Date & Term Date
i = 2
Do While ms.Range(mk & i).Value <> ""
If ms.Range(ltd & i).Value = "1/1/1900" Or ms.Range(ltd & i).Value = BadDateRef.Value Then
ms.Range(ltd & i).NumberFormat = "General"
ms.Range(ltd & i).ClearContents
End If
If ms.Range(td & i).Value = "1/1/1900" Or ms.Range(td & i).Value = BadDateRef.Value Then
ms.Range(td & i).NumberFormat = "General"
ms.Range(td & i).ClearContents
End If
i = i + 1
Loop
ret = True
'Save the workbook
m.SaveAs (Replace(fpath, "CDC", "MergedCDC")) 'This code HAD worked, despite none of the changes being anything that should impact this line, this line
Application.DisplayAlerts = False
m.Close SaveChanges:=False
Application.DisplayAlerts = True
Else
'Close the new workbook without saving
m.Close SaveChanges:=False
End If
'Close the original CDC workbook
Application.DisplayAlerts = False
src.Close
Application.DisplayAlerts = True
'Capture completion of CDC merge
sw.RStat.Range("C" & sw.StatRow).Value = Now()
sw.StatRow = sw.StatRow + 1
MergeCDC = ret
End Function
If you haven't changed your code then here's a few things to check which could be causing the error:
Workbook object is out of context - ensure that you are using only one instance of Excel, if your data and workbook are in different instances then they wont be able to reach each other. When your code breaks at the error, add the workbook to your watch list to see if it reachable.
Filepath is unreachable - when the code breaks at this error, take the value of Replace(fpath, "CDC", "MergedCDC") without the filename at the end, and paste it into windows explorer and check that it is reachable.

Unable to use variable input

Background
As I am trying to run a set of technical indicators on a large number of csv data files, I patched together a 3 macros which was intended to
Macro 1: RunAnalysis > Open every individual excel file in specific
folder
Macro 2: DoWork > Run Macro Macro 3: IndicatorData > To
populate the individual csv files opened by Macro 1 with technical
indicator formulas.
The codes are found below.
Problem/Issue
The problem lies with Macro 3 [Indicator Data]
The value of variable EMAWindow1 which captures a value from the sheet called ControlPanel found in the same Workbook is used selectively by vba when populating column H.
In the first two lines of formulas
ActiveSheet.Range("h1") = EMAWindow1 & " Day EMA"
ActiveSheet.Range("h" & EMAWindow1 + 1) = "=average(R[-" & EMAWindow1 - 1 & "]C[-3]:RC[-3])"
You will find the macro working perfecting. However
When you reach the third line
ActiveSheet.Range("h" & EMAWindow1 + 2 & ":h" & LastRowCheck).FormulaR1C1 = "=R[0]C[-3]*(2/(EMAWindow1 + 1)) + R[-1]C[0] * (1-(2/(EMAWindow1 + 1)))"
For some reason, the value of EMAWindow1 is not used and is treated as a text causing error and resulting in the #NAME? as the formula is unable to calculate with a text inside it.
The subsequent codes encounter the same problem. Anyone faced the same problem before? I have been at this problem for awhile, and I hope for some enlightenment.
Codes
Sub RunAnalysis()
Dim Filename, Pathname As String
Dim wb As Workbook
Pathname = "C:\Users\gabri_000\Desktop\Trading Data\Stocks - 1 - 100\"
Filename = Dir(Pathname & "*.csv")
Do While Filename <> ""
Set wb = Workbooks.Open(Pathname & Filename)
DoWork wb
wb.Close SaveChanges:=True
Filename = Dir()
Loop
End Sub
Sub DoWork(wb As Workbook)
With wb
Call IndicatorData
End With
End Sub
Sub IndicatorData()
Dim LastRowCheck As Long
Dim EMAWindow1, EMAWindow2, EMAWindow3 As Long
Dim Pathname, Filename, FileNameIndex, FinalFileName As String
'Converting file path into a string
Pathname = "C:\Users\gabri_000\Desktop\Trading Data\Stocks - 1 - 100\"
'Full file name
Filename = Dir(Pathname)
'Removing the .csv portion of the file name
FileNameIndex = InStr(1, Filename, ".csv")
FinalFileName = Left(Filename, FileNameIndex - 1)
'Selecting Recently Opened File
Sheets(FinalFileName).Select
'Counting Number of Rows in the worksheet
With Worksheets(FinalFileName)
LastRowCheck = .Range("A" & .Rows.Count).End(xlUp).Row
End With
'EMA Inputs
'Obtaining data from masterfile
With ThisWorkbook.Sheets("ControlPanel")
EMAWindow1 = .Range("EMAWindow1")
EMAWindow2 = .Range("EMAWindow2")
EMAWindow3 = .Range("EMAWindow3")
End With
'EMA Calcuations
ActiveSheet.Range("h1") = EMAWindow1 & " Day EMA"
ActiveSheet.Range("h" & EMAWindow1 + 1) = "=average(R[-" & EMAWindow1 - 1 & "]C[-3]:RC[-3])"
ActiveSheet.Range("h" & EMAWindow1 + 2 & ":h" & LastRowCheck).FormulaR1C1 = "=R[0]C[-3]*(2/(EMAWindow1 + 1)) + R[-1]C[0] * (1-(2/(EMAWindow1 + 1)))"
ActiveSheet.Range("i1") = EMAWindow2 & " Day EMA"
ActiveSheet.Range("i" & EMAWindow2 + 1) = "=average(R[-" & EMAWindow2 - 1 & "]C[-4]:RC[-4])"
ActiveSheet.Range("i" & EMAWindow2 + 2 & ":i" & LastRowCheck).FormulaR1C1 = "=R[0]C[-4]*(2/(EMAWindow2 + 1)) + R[-1]C[0] * (1-(2/(EMAWindow2 + 1)))"
ActiveSheet.Range("j1") = EMAWindow3 & " Day EMA"
ActiveSheet.Range("j" & EMAWindow3 + 1) = "=average(R[-" & EMAWindow3 - 1 & "]C[-5]:RC[-5])"
ActiveSheet.Range("j" & EMAWindow3 + 2 & ":i" & LastRowCheck).FormulaR1C1 = "=R[0]C[-5]*(2/(EMAWindow3 + 1)) + R[-1]C[0] * (1-(2/(EMAWindow3 + 1)))"
End Sub

Excel VBA SUMIF Super slow code

I have SUMIF running really really slow. My data has 14,800 Rows and 39 Columns.
I do the following:
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
ActiveSheet.DisplayPageBreaks = False
EDITED TO ADD more potentially relevant code that may be interacting with the SUMIF command
It may be relevant to the speed issue so I'll mention it. I get the user to open a file from wherever they may have stored the report. The file then stays open. Maybe that is a problem. I don't know if it should be some other way.. like I close it but keep the address in mind or something??
FilterType = "Text Files (*.txt),*.txt," & "Comma Separated Files (*.csv),*.csv," & "ASCII Files (*.asc),*.asc," & "All Files (*.*),*.*"
FilterIndex = 4
Title = "File to be Selected"
File_path = Application.GetOpenFilename(FileFilter:=FilterType, FilterIndex:=FilterIndex, Title:=Title)
If File_path = "" Then
MsgBox "No file was selected."
Exit Sub
End If
Set wbSource = Workbooks.Open(File_path)
Original_Name = ActiveWorkbook.Name
If ActiveSheet.AutoFilterMode Then
ActiveSheet.AutoFilterMode = False
End If
Set wb1 = ActiveWorkbook
Set ws1 = wb1.Worksheets("Sheet1")
With ws1
FinalColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
FinalRow = .Range("B" & .Rows.Count).End(xlUp).Row
For j = 1 To FinalColumn
If .Cells(1, j).Value = "Effec.Date" Then
Effective_Date_Column = j
ElseIf .Cells(1, j).Value = "FolderId" Then
FolderId_column = j
ElseIf .Cells(1, j).Value = "FolderNotional" Then
FolderNotional_column = j
End If
Next j
'range_Total_Folder_Fixed = .Cells(2, Total_Folder_Column).Address & ":" & .Cells(FinalRow, Total_Folder_Column).Address
range_FolderId_Fixed = .Cells(2, FolderId_column).Address & ":" & .Cells(FinalRow, FolderId_column).Address
range_FolderId_Cell = .Cells(2, FolderId_column).Address(RowAbsolute:=False, ColumnAbsolute:=False)
range_FolderNotional_Fixed = .Cells(2, FolderNotional_column).Address & ":" & .Cells(FinalRow, FolderNotional_column).Address
Everything runs in 8-10 seconds until we come to the lie below. Now the total time jumps to a 150 seconds.
.Range(range_Total_Folder_Fixed).Formula = "=SUMIF(" & range_FolderId_Fixed & "," & range_FolderId_Cell & "," & range_FolderNotional_Fixed & ")"
Am I doing something wrong? Is there a better (more efficient) way to write a general formula?
EDIT: Code generated Raw Formula
Some of the excel worksheet functions in my code:
.Range(range_Isnumber).Formula = "=(RIGHT(" & range_TradeId_cell & ",2)<> ""IB"")*1"
.Range(range_Is_IB).Formula = "=(RIGHT(" & range_TradeId_cell & ",2)= ""IB"")*1"
.Range(range_Exceptions).Formula = "=(SUMIF(" & range_FolderId_Fixed & "," & range_FolderId_Cell & "," & range_Isnumber_fixed & ")= COUNTIF(" & range_FolderId_Fixed & "," & range_FolderId_Cell & "))*1+(SUMIF(" & range_FolderId_Fixed & "," & range_FolderId_Cell & "," & range_Is_IB_fixed & ")= COUNTIF(" & range_FolderId_Fixed & "," & range_FolderId_Cell & "))*1 "
.Range("C13").FormulaR1C1 = "=SUM(IF(FREQUENCY(MATCH([SCL_FL_2013_11_30.xlsx]Rest!R2C2:R2321C2,[SCL_FL_2013_11_30.xlsx]Rest!R2C2:R2321C2,0),MATCH([SCL_FL_2013_11_30.xlsx]Rest!R2C2:R2321C2,[SCL_FL_2013_11_30.xlsx]Rest!R2C2:R2321C2,0))>0,1))"
So Stuff like
Range("I2")=SUMIF($H$2:$H$5,H2,$G$2:$G$5)
Where the data could be like
RowG RowH RowI
Alice 1 4
Alice 3 4
Bob 9 17
Bob 8 17
Dan 2 2
EDIT2 : Implementing Sam's solution, I am getting errors:
Set range_FolderId_Fixed = .Range(.Cells(2, FolderId_column), .Cells(FinalRow, FolderId_column))
Set range_FolderId_Cell = .Range(.Cells(2, FolderId_column),.Cells(FinalRow, FolderId_column))
Set range_FolderNotional_Fixed = .Range(.Cells(2, FolderNotional_column), .Cells(FinalRow, FolderNotional_column))
Set range_Total_Folder_Fixed = .Range(.Cells(2, Total_Folder_Column), .Cells(FinalRow, Total_Folder_Column))
.Range(range_Total_Folder_Fixed).Value = SumIf_func(range_FolderId_Fixed, range_FolderId_Cell, range_FolderNotional_Fixed)
I am getting a type application defined or object defined error in the line below.
.Range(range_Total_Folder_Fixed).Value = SumIf_func(range_FolderId_Fixed, range_FolderId_Cell, range_FolderNotional_Fixed)
I have no idea what to do next.
Ok this is what I came up with
Public Function SumIf_func(rng As Range, _
criteria As Range, _
sumRange As Range) As Variant()
Dim rngArr() As Variant
Dim sumArr() As Variant
Dim criteriaArr() As Variant
Dim returnArr() As Variant
Dim temp As Double
rngArr = rng.Value2
sumArr = sumRange.Value2
criteriaArr = criteria.Value2
If UBound(sumArr) <> UBound(rngArr) Then _
Err.Raise 12345, "SumIf_func", "Sum range and check range should be the same size"
If UBound(sumArr, 2) <> 1 Or UBound(rngArr, 2) <> 1 Then _
Err.Raise 12346, "SumIf_func", "Sum range and check range should be a single column"
ReDim returnArr(1 To UBound(criteriaArr), 1 To 1)
For c = LBound(criteriaArr) To UBound(criteriaArr)
returnArr(c, 1) = Application.WorksheetFunction.SumIf(rng, criteriaArr(c, 1), sumRange)
Next c
SumIf_func = returnArr
End Function
This function takes in three ranges:
The range to check
The range where the criteria are
The range where the values to sum are
The range to check and the sum range should both be the same length and only be 1 column across.
The array that is returned will be the same size as the criteria array..
Here is an example of usage:
Public Sub test_SumIf()
Dim ws As Worksheet
Set ws = Sheet1
Dim rng As Range, sumRng As Range, criteria As Range
Set rng = ws.Range("A1:A100")
Set sumRng = ws.Range("B1:B100")
Set criteria = ws.Range("C1:C10")
ws.Range("D1:D10").Value = SumIf_func(rng, criteria, sumRng)
End Sub

Resources