Should I be using something else besides GoalSeek? - vba

Background, so I need to optimize daily sales without exceeding daily capacity and without going over a End of the period(EOP) total capacity. So I thought the code was working fine then I realized all it's doing is taking daily capacity to 0 until my EOP capacity reaches my target. So it's basically all or nothing so sometimes my target doesn't get hit. i.e your off by 150 units from EOP target but your daily capacity is all 200+ so it never hits the target I want. (I should mention sales could be negative)
So is goal seek what I really want? Can I set Goal to be a range(eg -10 to 10) maybe?
Sub cashPark()
Set enddate = Sheets("Cash").Range("E4")
Set Window = Sheets("Cash").Range("D8")
Set TargetWindow = Sheets("Cash").Range("D14")
Set datecount = Sheets("Cash").Range("E4")
Set cashParkVol = Sheets("Inventory").Range("BW1")
Set Repeate = Sheets("Cash").Range("E5")
cashParkVol.Offset(datecount, -2).GoalSeek _
Goal:=0 And Window.Value = TargetWindow, _
ChangingCell:=cashParkVol.Offset(datecount, 0)
Let x = 0
Do While x < Repeate
cashParkVol.Offset(datecount + x, -2).GoalSeek _
Goal:=0 And Window.Value = TargetWindow, _
ChangingCell:=cashParkVol.Offset(datecount + x, 0)
x = x + 1
Loop
End Sub
Sorry for the constant questions but I'm just getting more involved with VBA and I'm loving it so I'm trying to automate everything I can.

The Solver is the tool of choice for optimizing in Excel and it can be run from VBA. If you are not familiar with the tool, you should probably first figure out how to use it in Excel for your problem and then figure out how to automate it with VBA. Frontline System wrote and maintains the Solver Add-in and their website has some tutorials and examples. There are a number of books (e.g. "Spreadsheet Modeling and Decision Analysis" by Cliff Ragsdale) about using the solver. Ragsdale's book has examples involving clash-flow problems. If you really want to become a power-user with scripting the Solver with VBA, I recommend the book "VBA for Modelers" by S. Christian Albright since it is the only book that I know of that really focuses on solutions built around the Solver.

Related

Putting "Align at equals" into a macro

I'm working on a Word Macro to streamline doing my University Mathematics and Statistics Coursework. Basically, selecting a group of equations and running it changes font size, line height and formats the paragraph in the way that I want to be common to all my maths/equations sections. It's great, but there's one little bit which I still have to do "manually", so to speak, which is right clicking and selecting "Align at equals".
Now the reason I'm asking this here and not on Super User is that I think I've exhausted all ways of doing this at the "record macro" stage. I found out how to access the right click menu without right clicking and accessed the "align at equals" option during record. Nothing was recorded.
Truth be told I'd prefer to code the lot anyway as it gives me more control. So, I'll post my code here and if anyone knows what line(s) of code I need to add to get it to replicate the "align at equals" command I would be extremely grateful.
Sub Equationiser()
'
' Equationiser Macro
'
'
With Selection.ParagraphFormat
.SpaceBefore = 12
.SpaceAfter = 12
.LineSpacingRule = wdLineSpace1pt5
End With
Selection.Font.Size = 20
End Sub
So, ideally just before the "With Selection.ParagraphFormat" section there would be some kind of "AlignAtEquals" command or whatever is needed so that, on one keypress, I would be able to align all the equals, set the line height to 1.5, place a 12 point space before and after the paragraph and change the font size to 20.
My absolute ideal would also be to programatically select all equation boxes that are in the same block, as "align at equals" is notoriously fussy and finicky as to when it will execute. That might also mean there may be a try and catch needed depending on whether trying to run "align at equals" when it wouldn't normally be available from the right click menu would do nothing or cause an error.
Any help on these two implementations would be gratefully appreciated but I'd happily settle for just the first.
I've built a solution that should address your needs, based on:
Looking through the equation to find the equal-sign.
Get the location of that equal-sign
Use that location to set the AlignPoint property of the OMath object
that is your equation
Use this MSDN reference if you want to explore more
Sub Equationiser()
'
' Equationiser Macro
'
'
Dim equationCounter As Long, charLoc As Long, FormattedTextLoc As Long
With Selection
For equationCounter = 1 To .OMaths.Count:
FormattedTextLoc = 0
For charLoc = 1 To Len(.OMaths(equationCounter).Range.FormattedText):
FormattedTextLoc = FormattedTextLoc + Len(.OMaths(equationCounter).Range.FormattedText.Characters(charLoc))
If .OMaths(equationCounter).Range.FormattedText.Characters(charLoc) = "=" Then
.OMaths(equationCounter).AlignPoint = (FormattedTextLoc - 1)
Exit For
End If
Next charLoc
Next equationCounter
End With
With Selection.ParagraphFormat
.SpaceBefore = 12
.SpaceAfter = 12
.LineSpacingRule = wdLineSpace1pt5
End With
Selection.Font.Size = 20
End Sub
I've done some brief testing that from what I can see this should be able to manage several code-blocks, i.e. when selecting 2 code-blocks it will align-at-equals all equations in the first block, then align-at-equals all equations in the second block (both blocks are not aligned with each oter) - is this your desired outcome to your request: My absolute ideal would also be to programatically select all equation boxes that are in the same block, as "align at equals" is notoriously fussy and finicky as to when it will execute.

Why when running hundreds of VBS files at once, only about 50 or so succeed each time

I've got a list of about 600 products where I need to get inventory data.
I can get this per product from an internal site, where I copy a table that shows specifically where the products are stored (warehouse, location).
Since VBA webscraping would do this in serial it takes around 10~15 minutes to get all 600.
I can make this time a lot shorter by doing it parallel via VBScript.
My VBA code dynamically creates the VBScript below that pulls the data and puts it back into the Excel sheet.
It works, but only for 50~60 products at a time, no matter how many VBScript files I launch. The rest fails and doesn't return output or doesn't put it into the sheet.
Does anyone know any reason why this might happen?
Is there something I can do to adjust my vbscript code so more will succeed?
Thanks for any help!
VBSCRIPT:
Dim oXML, oXL, product, sHTML, tabl, x, y
On Error Resume Next
Set oXL = GetObject(, "Excel.Application")
Set oXML = Wscript.CreateObject("WinHttp.WinHttpRequest.5.1")
oXML.Open "GET", "internal-site", False
oXML.SetAutoLogonPolicy AutoLogonPolicy_Always
oXML.send
sHTML = oXML.responseText
x = InStr(sHTML, "<table cellpadding=1 border=0 cellspacing=0 align=center>")
y = InStr(sHTML, "</table><br>") + 8
tabl = Mid(sHTML, x, y - x)
RandomNumber = Int(Rnd * 500)
Wscript.Sleep RandomNumber
oXL.workbooks("a3.xlsb").sheets("A").Cells(8, 3) = Mid(tabl, 1, 32767)
oXL.workbooks("a3.xlsb").sheets("A").Cells(8, 4) = Mid(tabl, 32768, 32767)
To emphasize chris' point: Test your task with the EVIL global OERN removed/disabled. As the OERN hides errors and lets your script continue in an undefined state, there should be a law "don't ask questions based on an active global OERN here".
Use the taskmanager to monitor your task: Any Excel zombies? Memory exhaustion?
The .Status of the WinHttpRequest should be checked.
The results of both InStr() calls should be checked - especially if you use them in a substraction (y - x) in a Mid() call.
The timeout after the Mid() call makes no sense (Mid() won't return before the substring is ready); doing a random wait for a resource is a bad idea in general [(c) sancho].
Post all relevant code: Surely the are calls to .Save, .Close and .Quit? Do you really write everything to the same workbook, sheet, cell [(c) AnalystCave]?
Consider: Isn't starting 600 simultaneous requests on your server a DOS attack?

Recalculate a variable on change event without duplicate code

I'm making a small app that handles pricing and quotes for cloud services.
On one of my forms, I work out some pricing info in the 'me.shown' bit.
The prices for various items are read in from a mysql database on app launch, so i've already got all that info.
My price working out code is as follows:
calc_vmCPUprice = vmcpuprice * cpuslider.Value
calc_vmHDDprice = vmhddprice * hddslider.Value
calc_vmRAMprice = vmRAMprice * memoryslider.Value
If requirebackup.Checked = True Then
calc_backupsetupfee = vmbackupsetupfeecost
calc_backupfee = vmbackupcostperGB * sliderbackup.Value
End If
If supportcheck.Checked = True Then
calc_supportfee = vmsupportfee
End If
vmmonthlycost = calc_vmCPUprice + calc_vmHDDprice + calc_vmRAMprice + calc_backupfee + calc_backupsetupfee + calc_supportfee
vm_monthlycost.Text = "£" & vmmonthlycost
I need to make my program re-calculate the 'vmmonthlycost' variable each time an item is changed.
So for example if you change the slider for cpu (cpuslider.value) then the price will obviously change as the 'calc_vmCPUprice' variable will now be different.
I dont want to copy and paste the calculation code into the change event of each item, as this will be messy and any future changes will need to be mirrored across all items etc.
What would you guys recommend as the best way of achieving this recalculation of price?
I would ideally like to take that bit of code and seperate it then call it from each change event, but as I tinker with vb as a hobbyist more than anything else, my knowledge is still limited.
Thanks in advance!!

Vb.net + SQL Server : Speed difference using float vs Decimal

I'm using VB.net 2013 and SQL server 2008R2.
I'm writing a financial application , and I'm not sure about which data type to use.
I know that decimal is more precise than float , but I read that using decimal can significantly decrease the speed of calculations , so the speed of my application.
I read that using decimals can be 20 times slower than using float.
Is this true , and if yes is there a solution or should I continue to use float ?
Thank you !
Use decimal for financial applications, period. Speed does not matter in this case. When money is lost, your users won't be happy. You cannot argue saying "well, but on the other hand, it was fast". Regarding 20 times difference on float vs decimal, trust me, you won't feel it at all, there will be more major factors in your app's performance. Most likely trying to synchronize transactions between each other, DB locks etc.
EDIT: Regarding 20 times performance difference, this is true, I was able to reproduce with below code:
Module Module1
Sub Main()
Dim f As Single = 123456792.0F
Dim fsw As New Stopwatch
fsw.Start()
For i = 1 To 100000000
f *= 1.00000012F
Next
fsw.Stop()
Dim dsw As New Stopwatch
dsw.Start()
Dim d As Decimal = 123456792.0F
For i = 1 To 100000000
d *= 1.00000012F
Next
dsw.Stop()
Console.WriteLine(f)
Console.WriteLine("Float (ms): " & fsw.ElapsedMilliseconds)
Console.WriteLine(d)
Console.WriteLine("Decimal (ms): " & dsw.ElapsedMilliseconds)
Console.WriteLine("Float is " & dsw.ElapsedMilliseconds / fsw.ElapsedMilliseconds & " faster")
Console.ReadLine()
End Sub
End Module
Output:
While writing this code, I got anywhere between 10-20 times for different numbers. As I mentioned before, speed is not the concern, compare the accuracy of both approaches, notice how float is off by several orders of magnitude. This is, of course, a synthetic example, but it shows how people may end up with 1 dollar on their payroll instead of a 1000 - imagine the reaction.

how to get time to the extent of exact millisecond in vb.net

I am developing an application that is very very time critical. I want to put a log writer in the code so that i can track the events and find out where the application is wasting the time.But the problem is that vb.net tells the time only at a interval of 15.25 milliseconds what to do. although msdn documentation says that we can get the time in millisecond.
To understand my problem better pls go through the following code. this code is written on a click event of a button and it writes down the time in a log file.
the problem is that it writes time like 16,16,16 and after some time when the dx value reaches to say 5000 it jumps to 31 and then to 46 and so on. Can anyone explain.
dx = 1
While dx <= 100000
dx = dx + 1
SRLog1.WriteLine("dx vALUE > " & CStr(dx) & " Ticks -> " + CStr(Now.Millisecond))
End While
You can create an incremental clock with much higher resolution by using the Stopwatch class. For example:
Dim sw = Stopwatch.StartNew()
Dim start = sw.Elapsed
'' Do stuff
'' ...
Dim sample = sw.Elapsed
Console.WriteLine(sample - start)
This is still not likely to work out that well for the code in your snippet, incrementing an integer takes less than half a nanosecond. You'll actually measure how long it takes to log, that ought to be slow enough to get different output values.
If you want to find out which parts of your application are waisting time, then you should try using a profiler. Two possible products would be JetBrains dotTrace and RedGates ANTS. You should also take a look at this question here.