Trying to get vba to "loop until" with a count - vba

I'm trying to get the code to read a value from an Input box which is the desired investment amount ie. 3000. Then to read down a list (40 rows long) of the amount of btc available at a particular price, and consecutively sum up these total dollar amounts (quantity*price) going down the list until the point where adding the next line would be greater than the desired investment amount (ie. I'm trying to see the cheapest way to acquire a bunch of btc).
I'll then write a bit to make it make up the rest of the value from the next line as it obviously won't be reached perfectly but I can't seem to get this bit to work. When I execute the code I'm getting some weird results that don't make much sense. I've put an example of a table in so you can see what I'm working with (The first price 94.25 is B3/ActiveCell)
This is probably extremely trivial but I've never done any of this stuff before. Thanks for your time and I hope I've outlined it clearly enough.
Sub Projected()
Dim InvestValue As Single
Dim SumBTCE As Single
Dim Sumup As Single
Dim NumBTC As Single
Dim Count As Integer
InvestValue = InputBox("Input investment amount:")
NumBTC = 0
Sumup = 0
ActiveWorkbook.Sheets("BTC-E Data").Cells(3, 2).Select
Do Until (Sumup + (ActiveCell.Offset(Count, 0).Value * ActiveCell.Offset(Count, 1).Value)) >= InvestValue
For Count = 1 To 40
Sumup = Sumup + ActiveCell.Offset(Count - 1, 0).Value * ActiveCell.Offset(Count - 1, 1).Value
NumBTC = NumBTC + ActiveCell.Offset(0, 1).Value
Next Count
Loop
MsgBox NumBTC
MsgBox Sumup
End Sub
price BTC USD
94.25 0.1 9.425
94.439 0.34583324 32.66014535
94.44 2 188.88
94.443 0.011 1.038873
94.444 0.4 37.7776
94.493 0.025 2.362325
94.5 0.1 9.45
94.55 0.1 9.455
94.6 0.1 9.46
94.601 0.5 47.3005
94.648 0.0112 1.0600576
94.649 4.12801098 390.7121112
94.65 35.75926753 3384.614672
94.664 2.128011 201.4460333
94.665 3.5 331.3275
94.679 0.1395 13.2077205
94.68 0.15 14.202
94.689 2.128011 201.4992336
94.69 18.73708352 1774.214439
94.698 0.010978 1.03959464
94.699 0.093 8.807007
94.7 0.1 9.47
94.704 0.025 2.3676
94.736 0.0837 7.9294032
94.737 0.09 8.52633
94.749 2.128011 201.6269142
94.75 20.1 1904.475
94.755 0.1 9.4755
94.8 0.1 9.48
94.801 0.03758691 3.56327665
94.81 5.7236763 542.66175
94.829 0.15 14.22435
94.84 0.20095058 19.058153
94.85 0.1 9.485
94.87 0.01 0.9487
94.879 0.401 38.046479
94.88 0.01 0.9488
94.887 0.40930425 38.83765236
94.89 0.01 0.9489
94.9 0.30106377 28.57095176

Here's how I'd do it:
A2 contains your goal, e.g., $3000.
C2:E41 contains your data
F2 formula:
=SUMPRODUCT((C$2:C2*D$2:D2))
G2 formula:
=SUM(F$2:F2)>=$A$2
H2 formula:
=IF(G2,MAX(0,$A$2-SUM(F$1:F1)),D2)
Then copy the formulas down.
You could combine these formulas, but it's easier to follow this way.

Try the code below
Sub Projected()
Dim InvestValue, SumBTCE, Sumup, NumBTC As Single
Dim Count, LastRow, BTC, Price As Integer
InvestValue = InputBox("Input investment amount:")
NumBTC = 0
Sumup = 0
With Worksheets("BTC-E Data")
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row 'finding the last row in column 2
End With
For Count = 3 To LastRow
Price = ActiveWorkbook.Sheets("BTC-E Data").Range("B" & Count).Value
BTC = ActiveWorkbook.Sheets("BTC-E Data").Range("C" & Count).Value
Sumup = Sumup + (Price * BTC)
NumBTC = NumBTC + BTC
If Sumup >= InvestValue Then Exit For
Next
MsgBox NumBTC
MsgBox Sumup
End Sub
Output of the above code
NumBTC = 100.2461
Sumup = 9520.399976

Related

VBA omitting last outer loop

I am requesting assistance as to why the last outer loop of the following code is omitted. This code is part of a healthcare simulation, which uses VBA to iterate through combinations of parameters to generate sensitivity analyses. I have 3 other sensitivity analyses operating without issue. Notably, the sub call_transplant_surv is a highly conserved program that operates without issue in many other operatiions not shown here. I have tried skeletonizing the code to isolate the issue without success. I have not noted an error on the sheets that would cause failure at certain values of txp1b.
Sub twoway1()
'delay in list and 1B VAD txp rate
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.DisplayStatusBar = False
Dim i As Long, j As Long, counter As Long
Dim prob_bin As Byte, delay_list As Byte, status_2_bin As Byte, elective_days As Byte, first_day As Byte
Dim timestart As Double, timeall As Double, twoway1 As Integer, twoway2 As Integer, delay_i As Integer
'begin time counter
timestart = Time
'set values
prob_bin = 0 'probabilistic model = 1
delay_list = 0 'set to to begin at 30 given loop
status_2_bin = 0 'normal values = 0
elective_days = 30 'fixed value of 1A days allowed
first_day = 30 'first day elective time is used, incremented in the macro w/o a variable
posttxp_death = 1
twoway1 = 1
twoway2 = 0
txp1b = 0
delay_i = 0
time_measure = 0 'measurement time (e.g. at 0 days all parameters are measured, 30 days all measured, etc.)
timemeas_inc = 30 'increment of the measurement time (e.g. every 30 days- 30, 60, 90,....
counter = 1
'enter settings into model
Sheets("settings").Range("C27").Value = prob_bin
Sheets("settings").Range("C28").Value = delay_list
Sheets("settings").Range("C29").Value = status_2_bin
Sheets("settings").Range("C30").Value = elective_days
Sheets("settings").Range("C31").Value = first_day
Sheets("settings").Range("C32").Value = posttxp_death
Sheets("settings").Range("C44").Value = twoway1
Sheets("settings").Range("C45").Value = twoway2
calculate
'enter two loops to control the parameters
'enter two loops to control the parameters
For txp1b = 0.05 To 0.3 Step 0.05
For delay_i = 0 To 360 Step 90
Sheets("settings").Range("C31").Value = delay_i + 30
Sheets("settings").Range("C28").Value = delay_i
Sheets("1B>TXP Weib").Range("J20").Value = txp1b
calculate
'transplant survival calcs
call_txp_surv
'enter measurement loop
For i = 1 To 61
'place time measured
Sheets("settings").Range("AD4").Value = time_measure
'speed up calcs part 2
calculate
'record simulation results into sheet delay_list Row/column
Sheets("twoway1").Activate
Sheets("twoway1").Range(Cells(counter + 1, 1), Cells(counter + 1, 45)).Value = Sheets("settings").Range("M4:BE4").Value
'increment the time point for data recording
time_measure = time_measure + timemeas_inc
'increment counter for correct placement of next loop of results
counter = counter + 1
Next i
time_measure = 0
Next
Next
time_all = Time - timestart
'Sheets("twoway1").Range("AU2").Value = time_all
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayStatusBar = True
End Sub
The issue is using a non-integer loop counter - my guess is that the loop is exiting early because of a floating point error:
Private Sub Example()
Dim i As Double
For i = 0.05 To 0.3 Step 0.05
Debug.Print i
Next
End Sub
My recommendation would be to use integer iterations and then calculate the working value separately:
Dim i As Long
For i = 1 To 6
txp1b = i * 0.05
'...
Next

Syntax error while executing if and select statement in vba

I am learning basic VBA. When executing the below program in Excel 2013, I am getting a syntax error every time.
Sub ShowDiscount3()
Dim Quantity As Integer
Dim Discount As Double
Quantity = InputBox(“Enter the quantity “)
Select Case Quantity
Case 0 To 24
Discount = 0.1
Case 25 To 49
Discount = 0.15
Case 50 To 74
Discount = 0.2
Case Is >= 75
Discount = 0.25
End Select
MsgBox “Discount: “ & Discount
End Sub
Do not use: “
Use " instead:
Sub ShowDiscount3()
Dim Quantity As Integer
Dim Discount As Double
Quantity = InputBox("Enter the quantity")
Select Case Quantity
Case 0 To 24
Discount = 0.1
Case 25 To 49
Discount = 0.15
Case 50 To 74
Discount = 0.2
Case Is >= 75
Discount = 0.25
End Select
MsgBox "Discount: " & Discount
End Sub

sorting data by date with excel

I have raw data I'm trying to sort out by date, the data is in this form:
month:april-2014
offer | value
ofr x | 2132
ofr y | 135
.
.
.
month:mai-2014
offer | value
ofr x | 5115
ofr z | 513
ofr y | 651
and it goes on, there are offers that apear every month and others that dissapear.
I wanted it to look like this :
offer | april-2014 |mai 14 | june ....
ofr x 123 5 6
ofr y 5 1 6
ofr z
ofr a
.
.
any help would be appreciated, thank you
Try to restructure the data like this and use pivot tables?
Date | offer | value
may-2014 |ofr x | 5115
may-2014 |ofr z | 513
may-2014 |ofr y | 651
This first chunk of code is going through and rearranging things for you. The other important thing it does is only sends one column from your selected range to the function. Some important things to remember are you may need to write the search criteria if you key word for "month" is not in the same spot in the text, the word offer is not by itself with no spaces in the following row. Another point of note, is this is treating everything as is. That means if the source cell was text, then the destination cell will be text. To convert from date as text to date as Excel serial that is a separate issue and there are plenty of ways to achieve that as well.
Option Explicit
Sub SortOffer(OfferList As Range)
Dim CounterX As Long, CounterY As Long, jCounter As Long, icounter As Long, MonthCount As Long, UniqueOffers As Long
Dim inlist As Boolean
Dim unsorted() As Variant
Dim sorted() As Variant
MonthCount = WorksheetFunction.CountIf(OfferList, "month*")
UniqueOffers = CountUnique(OfferList.Columns(1).Cells) - MonthCount - 1
ReDim sorted(1 To UniqueOffers + 1, 1 To MonthCount + 1) As Variant
unsorted = OfferList
CounterX = 1
jCounter = 1
sorted(1, 1) = "offer"
For CounterY = LBound(unsorted, 1) To UBound(unsorted, 1)
If Left(unsorted(CounterY, 1), 5) = "month" Then
CounterX = CounterX + 1
sorted(1, CounterX) = Right(unsorted(CounterY, 1), Len(unsorted(CounterY, 1)) - 6)
Else
inlist = False
For icounter = 2 To jCounter
If unsorted(CounterY, 1) = sorted(icounter, 1) Then
sorted(icounter, CounterX) = unsorted(CounterY, 2)
inlist = True
End If
Next icounter
If Not inlist And unsorted(CounterY, 1) <> "offer" And unsorted(CounterY, 1) <> "" Then
jCounter = jCounter + 1
sorted(jCounter, 1) = unsorted(CounterY, 1)
sorted(jCounter, CounterX) = unsorted(CounterY, 2)
End If
End If
Next CounterY
Range("F1").Resize(UBound(sorted, 1), UBound(sorted, 2)).Value = sorted
End Sub
This next function counts the number of unique entries in a range and does not count spaces. I stumbled across this code on this web page. If you subtract the number of months from this count, you will know how many offers are in your table. This is important because it will tell you how to size your array(alt link) that you will later write back as your results
Function CountUnique(ByVal MyRange As Range) As Integer
Dim Cell As Range
Dim J As Integer
Dim iNumCells As Integer
Dim iUVals As Integer
Dim sUCells() As String
iNumCells = MyRange.Count
ReDim sUCells(iNumCells) As String
iUVals = 0
For Each Cell In MyRange
If Cell.Text > "" Then
For J = 1 To iUVals
If sUCells(J) = Cell.Text Then
Exit For
End If
Next J
If J > iUVals Then
iUVals = iUVals + 1
sUCells(iUVals) = Cell.Text
End If
End If
Next Cell
CountUnique = iUVals
End Function
Now just in case the links don't cover it, this answer which was a learning lesson for me was taught in various parts to me by #JNevill, #Ralph, #findwindow, #Gary'sStudent and #ScottCraner. Appologies if I missed someone. I am also sure any of these individuals could do it slicker and take less then 10 hours to write it 8).

Random Sampling & Selection by Category VBA

I am trying to write a macro on MS Excel, which will enable me to create random samples and pick random values from those samples for each category in the data.
To be more specific, the data is at 2 levels: firm and year, where each row represents a firm-year-peer observation. For each firm i, at a given year j, we have number of actual peers.
What I want to do is assign to each firm, from the whole sample throughout many years, a random firm from the list of all available firms at that specific year. The trick is that the number of firms to be assigned should be identical to the number of actual peers that a firm has at that year. Also, the randomly assigned values should be different from the firm's actual peers, and of course, the firm itself.
i j k
1 2006 100
1 2006 105
1 2006 110
2 2006 113
2 2006 155
2 2006 200
2 2006 300
For example, Firm 1's actual peers in year 2006 are 100, 105 and 110. However, all possible firms available are 100, 105, 110, 113, 155, 200 and 300. This means that I have to select 3 (because Firm 1 has 3 actual peers) random fictional peers from the 4 firms that are not Firm 1's peer that year (i.e. 113, 155, 200 and 300). Applying the same procedure for Firm 2, I need to select 4 random firms that are not Firm 2's actual peers from all possible firms.
I hope this was clear.
I started trying this function out on MS Excel, but I am open to suggestions if you think other platforms would be more useful.
Your help would be very much appreciated!
Thanks!
Many thanks to everyone who has visited my post.
After some initial struggling, I have managed to figure out the code myself. I am posting it below for anyone who might need it.
Basically I used the randomisation code posted by this gentle soul, and enhanced it for my needs using couple of flags for each new firm and each new year. Hope it is clear for everyone.
Best
Sub Random_Sampling()
'
Dim PeerCount, FirmCount, YearCount As Long
Dim Focal_CIK, fiscalYear As Long
Const nItemsTotal As Long = 1532
Dim rngList As Range
Dim FirmYearRange As Range
Dim FirmStart, FirmStartRow, YearStartRow As Long
Dim ExistingPeers As Range
Dim idx() As Long
Dim varRandomItems() As Variant
Dim i, j, k, m, n As Long
Dim iCntr, jCntr As Long
Dim booIndexIsUnique As Boolean
Set rngList = Sheets("Sheet2").Range("A2").Resize(nItemsTotal, 1)
FirmCount = Cells(2, 10).Value
For k = 1 To FirmCount
FirmStart = Application.WorksheetFunction.Match(k, Columns("E"), 0)
Focal_CIK = Cells(FirmStart, 1).Value
YearCount = Cells(FirmStart, 7).Value
For m = 1 To YearCount
Set FirmYearRange = Range("H" & FirmStart & ":H200000")
YearStartRow = Application.WorksheetFunction.Match(m, FirmYearRange, 0) + FirmStart - 1
fiscalYear = Cells(YearStartRow, 3).Value
PeerCount = Cells(YearStartRow, 9).Value
Set ExistingPeers = Range(Cells(YearStartRow + PeerCount, 2), Cells(YearStartRow + PeerCount, 2))
ReDim idx(1 To PeerCount)
ReDim varRandomItems(1 To PeerCount)
For i = 1 To PeerCount
Do
booIndexIsUnique = True ' Innoncent until proven guilty
idx(i) = Int(nItemsTotal * Rnd + 1)
For j = 1 To i - 1
If idx(i) = idx(j) Then 'Is already picked
ElseIf idx(i) = Focal_CIK Then 'Is the firm itself
booIndexIsUnique = False 'If true, don't pick it
Exit For
End If
For n = 1 To PeerCount
If idx(i) = Cells(YearStartRow + n - 1, 2).Value Then 'Is one of the actual peers
booIndexIsUnique = False 'If true, don't pick it
Exit For
Exit For
End If
Next n
Next j
If booIndexIsUnique = True Then
Exit Do
End If
Loop
varRandomItems(i) = rngList.Cells(idx(i), 1)
Rows(YearStartRow + PeerCount).EntireRow.Insert
'The order of the columns are very important for the following lines
Cells(YearStartRow + PeerCount, 1) = Focal_CIK
Cells(YearStartRow + PeerCount, 2) = varRandomItems(i)
Cells(YearStartRow + PeerCount, 3) = fiscalYear
Cells(YearStartRow + PeerCount, 4) = "0"
Next i
Next m
Next k
End Sub

I cant get the loop right

Ok I have got this far and if you run it, it will do what you ask. Now when I type in 99999 or -99999 it will not end. Can someone tell me what I am doing wrong. I am suppose to loop until a sentinel value of -99999 is enter for previous meter reading.
Sub Main()
' program to compute a consumer’s electric bill. It will calculate the bill for one or more customers
' by looping until a sentinel value of -99999 is entered for the previous meter reading.
Dim previousReading As Integer = 0
Dim currentReading As Integer = 0
Do While (previousReading <> -99999)
Dim salesTax As Double
' prompt user to input value for previous reading then convert to integer
Console.WriteLine("Enter the value of previous meter reading")
previousReading = Convert.ToInt32(Console.ReadLine())
' prompt user to input value for current reading then convert to integer
Console.WriteLine("Enter the value of current meter reading")
currentReading = Convert.ToInt32(Console.ReadLine())
Dim kwhConsumed As Integer
Dim electricCharge, totalBill As Double
' calculate KWH consumed
kwhConsumed = currentReading - previousReading
' Use select case to determine electricCharge
Select Case kwhConsumed
Case Is < 500
electricCharge = kwhConsumed * 0.05
Case 500 To 1000
electricCharge = 25 + ((kwhConsumed - 500) * 0.055)
Case Is > 1000
electricCharge = 52.5 + ((kwhConsumed - 1000) * 0.06)
End Select
' calculate sales tax
salesTax = electricCharge * 0.085
' calculate total charges
totalBill = electricCharge + salesTax
' Output values for kwhConsumed, electricCharge, salesTax, and totalBill
Console.WriteLine("KWH consumed = " & kwhConsumed & " KWH")
Console.WriteLine("Electric charge = $" & Math.Round(electricCharge, 2))
Console.WriteLine("Sales tax = $" & Math.Round(salesTax, 2))
Console.WriteLine("Total bill = $" & Math.Round(totalBill, 2))
Loop
End Sub
You can try using string comparison instead for previousReading <> -99999. You also need to use absolute value to consider both -99999 and 99999. Do something like this
Do While (previousReading <> 99999)
//code
previousReading = Math.Abs(Convert.ToInt32(Console.ReadLine()))
//code
Loop
I'm guessing this is homework?
Instead of blurting out the answer, I wonder if you might think about inserting a Debug.Print statement and some kind of "break" statement after your previousReading = Convert.ToInt32 statement. To look for the "break" statement, search for "vb.net exit loop" and see what pops up.