I had a simple macro that used to run in a minute. But it's now running very slowly. It takes about an hour to run. Is this because of the loop I'm using? Can someone help me see what went wrong?
Sub Runtable()
Sheets("RateTable").Cells(1, "A") = "ID"
Sheets("RateTable").Cells(1, "B") = "Section"
Sheets("RateTable").Cells(1, "C") = "Gender"
Sheets("RateTable").Cells(1, "D") = "Age"
'
LastID = Sheets("Input").Cells(2, 22)
For ID = 0 To LastID
LastSet = Sheets("Input").Cells(2, 19)
For myRow = 2 To LastSet
Sheets("RateTable").Cells(ID * (LastSet - 1) + myRow, 1) = Sheets("Input").Cells(ID + 2, 1)
Next myRow
Next ID
'
Dim myMyRow As Long
Dim OutputMyRow As Long
OutputMyRow = 2
LastID = Sheets("Input").Cells(2, 22)
LastSection = Sheets("Input").Cells(2, 21)
LastAge = Sheets("Input").Cells(2, 20)
For ID = 0 To LastID
For Section = 0 To LastSection
For myMyRow = 2 To LastAge
Sheets("RateTable").Cells(OutputMyRow, 2).Value = Sheets("Input").Cells(Section - FirstID + 2, "N").Value
OutputMyRow = OutputMyRow + 1
Next myMyRow
Next Section
Next ID
'
EndGenderLoop = Sheets("Input").Cells(2, 23)
For myRow = 2 To EndGenderLoop
Sheets("RateTable").Cells(myRow, 3) = Sheets("Input").Cells(2, 17)
Next myRow
'
EndAgeLoop = Sheets("Input").Cells(2, 24)
For AgeCurve = 0 To EndAgeLoop
'
For myRow = 2 To 52
Sheets("RateTable").Cells(AgeCurve * 51 + myRow, 4) = Sheets("Input").Cells(myRow, 10)
Next myRow
Next AgeCurve
'
End Sub
Use a status bar to determine where the code is slowing down. Here's one site with simple code (included below in case that link fails) but there are many others. For code this simple to be running 60 times slower now compared to earlier could indicate something wrong with the computer. Have you restarted? Can you revert to a previous backup state?
Option Explicit
Sub StatusBar()
Dim x As Integer
Dim MyTimer As Double
'Change this loop as needed.
For x = 1 To 250
'Dummy Loop here just to waste time.
'Replace this loop with your actual code.
MyTimer = Timer
Do
Loop While Timer - MyTimer < 0.03
Application.StatusBar = "Progress: " & x & " of 250: " & Format(x / 250, "Percent")
DoEvents
Next x
Application.StatusBar = False
End Sub
Related
An analyst observed that the upward movement of stocks on Bovespa is repeated according to a mathematical sequence. He wants to find out what the next bullish sequences will be. Generate and save in Excel cells using macro the sequence 1, 3, 4, 7, 11, 18, 29, ... up to its twentieth term?
following my code in vba:
Sub GerarSequencia()
Dim num As Long
Dim previous As Long
Dim i As Integer
num = 0
previous = 0
For i = 1 To 20
If i = 1 Then
num = 1
Else
num = num + previous
End If
Cells(i, 1).Value = num
previous = num
Next i
End Sub
I tried to generate the sequence of the exercise but did it generate another one?
The sequence is a sommation of the earlier two values. So 1 + 3 = 4 and so on. Before you can start the sqequence you have to have two numbers. I think you can work with:
Sub GerarSequencia()
Dim intFirstNum, intSecondNum As Integer
Dim intCounter As Integer
intFirstNum = 1
intSecondNum = 3
Cells(1, 1) = intFirstNum
Cells(2, 1) = intSecondNum
For intCounter = 3 To 20
Cells(intCounter, 1).Value = Cells(intCounter - 2, 1).Value + Cells(intCounter - 1, 1).Value
Next intCounter
End Sub
So you see that I have made two additional variables which are filled with 1 and 3 (if you change them you can start wherever you want). From that point on, I start the loop from position 3. This is because the first two are already known.
From that point on you can run the sequence. You don't need an if statement in that case.
Generating a Sequence
Sub GerarSequencia()
Const nCOUNT As Long = 20
Dim nPrev As Long: nPrev = 1
Dim nCurr As Long: nCurr = 3
Cells(1, 1).Value = nPrev
Cells(2, 1).Value = nCurr
Dim nNext As Long
Dim i As Long
For i = 3 To nCOUNT
nNext = nPrev + nCurr ' sum up
Cells(i, 1).Value = nNext ' write
nPrev = nCurr ' swap
nCurr = nNext ' swap
Next i
' ' Return the worksheet results in the Immediate window (Ctrl + G).
' For i = 1 To 20
' Debug.Print Cells(i, 1).Value
' Next i
End Sub
I written a vba where when i roll 6000 times dice, it will count the number of 1's rolled 2's rolled and so on until number of 6's
Private Sub CommandButton2_Click()
i = 6000
Do Until i < 0
n = Int(1 + Rnd * (6 - 1 + 1))
TextBox1.Text = Range("A1")
TextBox2.Text = Range("A2")
TextBox3.Text = Range("A3")
TextBox4.Text = Range("A4")
TextBox5.Text = Range("A5")
TextBox6.Text = Range("A6")
If n = 1 Then
Range("A1") = Range("A1") + n
ElseIf n = 2 Then
Range("A2") = Range("A2") + n / 2
ElseIf n = 3 Then
Range("A3") = Range("A3") + n / 3
ElseIf n = 4 Then
Range("A4") = Range("A4") + n / 4
ElseIf n = 5 Then
Range("A5") = Range("A5") + n / 5
ElseIf n = 6 Then
Range("A6") = Range("A6") + n / 6
End If
i = i - 1
Loop
End Sub
It works fine but the problem is it loads so slow, is there a way to fasten this code ?
Please try this code. It will give the result instantly.
Private Sub CommandButton2_Click()
Dim Arr(1 To 6) As Integer
Dim n As Integer ' random number: 1 to 6
Dim i As Long ' loop counter: turns
Randomize
For i = 1 To 6000
n = Int(1 + Rnd * (6 - 1 + 1))
Arr(n) = Arr(n) + 1
Next i
Range("A1").Resize(UBound(Arr)).Value = Application.Transpose(Arr)
For i = 1 To UBound(Arr)
Me.Controls("TextBox" & i).Value = Arr(i)
Next i
End Sub
The interaction between text boxes and worksheet cells isn't clear. It's easy to establish in any way you want.
Option Explicit
Private Sub CommandButton2_Click()
Dim i As Long
Dim n As Long
Dim results As Variant
results = Array(0, 0, 0, 0, 0, 0)
' read results from cells A1 - A6
For i = 1 To 6
results(i - 1) = Cells(1, i).Value
Next i
' roll the dice 6000 times
For i = 1 To 6000
n = Int(Rnd * 6)
results(n) = results(n) + 1
Next i
' write results to cells A1 - A6
For i = 1 To 6
Cells(1, i).Value = results(i - 1)
Next i
End Sub
I need to get the table from website via VBA, but the data is very big.
I used array to save every data, and it cost me over 300 seconds to run it...
Is there any method to accelerate?
(I need to key in and click elements to get the table, can I use "msxml2.xmlhttp"?)
(I am not allowed to use SeleniumBasic.)
this is my code:
Sub ie_()
Application.ScreenUpdating = False
If Weekday(Date) > 1 Then
w1 = DateAdd("d", -Weekday(Date) + 1, Date)
w2 = DateAdd("d", -7, w1)
End If
date1 = Format(w2, "yyyy-mm-dd")
date2 = Format(w1, "yyyy-mm-dd")
Set IE = CreateObject("InternetExplorer.application")
With IE
.Visible = True
.navigate myURL
Set report_btn = .Document.getElementsByClassName("sys-btn")(18)
report_btn.Click
Set next_btn = .Document.getElementByid("btnQry")
next_btn.Click
'key in element
.Document.All.txtTxnTime_From.Value = date1
.Document.All.txtTxnTime_End.Value = date2
.Document.All.btnQuery.Click
'search and get the table. Because the data is huge, I used the loop to wait for it....
Set tbl = .Document.getElementByid("tb_Main")
Do While tbl Is Nothing
Application.Wait (Now + TimeValue("0:00:10"))
Set tbl = .Document.getElementByid("tb_Main")
Loop
End With
'save the data in table to the array
'this step cost almost 300 seconds....
Set trs = tbl.getElementsByTagName("tr")
Dim arr() As Variant
ReDim arr(trs.Length - 1, 25)
i = 0
For Each rw In tbl.Rows
j = 0
For Each cel In rw.Cells
arr(i, j) = cel.innertext
j = j + 1
Next
i = i + 1
Next
'get the data in array and write to the cell
For i = 0 To trs.Length - 1
For j = 0 To 25
Cells(i + 1, j + 1) = arr(i, j)
Next
Next
'close ie
IE.Quit
Set IE = Nothing
End Sub
I have made a userform that allows the user to select a table and add rows to it and fill those rows with various information, all from the userform. I have run into a few problems with this.
First after adding or during adding the items (after hitting submit) excel would crash. It occurs randomly and is hard to reproduce.
Second after running the macro there is a good chance that all the cells in the workbook and every other object except the userform button will stop working, meaning you can't edit interact or even select anything. Then when I close the workbook excel crashes after saving. This is my major offender and I think causes the other problem.
What causes this freezing and why does it occur? How do I fix it? I have looked around and haven't found anything circumstantial. One post said that I should try editing the table with no formatting on it and I did that and it didn't work.
I can provide the excel workbook at a request basis via pm.
The code:
On Activate -
Public Sub UserForm_Activate()
Set cBook = ThisWorkbook
Set dsheet = cBook.Sheets("DATA")
End Sub
Help Checkbox -
Private Sub cbHelp_Click()
If Me.cbHelp.Value = True Then
Me.lbHelp.Visible = True
Else
Me.lbHelp.Visible = False
End If
End Sub
Brand combobox -
Public Sub cmbBrand_Change()
brandTableName = cmbBrand.Value
brandTableName = CleanBrandTableName(brandTableName)
'if brand_edit is not = to a table name then error is thrown
On Error Resume Next
If Err = 380 Then
Exit Sub
Else
cmbItemID.RowSource = brandTableName
End If
On Error GoTo 0
'Set cmbItemID's text to nothing after changing to a new brand
cmbItemID.Text = ""
End Sub
CleanBrandTableName(brandTableName) function -
Option Explicit
Public Function CleanBrandTableName(ByVal brandTableName As String) As String
Dim s As Integer
Dim cleanResult As String
For s = 1 To Len(brandTableName)
Select Case Asc(Mid(brandTableName, s, 1))
Case 32, 48 To 57, 65 To 90, 97 To 122:
cleanResult = cleanResult & Mid(brandTableName, s, 1)
Case 95
cleanResult = cleanResult & " "
Case 38
cleanResult = cleanResult & "and"
End Select
Next s
CleanBrandTableName = Replace(WorksheetFunction.Trim(cleanResult), " ", "_")
End Function
Public Function CleanSpecHyperlink(ByVal specLink As String) As String
Dim cleanLink As Variant
cleanLink = specLink
cleanLink = Replace(cleanLink, "=HYPERLINK(", "")
cleanLink = Replace(cleanLink, ")", "")
cleanLink = Replace(cleanLink, ",", "")
cleanLink = Replace(cleanLink, """", "")
cleanLink = Replace(cleanLink, "Specs", "")
CleanSpecHyperlink = cleanLink
End Function
Browse button -
Public Sub cbBrowse_Click()
Dim rPos As Long
Dim lPos As Long
Dim dPos As Long
specLinkFileName = bFile
rPos = InStrRev(specLinkFileName, "\PDFS\")
lPos = Len(specLinkFileName)
dPos = lPos - rPos
specLinkFileName = Right(specLinkFileName, dPos)
Me.tbSpecLink.Text = specLinkFileName
End Sub
bFile function -
Option Explicit
Public Function bFile() As String
bFile = Application.GetOpenFilename(Title:="Please choose a file to open")
If bFile = "" Then
MsgBox "No file selected.", vbExclamation, "Sorry!"
Exit Function
End If
End Function
Preview button -
Private Sub cbSpecs_Click()
If specLinkFileName = "" Then Exit Sub
cBook.FollowHyperlink (specLinkFileName)
End Sub
Add Item button -
Private Sub cbAddItem_Click()
Dim brand As String
Dim description As String
Dim listPrice As Currency
Dim cost As Currency
Dim Notes As String
Dim other As Variant
itemID = Me.tbNewItem.Text
brand = Me.tbBrandName.Text
description = Me.tbDescription.Text
specLink = Replace(specLinkFileName, specLinkFileName, "=HYPERLINK(""" & specLinkFileName & """,""Specs"")")
If Me.tbListPrice.Text = "" Then
listPrice = 0
Else
listPrice = Me.tbListPrice.Text
End If
If Me.tbCost.Text = "" Then
cost = 0
Else
cost = Me.tbCost.Text
End If
Notes = Me.tbNotes.Text
other = Me.tbOther.Text
If Me.lbItemList.listCount = 0 Then
x = 0
End If
With Me.lbItemList
Me.lbItemList.ColumnCount = 8
.AddItem
.List(x, 0) = itemID
.List(x, 1) = brand
.List(x, 2) = description
.List(x, 3) = specLink
.List(x, 4) = listPrice
.List(x, 5) = cost
.List(x, 6) = Notes
.List(x, 7) = other
x = x + 1
End With
End Sub
Submit button -
Private Sub cbSubmit_Click()
Dim n As Long
Dim v As Long
Dim vTable() As Variant
Dim r As Long
Dim o As Long
Dim c As Long
Dim w As Variant
Set brandTable = dsheet.ListObjects(brandTableName)
o = 1
listAmount = lbItemList.listCount
v = brandTable.ListRows.Count
w = 0
For c = 1 To listAmount
If brandTable.ListRows(v).Range(, 1).Value <> "" Then
brandTable.ListRows.Add alwaysinsert:=True
brandTable.ListRows.Add alwaysinsert:=True
Else
brandTable.ListRows.Add alwaysinsert:=True
End If
Next
ReDim vTable(1000, 1 To 10)
For n = 0 To listAmount - 1
vTable(n + 1, 1) = lbItemList.List(n, 0)
vTable(n + 1, 2) = lbItemList.List(n, 1)
vTable(n + 1, 3) = lbItemList.List(n, 2)
vTable(n + 1, 5) = lbItemList.List(n, 4)
vTable(n + 1, 6) = lbItemList.List(n, 5)
vTable(n + 1, 7) = lbItemList.List(n, 6)
vTable(n + 1, 8) = lbItemList.List(n, 7)
If lbItemList.List(n, 3) = "" Then
ElseIf lbItemList.List(n, 3) <> "" Then
vTable(n + 1, 4) = lbItemList.List(n, 3)
End If
If n = 0 And brandTable.DataBodyRange(1, 1) <> "" Then
For r = 1 To brandTable.ListRows.Count
If brandTable.DataBodyRange(r, 1) <> "" Then
o = r + 1
' brandTable.ListRows.Add alwaysinsert:=True
End If
Next
End If
brandTable.ListColumns(1).DataBodyRange(n + o).Value = vTable(n + 1, 1)
brandTable.ListColumns(2).DataBodyRange(n + o).Value = vTable(n + 1, 2)
brandTable.ListColumns(3).DataBodyRange(n + o).Value = vTable(n + 1, 3)
brandTable.ListColumns(4).DataBodyRange(n + o).Value = vTable(n + 1, 4)
brandTable.ListColumns(5).DataBodyRange(n + o).Value = vTable(n + 1, 5)
brandTable.ListColumns(6).DataBodyRange(n + o).Value = vTable(n + 1, 6)
brandTable.ListColumns(7).DataBodyRange(n + o).Value = vTable(n + 1, 7)
brandTable.ListColumns(8).DataBodyRange(n + o).Value = vTable(n + 1, 8)
Next
brandTable.DataBodyRange.Select
Selection.Font.Bold = True
Selection.WrapText = True
brandTable.ListColumns(5).DataBodyRange.Select
Selection.NumberFormat = "$#,##0.00"
brandTable.ListColumns(6).DataBodyRange.Select
Selection.NumberFormat = "$#,##0.00"
Unload Me
End Sub
Remove Items button -
Private Sub cbRemoveItems_Click()
Dim intCount As Long
For intCount = lbItemList.listCount - 1 To 0 Step -1
If lbItemList.Selected(intCount) Then
lbItemList.RemoveItem (intCount)
x = x - 1
End If
Next intCount
End Sub
There is other code that does things for the other tabs but they don't interact with this tabs code.
I have already looked at a few examples of how to use Application.OnTime,
to check for progress within the cell before updating and wrote up an implementation but I'm not sure why it wont work.
I dont want to paste the whole thing here, because it may be more confusing than just looking at the subs within the workbook.
I was wondering if someone with experience with this type of thing would be willing to look at my code. I can pm the file I'm working on.
Here is the method that loads data into the shell sheet. Ideally the data will all load before the pattern_recogADR sub is run... otherwise there is an error.
Sub build_singleEquity()
'x As Long
Dim x As Long
x = 6
'Dim x As Long
'x = 4
Application.ScreenUpdating = False
Call DefineTixCollection 'creates table of inputs
'check
'Debug.Print TixCollection(4).ORD
'set up data points - from "Input" sheet
'Dim x As Long
'Dim path As String
'path = Sheets("Input").Range("V1").value
'For x = 1 To TixCollection.Count
Sheets("SingleEquityHistoryHedge").Activate
'clear inputs
Range("B2:B8").Clear
Dim Inputs() As Variant
Dim name As String
name = "SingleEquityHistoryHedge"
'insert new inputs
Inputs = Array(TixCollection(x).ADR, TixCollection(x).ORD, TixCollection(x).ratio, _
TixCollection(x).crrncy, TixCollection(x).hedge_index, TixCollection(x).hedge_ord, _
TixCollection(x).hedge_ratio)
Call PrintArray(2, 2, Inputs, name, "yes") ' prints inputs
Dim last_row As Long
last_row = Range("A" & Rows.count).End(xlUp).Row
Range("AN11") = "USD" & TixCollection(x).crrncy
Range("AA11") = "USD" & TixCollection(x).crrncy
' Dim sht_name As String
'Application.Run "RefreshAllStaticData"
BloombergUI.ThisWorkbook.RefreshAll
' sht_name = TixCollection(x).ADR
' Call Sheet_SaveAs(path, sht_name, "SingleEquityHistoryHedge") 'save collection of sheets
'Next x
'Call TriggerCalc
'check this out
Call pattern_recogADR(x + 4, 5, 13)
End Sub
Here is the pattern_recogADR sub.... as you can see I have tried a ton of different thing which are commented out.
Sub pattern_recogADR(pos As Long, pat_days As Long, sht_start As Long)
'
'Application.Wait Now + "00:00:20"
'Dim pat As pattern
'Dim tix As clsTix
Dim newTime As Date
newTime = Now + TimeValue("00:00:30")
Do While Not Now >= newTime
'add back in as parameters
'Dim pos As Long
Dim x As Long
'Dim pat_days As Long
'Dim sht_start As Long
'************************
'pos = 5
'pat_days = 5
'sht_start = 13
Sheets("SingleEquityHistoryHedge").Activate
'Sleep 20000 'sleeps
Dim st As Long
Dim st_num As Long
Dim st_end As Long
Dim count As Long
Dim patrn As Long
count = sht_start
Dim i As Long
Dim j As Long
Dim patPLUSret() As Variant
Dim k As Long
Dim z As Long
k = 2
z = 3
For j = 8 To 12
'**************************************
count = sht_start
st_num = sht_start
st_end = 13
If IsNumeric(Cells(count, j).value) Then
'sets default pattern to beginning cell value
' Debug.Print st_num
If Cells(st_num, j).value < 0 Then
For i = count + 1 To count + 1 + pat_days
If IsNumeric(Cells(i, j).value) Then
If Cells(i, j).value < 0 Then
st_end = i
'Debug.Print st_end
End If
Else
Exit For
End If
Next i
patrn = st_end - st_num
' Debug.Print count
' Debug.Print patrn
ReDim Preserve patPLUSret(k * 2 + 1)
patPLUSret(0) = Range("B2").value 'ADR
patPLUSret(1) = Range("B3").value 'ORD
patPLUSret(k) = patrn
patPLUSret(z) = Application.WorksheetFunction.Average(Range(Cells(st_num, j), Cells(st_end, j)))
' Debug.Print patPLUSret(j)
' Debug.Print patPLUSret(j + 1)
st_num = sht_start 'resets starting point to initial
st_end = sht_start
' For x = 4 To 6
' If Range("L" & x).value = "x" Then
' ReDim Preserve mac_array(x - 4)
' mac_array(x - 4) = Range("N" & x).value
' End If
' Next x
' check this out
'tix.arbPnl = patrn
'save to separate class for patterns
'TixCollection.Add tix, tix.ADR
'******************************
ElseIf Cells(st_num, j).value > 0 Then
For i = count + 1 To count + 1 + pat_days
If IsNumeric(Cells(i, j).value) Then
If Cells(i, j).value > 0 Then
st_end = i
End If
Else
st_end = st_num
Exit For
End If
Next i
patrn = st_end - st_num
ReDim Preserve patPLUSret(k * 2 + 1)
patPLUSret(0) = Range("B2").value 'ADR
patPLUSret(1) = Range("B3").value 'ORD
patPLUSret(k) = patrn
patPLUSret(z) = Application.WorksheetFunction.Average(Range(Cells(st_num, j), Cells(st_end, j)))
' Debug.Print patPLUSret(j)
' Debug.Print patPLUSret(j + 1)
st_num = sht_start 'resets starting point to initial
st_end = sht_start
' Debug.Print patrn
'pat.arbPnl = patrn
'save to separate class for patterns
End If
k = k + 2
z = z + 2
Else
count = count + 1
st_num = count
End If
'
' k = k + 1
'new_array = patPLUSret
Next j
' Debug.Print patPLUSret
Sheets("PatternADR_ORD").Activate
Range(Cells(pos, 1), Cells(pos, 10)) = patPLUSret
Loop
End Sub
If you wait or loop to simulate a wait in your second sub, it won't give the control back to the spreadsheet and your formulae won't update.
Instead of
Call pattern_recogADR(x + 4, 5, 13)
why don't you call:
Application.onTime "'pattern_recogADR ""x + 4"", ""5"", ""13""'"