mitesh114
asked on
Call C# function in Excel VBA; not working
Hi,
I am implementing a COM interface in C#.NET to be used in Excel. My C# class inherits from two different interfaces, both of which have Guid attributes as shown below (i have simplified the classes):
using System;
using System.Collections.Generic ;
using System.Text;
using System.Runtime.InteropServ ices;
namespace Test
{
[Guid("92AF729B-299C-4d1b- 928F-F148E 43C061C")]
public interface ITrade
{
void AddTradeCharge(TradeCharge tradeCharge);
bool ValidateTrade();
}
[Guid("DF8B55FE-FFCF-402e- ADEE-9298E 3B0CBE4")]
public interface IDataContainer
{
bool Load();
}
[Guid("1D67F24F-7B62-42d1- 86C3-BF925 87E3FA9")]
[ClassInterface(ClassInter faceType.N one)]
[ComSourceInterfaces(typeo f(IDataCon tainerEven ts))]
public class Trade : DataObject, IDataContainer, ITrade
{
public Trade() {}
private TradeSet mcharges;
public TradeSet TradeCharges
{
get{ return mcharges;}
set(mcharges = value; }
}
public bool ValidateTrade()
{
return ExecuteCommand("InsertTrad eOnly", true, true, false);
}
public void AddTradeCharge(TradeCharge tradeCharge)
{
TradeCharges.Add(tradeChar ge);
}
public void Load()
{
//some code
}
}
}
The problem that i have is when i call ValidateTrade from Excel VBA, it doesn't actually run the function and i get the following error: Object doesn't support this property or method.
The other problem is that when i call .AddTradeCharge (dtTradeCharge) in VBA, i have a compile error which says "argument not optional". I have been working on this for absolute AGES! I have tried recompiling the C# code, re-registering the assembly and adding the reference to the tlb in Excel again and restarting my machine, but to no avail.
Also, I am not seeing all of my exposed methods from both interfaces in intellisense. If i remove ITrade interface from the Trade class, then in Excel the intellisense shows IDataContainers methods and if i leave remove IDataContainer and leave ITrade then intellisense shows ITrade methods. Is there a way to
around this problem?
I have run these methods using NUnit to test that they do work and I get the correct outputs.
Please help! It is very frustrating!
Many Thanks
I am implementing a COM interface in C#.NET to be used in Excel. My C# class inherits from two different interfaces, both of which have Guid attributes as shown below (i have simplified the classes):
using System;
using System.Collections.Generic
using System.Text;
using System.Runtime.InteropServ
namespace Test
{
[Guid("92AF729B-299C-4d1b-
public interface ITrade
{
void AddTradeCharge(TradeCharge
bool ValidateTrade();
}
[Guid("DF8B55FE-FFCF-402e-
public interface IDataContainer
{
bool Load();
}
[Guid("1D67F24F-7B62-42d1-
[ClassInterface(ClassInter
[ComSourceInterfaces(typeo
public class Trade : DataObject, IDataContainer, ITrade
{
public Trade() {}
private TradeSet mcharges;
public TradeSet TradeCharges
{
get{ return mcharges;}
set(mcharges = value; }
}
public bool ValidateTrade()
{
return ExecuteCommand("InsertTrad
}
public void AddTradeCharge(TradeCharge
{
TradeCharges.Add(tradeChar
}
public void Load()
{
//some code
}
}
}
The problem that i have is when i call ValidateTrade from Excel VBA, it doesn't actually run the function and i get the following error: Object doesn't support this property or method.
The other problem is that when i call .AddTradeCharge (dtTradeCharge) in VBA, i have a compile error which says "argument not optional". I have been working on this for absolute AGES! I have tried recompiling the C# code, re-registering the assembly and adding the reference to the tlb in Excel again and restarting my machine, but to no avail.
Also, I am not seeing all of my exposed methods from both interfaces in intellisense. If i remove ITrade interface from the Trade class, then in Excel the intellisense shows IDataContainers methods and if i leave remove IDataContainer and leave ITrade then intellisense shows ITrade methods. Is there a way to
around this problem?
I have run these methods using NUnit to test that they do work and I get the correct outputs.
Please help! It is very frustrating!
Many Thanks
ASKER
Hi Jell,
I'm using office 2003.
Private Function mf_DoTrades(ByVal blnCalculateOnly As Boolean, ByVal lngCurrentPage As Long, ByVal lngPageCount As Long) As eActionStatus
Dim strTradeBasis As String
Dim strDealType As String
Dim strBook As String
Dim strStock As String
Dim strBasketDesc As String
Dim strBasketRef As String
Dim strPriceType As String
Dim strNarrative As String
Dim dblNominal As Double
Dim dblPrice As Double
Dim dblCommission As Double
Dim strCommType As String
Dim strCommArg As String
Dim strTradeComm As String
Dim strSalesman As String
Dim strTradeDate As String
Dim strValueDate As String
Dim strExchange As String
Dim strBasketId As String
Dim lngCurrentRow As Long
Dim lngErrorTrades As Long
Dim lngWarningTrades As Long
Dim wsCurrent As Worksheet
Dim blnIsBasket As Boolean
Dim blnHasMultiTrades As Boolean
Dim bIgnoreCommCap As Boolean
Dim bIgnorePriceVariance As Boolean
Dim asTradeResult As eActionStatus
Dim lngTradeCount As Long
Dim lngRightmostColumn As Long
Dim lngResultColumn As Long
Dim lngSplitResultColumn As Long
Dim blnSplitsExist As Boolean
Dim rngCommCell As Range
Dim lngPageLoop As Long
Dim blnLoopPages As Boolean
Dim dblSplitRowTotal As Double
Dim lngPageOriginal As Long
Dim lngSplitColumn As Long
Dim sdSplitData As CSplitData
Dim blnSplitSuccess As Boolean
Dim blnAllocatedBasket As Boolean
Dim vntSplitAccts As Variant
Dim vntSplitNominalsOneRow As Variant
Dim vntSplitNominalsAll As Variant
Dim lngFirstRow As Long
Dim lngLastRow As Long
Dim strClient As String
Dim colTrades As Collection 'holds the trade data
Dim tdCurrentTrade As CTradeData 'holds the data for the trade currently being processed
Dim lCount As Long
Dim basket As basket
Dim dtTrader As trade
Dim dtSplitTrade As allocation
Dim dtTradeCharge As TradeCharge
'Set up error
On Error GoTo DoTradesError
err.Clear
With Application
.ScreenUpdating = False
Set wsCurrent = .ActiveSheet
.DisplayAlerts = False
.Calculation = xlCalculationManual
End With
Set colTrades = New Collection
lngTradeCount = mf_GetTradeCount(wsCurrent )
blnHasMultiTrades = (lngTradeCount > 1)
blnLoopPages = (lngPageCount > 0)
lngPageOriginal = lngCurrentPage
'
'now we retrieve the values from the various named ranges.
'
'************************* ********** ********** ********** ********** ********** ********** *********
'NOTE: It is of VITAL importance that the named ranges (e.g. "TRADE_BASIS", "BOOK_CODE", etc.)
'exist in the worksheet and also that they point to the appropriate cells or the macro will not work.
'************************* ********** ********** ********** ********** ********** ********** *********
'
'read "common" fields and assign their values to local variables
With wsCurrent
strTradeBasis = .Range("TRADE_BASIS").Valu e
strBook = UCase$(CStr(.Range("BOOK_C ODE").Valu e))
strClient = CStr(.Range("CPTY_CODE").V alue)
strSalesman = UCase$(CStr(.Range("SALESM AN").Value ))
strExchange = UCase$(CStr(.Range("EXCHAN GE").Value ))
strTradeDate = Format$(CDate(.Range("TRAD E_DATE").V alue), "yyyymmdd")
strValueDate = Format$(CDate(.Range("VALU E_DATE").V alue), "yyyymmdd")
strPriceType = UCase$(CStr(.Range("PRICE_ TYPE").Val ue))
strBasketDesc = CStr(.Range("BASKET_DESC") .Value)
strBasketRef = CStr(.Range("BASKET_REF"). Value)
'Should we ignore the difference between enterd price and market price?
If UCase$(CStr(.Range("IGNORE _LOCAL_PRI CE").Value )) = "Y" Then
bIgnorePriceVariance = True
Else
bIgnorePriceVariance = False
End If
'the trades will be 'basketed' only if the user has specified this in the "BASKET_FLAG" cell
'AND if there's more than one trade on the sheet
blnIsBasket = ((UCase$(Left$(CStr(.Range ("BASKET_F LAG").Valu e & " "), 1)) = "Y") _
And blnHasMultiTrades)
lngFirstRow = .Range("SUCCESS_HEADER").R ow + 1
.Range("BASKET_ID").ClearC ontents
lngResultColumn = .Range("SUCCESS_HEADER").C olumn
strCommType = CStr(.Range("COMMISSION_TY PE").Value & "")
strCommArg = CStr(.Range("COMMISSION_AR GUMENT").V alue & "")
lngSplitResultColumn = .Range("SPLIT_RESULT").Col umn
End With
lngLastRow = (lngFirstRow + lngTradeCount - 1)
ReDim vntSplitNominalsAll(lngFir stRow To lngLastRow)
lngErrorTrades = 0
lngWarningTrades = 0
blnAllocatedBasket = False
If blnIsBasket And (Not blnCalculateOnly) Then
'Avoid Generating BASKET_ID during validation
If strBasketRef = "" Then
strBasketRef = " "
End If
If strBasketDesc = "" Then
strBasketDesc = " "
End If
basket.SetObjectValue "BookId", strBook
basket.SetObjectValue "CounterpartyId", strClient
basket.SetObjectValue "DealtPriceType", strPriceType
basket.SetObjectValue "SettlementDate", strValueDate
basket.SetObjectValue "TradeDate", strTradeDate
basket.SetObjectValue "BasketType", "JP"
basket.SetObjectValue "TradeCount", lngTradeCount
basket.SetObjectValue "BasketReference", strBasketRef
basket.SetObjectValue "BasketDescription", strBasketDesc
End If
If blnLoopPages Then
Call ms_ShowSubAcctPage(lngCurr entPage, 0, False)
End If
'retrieve trades from worksheet
Do 'we have to go through the trades at least once, hence the Do/Loop While construct
For lngCurrentRow = lngFirstRow To lngLastRow
blnSplitsExist = False 'reset semaphore for next trade
With wsCurrent
'find out if there's any splits...
'find the rightmost column in use, if it's not at least as far across as
'the first split nominal column, then we know there's no splits for this trade
lngRightmostColumn = .Cells(lngCurrentRow, 256).End(xlToLeft).Column
If lngRightmostColumn >= .Range("FIRST_SUBACCT_NUMB ER").Colum n Then
'grab all of the columns, this way we guarantee that the variant will hold an array
'of values and not just a single value
'first, the account numbers...
vntSplitAccts = .Range(.Range("FIRST_SUBAC CT_NUMBER" ), .Cells(.Range("FIRST_SUBAC CT_NUMBER" ).Row, _
MAX_COLUMN_IN_USE)).Value
'... and then the nominals
vntSplitNominalsOneRow = .Range(.Cells(lngCurrentRo w, .Range("FIRST_SUBACCT_NUMB ER").Colum n), _
.Cells(lngCurrentRow, MAX_COLUMN_IN_USE)).Value
blnSplitsExist = True
dblSplitRowTotal = 0#
Else
vntSplitNominalsOneRow = Empty
End If
'at this point, vntSplitNominalsOneRow will be in one of two states:
' Empty, if no nominals are present
' 2-dimensional Array of strings (1,n) if one or more nominals are present
vntSplitNominalsAll(lngCur rentRow) = vntSplitNominalsOneRow
End With 'end of "With wsCurrent" block
If mf_GetNextTrade(wsCurrent, lngCurrentRow, strStock, dblNominal, dblPrice, strDealType, strTradeComm) Then
If lngPageLoop = 0 Then
'we're on the first page of subaccounts, then the trades need to be added to the
'trades collection
Set tdCurrentTrade = New CTradeData
With tdCurrentTrade
'reverse the buy/sell flag so that the users can interpret this from their perspective
.DealType = IIf(strDealType = "B", "S", "B")
.Nominal = dblNominal
.Price = dblPrice
.RowNumber = lngCurrentRow
.Stock = strStock
.Commission = strTradeComm
.Status = AS_SUCCESS
'references to the result cells for the trades are stored within the CTradeData instance
'this is done to enhance code readability where these cells are populated
'with result codes, it should also be an improvement in performance over
'the alternative, which is using repeated Range/Cells references
Set .SplitResultCell = wsCurrent.Cells(lngCurrent Row, lngSplitResultColumn)
Set .TradeResultCell = wsCurrent.Cells(lngCurrent Row, lngResultColumn)
Set .GrossConsidCell = wsCurrent.Cells(lngCurrent Row, wsCurrent.Range("GROSS_CON SID_HEADER ").Column)
Set .NetConsidCell = wsCurrent.Cells(lngCurrent Row, wsCurrent.Range("NET_CONSI D_HEADER") .Column)
End With
colTrades.Add Item:=tdCurrentTrade, Key:=CStr(lngCurrentRow)
Else
'we're on a subsequent page of subaccounts, and the trades are already
'in the collection so grab the trade object that corresponds to the current row
tdCurrentTrade = colTrades.Item(CStr(lngCur rentRow))
End If
If blnSplitsExist Then
For lngSplitColumn = LBound(vntSplitNominalsOne Row, 2) To UBound(vntSplitNominalsOne Row, 2)
'proceed only if there's a nominal and a subaccount specified for the column
If Not IsEmpty(vntSplitNominalsOn eRow(1, lngSplitColumn)) And Not IsEmpty(vntSplitAccts(1, lngSplitColumn)) Then
vntSplitNominalsOneRow = vntSplitNominalsAll(lngCur rentRow)
'the nominals are stored in an array of collections, one element per spreadsheet row.
'this is done because the number of nominals per row can vary wildly,
'so by using a collection we can store only the nominals specified and
'later we can (and do) iterate through the collection using a For Each loop
'to add up the nominals (for Calculate) or to Commit them.
sdSplitData = New CSplitData
sdSplitData.AccountNumber = CStr(vntSplitAccts(1, lngSplitColumn))
sdSplitData.Nominal = CDbl(vntSplitNominalsOneRo w(1, lngSplitColumn))
'Consider the split trade only if nominal is greater than zero
If sdSplitData.Nominal > 0 Then
tdCurrentTrade.Splits.Add Item:=sdSplitData, _
Key:=sdSplitData.AccountNu mber
End If
End If
Next lngSplitColumn
End If
'If this is a basket trade and there are splits then it is an allocated
'basket. Set this variable to true, which is used later to send
'MODIFY transaction to basket record.
If blnIsBasket And tdCurrentTrade.Splits.Coun t > 0 Then
blnAllocatedBasket = True
End If
If Not blnCalculateOnly Then
If blnIsBasket And tdCurrentTrade.Splits.Coun t > 0 Then
basket.SetObjectValue "AllocatedBasket", "Y"
Else
basket.SetObjectValue "AllocatedBasket", "N"
End If
End If
Else
'set the status cell when the trade entry is missing one or more fields
With wsCurrent.Cells(lngCurrent Row, lngResultColumn)
.Value = "INCOMPLETE"
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
End With
End If 'end of "If mf_GetNextTrade..." block
Next lngCurrentRow
'if there's more than one page of subaccounts then we need to iterate through all of them
'to get all of the split nominals
If blnLoopPages Then
lngPageLoop = lngPageLoop + 1
If lngPageLoop <= lngPageCount Then
Call ms_ShowSubAcctPage(lngPage Loop - 1, lngPageLoop, False)
End If
End If
Loop While (blnLoopPages) And (lngPageLoop <= lngPageCount)
'Set CommissionType to either FIXED_AMOUNT or BASIS_POINT
If strCommType = "FXTR" Then
strCommType = "FIXED_AMOUNT"
ElseIf strCommType = "FXBP" Then
strCommType = "BASIS_POINT"
End If
lCount = colTrades.Count
'process trades
'trap errors returned from DaiwaTrader so that they can be displayed
'in the worksheet in the status column
On Error Resume Next
For Each tdCurrentTrade In colTrades
Set dtTrader = New trade
With dtTrader
.SetObjectValue "RepresentativeId", strSalesman
.SetObjectValue "BuySell", tdCurrentTrade.DealType
.SetObjectValue "InstrumentCode", tdCurrentTrade.Stock
.SetObjectValue "CounterpartyCode", strClient
.SetObjectValue "BookId", strBook
.SetObjectValue "TradeBasis", strTradeBasis
.SetObjectValue "Quantity", tdCurrentTrade.Nominal
.SetObjectValue "MarketId", strExchange
.SetObjectValue "ValueDate", strValueDate
.SetObjectValue "BidPrice", tdCurrentTrade.Price
.SetObjectValue "OfferPrice", tdCurrentTrade.Price
If strPriceType <> "N" Then
'This should load the charges for the deal if price structure is not NET
Set dtTradeCharge = New TradeCharge
If IsEmpty(wsCurrent.Cells(td CurrentTra de.RowNumb er, wsCurrent.Range("COMMISSIO N_HEADER") .Column)) Then
'if the commission Type is set then
If strCommType <> "" Then
'.SetValue(COMMISSION_METH OD, strCommType)
dtTradeCharge.SetObjectVal ue "CalculationMethod", strCommType
'If strCommType = "FXTR" And_
If strCommType = "FIXED_AMOUNT" And _
(Not IsEmpty(wsCurrent.Cells(td CurrentTra de.RowNumb er, wsCurrent.Range("COMMISSIO N_HEADER") .Column))) Then
'.SetValue(COMMISSION_ARG, tdCurrentTrade.Commission)
dtTradeCharge.SetObjectVal ue "CalculationValue", tdCurrentTrade.Commission
Else
'.SetValue(COMMISSION_ARG, strCommArg)
dtTradeCharge.SetObjectVal ue "CalculationValue", strCommArg
End If
Else
'do nothing so that it uses default commission
End If
Else
dtTradeCharge.SetObjectVal ue "CalculationMethod", strCommType
'check if the commission type is FXBP
If strCommType = "BASIS_POINT" Then
dtTradeCharge.SetObjectVal ue "CalculationValue", strCommArg
Else
'users have entered fixed commission against each trade
.SetObjectValue "Commission", tdCurrentTrade.Commission
End If
End If
.AddTradeCharge (dtTradeCharge)
'Check to see if TradeCharge has been added to Trade
Dim tradeCharges As FidessaDataModels.TradeCha rgeSet
Set tradeCharges = New FidessaDataModels.TradeCha rgeSet
tradeCharges = dtTrader.GetObjectValue("T radeCharge s")
For Each dtTradeCharge In tradeCharges
Dim s As String
s = dtTradeCharge.GetObjectVal ue("Charge Id")
Next
On Error GoTo DoTradesError
err.Clear
End If
If tdCurrentTrade.Status = AS_SUCCESS Then
Dim RetVal As Boolean
If blnCalculateOnly Then
'asTradeResult = .PerformAction(ACTION_VALI DATE)
If Not .ValidateTrade() Then
On Error GoTo DoTradesError
End If
'Else
'asTradeResult = .PerformAction(ACTION_COMM IT)
'RetVal = .Insert()
End If
If asTradeResult = AS_FAILURE Or err.Number <> 0 Then
tdCurrentTrade.Status = AS_FAILURE
'tdCurrentTrade.TradeResul tCell.Valu e = "ERROR: " & .GetLastErrorDescription()
tdCurrentTrade.TradeResult Cell.Inter ior.Color = RED
lngErrorTrades = lngErrorTrades + 1
tdCurrentTrade.TradeID = "FAILED"
Else
If asTradeResult = AS_WARNING Then
If tdCurrentTrade.Status = AS_SUCCESS Then
tdCurrentTrade.Status = AS_WARNING
lngWarningTrades = lngWarningTrades + 1
tdCurrentTrade.TradeResult Cell.Inter ior.Color = YELLOW
'tdCurrentTrade.TradeResul tCell.Valu e = .GetLastErrorDescription()
End If
Else
tdCurrentTrade.Status = AS_SUCCESS
tdCurrentTrade.TradeResult Cell.Inter ior.Color = STATUS_GREY
If blnCalculateOnly Then
tdCurrentTrade.TradeResult Cell.Value = "Calculated"
tdCurrentTrade.TradeID = "OK"
Else
tdCurrentTrade.TradeResult Cell.Value = .GetObjectValue("TradeId")
tdCurrentTrade.TradeID = .GetObjectValue("TradeId")
End If
tdCurrentTrade.GrossConsid Cell.Value = .GetObjectValue("GrossCons ideration" )
tdCurrentTrade.NetConsidCe ll.Value = .GetObjectValue("NetConsid eration")
End If
If strTradeComm = "" Then
rngCommCell = wsCurrent.Cells(tdCurrentT rade.RowNu mber, wsCurrent.Range("COMMISSIO N_HEADER") .Column)
rngCommCell.Value = .GetObjectValue("Commissio n")
End If
'If strCommType = "FXBP" Then
If strCommType = "BASIS_POINT" Then
rngCommCell = wsCurrent.Cells(tdCurrentT rade.RowNu mber, wsCurrent.Range("COMMISSIO N_HEADER") .Column)
rngCommCell.Value = .GetObjectValue("Commissio n")
End If
End If 'end of "If asTradeResult = as_FAILURE ..." block
If Not blnCalculateOnly And tdCurrentTrade.Splits.Coun t > 0 Then
'This is a commit, Block trade is already committed, now commit split
Set dtSplitTrade = New allocation
dtSplitTrade.SetObjectValu e "TradeSetId", tdCurrentTrade.TradeID
For Each sdSplitData In tdCurrentTrade.Splits
'multiple split nominals
dtSplitTrade.MoveNext
dtSplitTrade.SetObjectValu e "CptyAccountId", sdSplitData.AccountNumber
dtSplitTrade.SetObjectValu e "CtacAllocationQuantity", sdSplitData.Nominal
'dtTrader.AddAllocation (dtSplitTrade)
Next
dtSplitTrade.MoveTo (0)
'If dtSplitTrade.PerformAction (ACTION_CO MMIT) = AS_SUCCESS Then
' blnSplitSuccess = True
'Else
' blnSplitSuccess = False
'End If
With tdCurrentTrade.SplitResult Cell
If blnSplitSuccess And err.Number = 0 Then
.Value = "OK"
.Interior.Color = STATUS_GREY
Else
.Value = dtSplitTrade.GetLastErrorD escription ()
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
err.Clear
End If
End With
'set the split trade object to nothing
Set dtSplitTrade = Nothing
ElseIf blnCalculateOnly Then
'just add up the nominals to see if they match the trade nominal...
'...if they don't match, it's an error and will be flagged accordingly
'...if there are no splits at all for the trade, then it merits only a warning to the user
dblSplitRowTotal = 0#
For Each sdSplitData In tdCurrentTrade.Splits
dblSplitRowTotal = dblSplitRowTotal + sdSplitData.Nominal
Next
If dblSplitRowTotal = 0# Then
If tdCurrentTrade.Status = AS_SUCCESS Then
tdCurrentTrade.Status = AS_WARNING
tdCurrentTrade.TradeResult Cell.Inter ior.Color = YELLOW
tdCurrentTrade.TradeResult Cell.Value = "NO SPLITS"
tdCurrentTrade.SplitResult Cell = Empty
tdCurrentTrade.SplitResult Cell.Inter ior.Color = STATUS_GREY
lngWarningTrades = lngWarningTrades + 1
End If
Else
With tdCurrentTrade.SplitResult Cell
If dblSplitRowTotal = tdCurrentTrade.Nominal Then
.Value = "VALID"
.Interior.Color = STATUS_GREY
Else
.Value = "INVALID"
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
End If
End With
End If
End If 'end of if not blnCalculateOnly
End If 'end of "If tdCurrentTrade.Status = AS_SUCCESS Then" block
End With 'end of "With dtTrader" block
If blnIsBasket And Not blnCalculateOnly Then
basket.AddTrade dtTrader
End If
Set dtTrader = Nothing
Next tdCurrentTrade
err.Clear
On Error GoTo DoTradesError
If Not blnCalculateOnly Then
If basket.CreateBasket() Then
strBasketId = basket.GetObjectValue("Bas ketId")
wsCurrent.Range("BASKET_ID ").Value = strBasketId
Else
Dim strError As String
Dim error As Variant
For Each error In basket.FieldErrors
strError = strError + error.Text
Next
MsgBox "Unable to create Basket. " + vbCrLf + strError, vbCritical
End If
End If
DoTradesError:
If (err.Number <> 0) Then
MsgBox ("Error: " & err.Description & " in " & err.Source)
lngErrorTrades = lngErrorTrades + 1
End If
'clean up all objects and arrays
wsCurrent = Nothing
rngCommCell = Nothing
sdSplitData = Nothing
Set dtSplitTrade = Nothing
Set colTrades = Nothing
tdCurrentTrade = Nothing
vntSplitNominalsAll = Empty
vntSplitNominalsOneRow = Empty
vntSplitAccts = Empty
'show the page of subaccounts that was displayed when the user clicked "Calculate" or "Commit"
If blnLoopPages Then
Call ms_ShowSubAcctPage(lngPage Count, lngPageOriginal, False)
End If
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.Calculation = xlCalculationAutomatic
End With
'return result code, based on whether or not trade processing resulted in any errors or warnings
If (lngErrorTrades > 0) Then
mf_DoTrades = AS_FAILURE
ElseIf (lngWarningTrades > 0) Then
mf_DoTrades = AS_WARNING
Else
mf_DoTrades = AS_SUCCESS
End If
End Function
The errors are
I'm using office 2003.
Private Function mf_DoTrades(ByVal blnCalculateOnly As Boolean, ByVal lngCurrentPage As Long, ByVal lngPageCount As Long) As eActionStatus
Dim strTradeBasis As String
Dim strDealType As String
Dim strBook As String
Dim strStock As String
Dim strBasketDesc As String
Dim strBasketRef As String
Dim strPriceType As String
Dim strNarrative As String
Dim dblNominal As Double
Dim dblPrice As Double
Dim dblCommission As Double
Dim strCommType As String
Dim strCommArg As String
Dim strTradeComm As String
Dim strSalesman As String
Dim strTradeDate As String
Dim strValueDate As String
Dim strExchange As String
Dim strBasketId As String
Dim lngCurrentRow As Long
Dim lngErrorTrades As Long
Dim lngWarningTrades As Long
Dim wsCurrent As Worksheet
Dim blnIsBasket As Boolean
Dim blnHasMultiTrades As Boolean
Dim bIgnoreCommCap As Boolean
Dim bIgnorePriceVariance As Boolean
Dim asTradeResult As eActionStatus
Dim lngTradeCount As Long
Dim lngRightmostColumn As Long
Dim lngResultColumn As Long
Dim lngSplitResultColumn As Long
Dim blnSplitsExist As Boolean
Dim rngCommCell As Range
Dim lngPageLoop As Long
Dim blnLoopPages As Boolean
Dim dblSplitRowTotal As Double
Dim lngPageOriginal As Long
Dim lngSplitColumn As Long
Dim sdSplitData As CSplitData
Dim blnSplitSuccess As Boolean
Dim blnAllocatedBasket As Boolean
Dim vntSplitAccts As Variant
Dim vntSplitNominalsOneRow As Variant
Dim vntSplitNominalsAll As Variant
Dim lngFirstRow As Long
Dim lngLastRow As Long
Dim strClient As String
Dim colTrades As Collection 'holds the trade data
Dim tdCurrentTrade As CTradeData 'holds the data for the trade currently being processed
Dim lCount As Long
Dim basket As basket
Dim dtTrader As trade
Dim dtSplitTrade As allocation
Dim dtTradeCharge As TradeCharge
'Set up error
On Error GoTo DoTradesError
err.Clear
With Application
.ScreenUpdating = False
Set wsCurrent = .ActiveSheet
.DisplayAlerts = False
.Calculation = xlCalculationManual
End With
Set colTrades = New Collection
lngTradeCount = mf_GetTradeCount(wsCurrent
blnHasMultiTrades = (lngTradeCount > 1)
blnLoopPages = (lngPageCount > 0)
lngPageOriginal = lngCurrentPage
'
'now we retrieve the values from the various named ranges.
'
'*************************
'NOTE: It is of VITAL importance that the named ranges (e.g. "TRADE_BASIS", "BOOK_CODE", etc.)
'exist in the worksheet and also that they point to the appropriate cells or the macro will not work.
'*************************
'
'read "common" fields and assign their values to local variables
With wsCurrent
strTradeBasis = .Range("TRADE_BASIS").Valu
strBook = UCase$(CStr(.Range("BOOK_C
strClient = CStr(.Range("CPTY_CODE").V
strSalesman = UCase$(CStr(.Range("SALESM
strExchange = UCase$(CStr(.Range("EXCHAN
strTradeDate = Format$(CDate(.Range("TRAD
strValueDate = Format$(CDate(.Range("VALU
strPriceType = UCase$(CStr(.Range("PRICE_
strBasketDesc = CStr(.Range("BASKET_DESC")
strBasketRef = CStr(.Range("BASKET_REF").
'Should we ignore the difference between enterd price and market price?
If UCase$(CStr(.Range("IGNORE
bIgnorePriceVariance = True
Else
bIgnorePriceVariance = False
End If
'the trades will be 'basketed' only if the user has specified this in the "BASKET_FLAG" cell
'AND if there's more than one trade on the sheet
blnIsBasket = ((UCase$(Left$(CStr(.Range
And blnHasMultiTrades)
lngFirstRow = .Range("SUCCESS_HEADER").R
.Range("BASKET_ID").ClearC
lngResultColumn = .Range("SUCCESS_HEADER").C
strCommType = CStr(.Range("COMMISSION_TY
strCommArg = CStr(.Range("COMMISSION_AR
lngSplitResultColumn = .Range("SPLIT_RESULT").Col
End With
lngLastRow = (lngFirstRow + lngTradeCount - 1)
ReDim vntSplitNominalsAll(lngFir
lngErrorTrades = 0
lngWarningTrades = 0
blnAllocatedBasket = False
If blnIsBasket And (Not blnCalculateOnly) Then
'Avoid Generating BASKET_ID during validation
If strBasketRef = "" Then
strBasketRef = " "
End If
If strBasketDesc = "" Then
strBasketDesc = " "
End If
basket.SetObjectValue "BookId", strBook
basket.SetObjectValue "CounterpartyId", strClient
basket.SetObjectValue "DealtPriceType", strPriceType
basket.SetObjectValue "SettlementDate", strValueDate
basket.SetObjectValue "TradeDate", strTradeDate
basket.SetObjectValue "BasketType", "JP"
basket.SetObjectValue "TradeCount", lngTradeCount
basket.SetObjectValue "BasketReference", strBasketRef
basket.SetObjectValue "BasketDescription", strBasketDesc
End If
If blnLoopPages Then
Call ms_ShowSubAcctPage(lngCurr
End If
'retrieve trades from worksheet
Do 'we have to go through the trades at least once, hence the Do/Loop While construct
For lngCurrentRow = lngFirstRow To lngLastRow
blnSplitsExist = False 'reset semaphore for next trade
With wsCurrent
'find out if there's any splits...
'find the rightmost column in use, if it's not at least as far across as
'the first split nominal column, then we know there's no splits for this trade
lngRightmostColumn = .Cells(lngCurrentRow, 256).End(xlToLeft).Column
If lngRightmostColumn >= .Range("FIRST_SUBACCT_NUMB
'grab all of the columns, this way we guarantee that the variant will hold an array
'of values and not just a single value
'first, the account numbers...
vntSplitAccts = .Range(.Range("FIRST_SUBAC
MAX_COLUMN_IN_USE)).Value
'... and then the nominals
vntSplitNominalsOneRow = .Range(.Cells(lngCurrentRo
.Cells(lngCurrentRow, MAX_COLUMN_IN_USE)).Value
blnSplitsExist = True
dblSplitRowTotal = 0#
Else
vntSplitNominalsOneRow = Empty
End If
'at this point, vntSplitNominalsOneRow will be in one of two states:
' Empty, if no nominals are present
' 2-dimensional Array of strings (1,n) if one or more nominals are present
vntSplitNominalsAll(lngCur
End With 'end of "With wsCurrent" block
If mf_GetNextTrade(wsCurrent,
If lngPageLoop = 0 Then
'we're on the first page of subaccounts, then the trades need to be added to the
'trades collection
Set tdCurrentTrade = New CTradeData
With tdCurrentTrade
'reverse the buy/sell flag so that the users can interpret this from their perspective
.DealType = IIf(strDealType = "B", "S", "B")
.Nominal = dblNominal
.Price = dblPrice
.RowNumber = lngCurrentRow
.Stock = strStock
.Commission = strTradeComm
.Status = AS_SUCCESS
'references to the result cells for the trades are stored within the CTradeData instance
'this is done to enhance code readability where these cells are populated
'with result codes, it should also be an improvement in performance over
'the alternative, which is using repeated Range/Cells references
Set .SplitResultCell = wsCurrent.Cells(lngCurrent
Set .TradeResultCell = wsCurrent.Cells(lngCurrent
Set .GrossConsidCell = wsCurrent.Cells(lngCurrent
Set .NetConsidCell = wsCurrent.Cells(lngCurrent
End With
colTrades.Add Item:=tdCurrentTrade, Key:=CStr(lngCurrentRow)
Else
'we're on a subsequent page of subaccounts, and the trades are already
'in the collection so grab the trade object that corresponds to the current row
tdCurrentTrade = colTrades.Item(CStr(lngCur
End If
If blnSplitsExist Then
For lngSplitColumn = LBound(vntSplitNominalsOne
'proceed only if there's a nominal and a subaccount specified for the column
If Not IsEmpty(vntSplitNominalsOn
vntSplitNominalsOneRow = vntSplitNominalsAll(lngCur
'the nominals are stored in an array of collections, one element per spreadsheet row.
'this is done because the number of nominals per row can vary wildly,
'so by using a collection we can store only the nominals specified and
'later we can (and do) iterate through the collection using a For Each loop
'to add up the nominals (for Calculate) or to Commit them.
sdSplitData = New CSplitData
sdSplitData.AccountNumber = CStr(vntSplitAccts(1, lngSplitColumn))
sdSplitData.Nominal = CDbl(vntSplitNominalsOneRo
'Consider the split trade only if nominal is greater than zero
If sdSplitData.Nominal > 0 Then
tdCurrentTrade.Splits.Add Item:=sdSplitData, _
Key:=sdSplitData.AccountNu
End If
End If
Next lngSplitColumn
End If
'If this is a basket trade and there are splits then it is an allocated
'basket. Set this variable to true, which is used later to send
'MODIFY transaction to basket record.
If blnIsBasket And tdCurrentTrade.Splits.Coun
blnAllocatedBasket = True
End If
If Not blnCalculateOnly Then
If blnIsBasket And tdCurrentTrade.Splits.Coun
basket.SetObjectValue "AllocatedBasket", "Y"
Else
basket.SetObjectValue "AllocatedBasket", "N"
End If
End If
Else
'set the status cell when the trade entry is missing one or more fields
With wsCurrent.Cells(lngCurrent
.Value = "INCOMPLETE"
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
End With
End If 'end of "If mf_GetNextTrade..." block
Next lngCurrentRow
'if there's more than one page of subaccounts then we need to iterate through all of them
'to get all of the split nominals
If blnLoopPages Then
lngPageLoop = lngPageLoop + 1
If lngPageLoop <= lngPageCount Then
Call ms_ShowSubAcctPage(lngPage
End If
End If
Loop While (blnLoopPages) And (lngPageLoop <= lngPageCount)
'Set CommissionType to either FIXED_AMOUNT or BASIS_POINT
If strCommType = "FXTR" Then
strCommType = "FIXED_AMOUNT"
ElseIf strCommType = "FXBP" Then
strCommType = "BASIS_POINT"
End If
lCount = colTrades.Count
'process trades
'trap errors returned from DaiwaTrader so that they can be displayed
'in the worksheet in the status column
On Error Resume Next
For Each tdCurrentTrade In colTrades
Set dtTrader = New trade
With dtTrader
.SetObjectValue "RepresentativeId", strSalesman
.SetObjectValue "BuySell", tdCurrentTrade.DealType
.SetObjectValue "InstrumentCode", tdCurrentTrade.Stock
.SetObjectValue "CounterpartyCode", strClient
.SetObjectValue "BookId", strBook
.SetObjectValue "TradeBasis", strTradeBasis
.SetObjectValue "Quantity", tdCurrentTrade.Nominal
.SetObjectValue "MarketId", strExchange
.SetObjectValue "ValueDate", strValueDate
.SetObjectValue "BidPrice", tdCurrentTrade.Price
.SetObjectValue "OfferPrice", tdCurrentTrade.Price
If strPriceType <> "N" Then
'This should load the charges for the deal if price structure is not NET
Set dtTradeCharge = New TradeCharge
If IsEmpty(wsCurrent.Cells(td
'if the commission Type is set then
If strCommType <> "" Then
'.SetValue(COMMISSION_METH
dtTradeCharge.SetObjectVal
'If strCommType = "FXTR" And_
If strCommType = "FIXED_AMOUNT" And _
(Not IsEmpty(wsCurrent.Cells(td
'.SetValue(COMMISSION_ARG,
dtTradeCharge.SetObjectVal
Else
'.SetValue(COMMISSION_ARG,
dtTradeCharge.SetObjectVal
End If
Else
'do nothing so that it uses default commission
End If
Else
dtTradeCharge.SetObjectVal
'check if the commission type is FXBP
If strCommType = "BASIS_POINT" Then
dtTradeCharge.SetObjectVal
Else
'users have entered fixed commission against each trade
.SetObjectValue "Commission", tdCurrentTrade.Commission
End If
End If
.AddTradeCharge (dtTradeCharge)
'Check to see if TradeCharge has been added to Trade
Dim tradeCharges As FidessaDataModels.TradeCha
Set tradeCharges = New FidessaDataModels.TradeCha
tradeCharges = dtTrader.GetObjectValue("T
For Each dtTradeCharge In tradeCharges
Dim s As String
s = dtTradeCharge.GetObjectVal
Next
On Error GoTo DoTradesError
err.Clear
End If
If tdCurrentTrade.Status = AS_SUCCESS Then
Dim RetVal As Boolean
If blnCalculateOnly Then
'asTradeResult = .PerformAction(ACTION_VALI
If Not .ValidateTrade() Then
On Error GoTo DoTradesError
End If
'Else
'asTradeResult = .PerformAction(ACTION_COMM
'RetVal = .Insert()
End If
If asTradeResult = AS_FAILURE Or err.Number <> 0 Then
tdCurrentTrade.Status = AS_FAILURE
'tdCurrentTrade.TradeResul
tdCurrentTrade.TradeResult
lngErrorTrades = lngErrorTrades + 1
tdCurrentTrade.TradeID = "FAILED"
Else
If asTradeResult = AS_WARNING Then
If tdCurrentTrade.Status = AS_SUCCESS Then
tdCurrentTrade.Status = AS_WARNING
lngWarningTrades = lngWarningTrades + 1
tdCurrentTrade.TradeResult
'tdCurrentTrade.TradeResul
End If
Else
tdCurrentTrade.Status = AS_SUCCESS
tdCurrentTrade.TradeResult
If blnCalculateOnly Then
tdCurrentTrade.TradeResult
tdCurrentTrade.TradeID = "OK"
Else
tdCurrentTrade.TradeResult
tdCurrentTrade.TradeID = .GetObjectValue("TradeId")
End If
tdCurrentTrade.GrossConsid
tdCurrentTrade.NetConsidCe
End If
If strTradeComm = "" Then
rngCommCell = wsCurrent.Cells(tdCurrentT
rngCommCell.Value = .GetObjectValue("Commissio
End If
'If strCommType = "FXBP" Then
If strCommType = "BASIS_POINT" Then
rngCommCell = wsCurrent.Cells(tdCurrentT
rngCommCell.Value = .GetObjectValue("Commissio
End If
End If 'end of "If asTradeResult = as_FAILURE ..." block
If Not blnCalculateOnly And tdCurrentTrade.Splits.Coun
'This is a commit, Block trade is already committed, now commit split
Set dtSplitTrade = New allocation
dtSplitTrade.SetObjectValu
For Each sdSplitData In tdCurrentTrade.Splits
'multiple split nominals
dtSplitTrade.MoveNext
dtSplitTrade.SetObjectValu
dtSplitTrade.SetObjectValu
'dtTrader.AddAllocation (dtSplitTrade)
Next
dtSplitTrade.MoveTo (0)
'If dtSplitTrade.PerformAction
' blnSplitSuccess = True
'Else
' blnSplitSuccess = False
'End If
With tdCurrentTrade.SplitResult
If blnSplitSuccess And err.Number = 0 Then
.Value = "OK"
.Interior.Color = STATUS_GREY
Else
.Value = dtSplitTrade.GetLastErrorD
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
err.Clear
End If
End With
'set the split trade object to nothing
Set dtSplitTrade = Nothing
ElseIf blnCalculateOnly Then
'just add up the nominals to see if they match the trade nominal...
'...if they don't match, it's an error and will be flagged accordingly
'...if there are no splits at all for the trade, then it merits only a warning to the user
dblSplitRowTotal = 0#
For Each sdSplitData In tdCurrentTrade.Splits
dblSplitRowTotal = dblSplitRowTotal + sdSplitData.Nominal
Next
If dblSplitRowTotal = 0# Then
If tdCurrentTrade.Status = AS_SUCCESS Then
tdCurrentTrade.Status = AS_WARNING
tdCurrentTrade.TradeResult
tdCurrentTrade.TradeResult
tdCurrentTrade.SplitResult
tdCurrentTrade.SplitResult
lngWarningTrades = lngWarningTrades + 1
End If
Else
With tdCurrentTrade.SplitResult
If dblSplitRowTotal = tdCurrentTrade.Nominal Then
.Value = "VALID"
.Interior.Color = STATUS_GREY
Else
.Value = "INVALID"
.Interior.Color = RED
lngErrorTrades = lngErrorTrades + 1
End If
End With
End If
End If 'end of if not blnCalculateOnly
End If 'end of "If tdCurrentTrade.Status = AS_SUCCESS Then" block
End With 'end of "With dtTrader" block
If blnIsBasket And Not blnCalculateOnly Then
basket.AddTrade dtTrader
End If
Set dtTrader = Nothing
Next tdCurrentTrade
err.Clear
On Error GoTo DoTradesError
If Not blnCalculateOnly Then
If basket.CreateBasket() Then
strBasketId = basket.GetObjectValue("Bas
wsCurrent.Range("BASKET_ID
Else
Dim strError As String
Dim error As Variant
For Each error In basket.FieldErrors
strError = strError + error.Text
Next
MsgBox "Unable to create Basket. " + vbCrLf + strError, vbCritical
End If
End If
DoTradesError:
If (err.Number <> 0) Then
MsgBox ("Error: " & err.Description & " in " & err.Source)
lngErrorTrades = lngErrorTrades + 1
End If
'clean up all objects and arrays
wsCurrent = Nothing
rngCommCell = Nothing
sdSplitData = Nothing
Set dtSplitTrade = Nothing
Set colTrades = Nothing
tdCurrentTrade = Nothing
vntSplitNominalsAll = Empty
vntSplitNominalsOneRow = Empty
vntSplitAccts = Empty
'show the page of subaccounts that was displayed when the user clicked "Calculate" or "Commit"
If blnLoopPages Then
Call ms_ShowSubAcctPage(lngPage
End If
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.Calculation = xlCalculationAutomatic
End With
'return result code, based on whether or not trade processing resulted in any errors or warnings
If (lngErrorTrades > 0) Then
mf_DoTrades = AS_FAILURE
ElseIf (lngWarningTrades > 0) Then
mf_DoTrades = AS_WARNING
Else
mf_DoTrades = AS_SUCCESS
End If
End Function
The errors are
ASKER
Sorry! It is a lot of code!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
OK,
Problem(1)
I'm going to try this out, although i have other methods with return values which work.
Problem (2)
both Call .AddTradeCharge(dtTradeCha rge) and
.AddTradeCharge dtTradeCharge do not cause the argument not optional error and work!
Problem(3)
Any idea why the intellisense might not be working?!
PS - thanks for you help so far!
Problem(1)
I'm going to try this out, although i have other methods with return values which work.
Problem (2)
both Call .AddTradeCharge(dtTradeCha
.AddTradeCharge dtTradeCharge do not cause the argument not optional error and work!
Problem(3)
Any idea why the intellisense might not be working?!
PS - thanks for you help so far!
Problem(3)
Not really an expert in com interfaces but
Try adding:
[ComVisible(True)]
and/or setting this property to true in the properties window:
ReferenceAssemblyFromVbaPr oject
Not really an expert in com interfaces but
Try adding:
[ComVisible(True)]
and/or setting this property to true in the properties window:
ReferenceAssemblyFromVbaPr
ASKER
Even without the intellisense working, when i inherit from multiple interfaces, it is only picking up one of them and not the other. So the methods/properties of ITrade are picked up, but not those of IDataContainer. It does not however throw an error saying that the methods and properties don't exist, but the calls to the methods jsut don't do anything. I really can't see anything that I'm missing here. I know for a fact that when I have a class that inherits just from IDataContainer, I can access it's methods/properties as I am using this elsewhere.
What version of office are you using?
Jell