' ******************************************************************************
' **
' ** Yahoo Finance Managed
' ** Written by Marius Häusler 2010
' ** It would be pleasant, if you contact me when you are using this code.
' ** Contact: YahooFinanceManaged@gmail.com
' ** Project Home: http://code.google.com/p/yahoo-finance-managed/
' **
' ******************************************************************************
' **
' ** Copyright 2010 Marius Häusler
' **
' ** Licensed under the Apache License, Version 2.0 (the "License");
' ** you may not use this file except in compliance with the License.
' ** You may obtain a copy of the License at
' **
' ** http://www.apache.org/licenses/LICENSE-2.0
' **
' ** Unless required by applicable law or agreed to in writing, software
' ** distributed under the License is distributed on an "AS IS" BASIS,
' ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' ** See the License for the specific language governing permissions and
' ** limitations under the License.
' **
' ******************************************************************************
Imports System.Text.RegularExpressions
Namespace Finance.API
''' <summary>
''' Provides methods for downloading historic quote data.
''' </summary>
''' <remarks></remarks>
Public Class HistQuotesDownload
Inherits Base.StringDownload
''' <summary>
''' Raises if an asynchronous download of historic quote data completes.
''' </summary>
''' <param name="sender">The event raising object</param>
''' <param name="ea">The event args of the asynchronous download</param>
''' <remarks></remarks>
Public Event AsyncDownloadCompleted(ByVal sender As Base.Download, ByVal ea As HistQuotesDownloadCompletedEventArgs)
Friend ReadOnly mFinanceHelper As New FinanceHelper
Private mCsvParser As New ImportExport.CSV
''' <summary>
''' Downloads historic quotes data.
''' </summary>
''' <param name="managedID">The managed ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Function Download(ByVal managedID As IID, ByVal fromDate As Date, ByVal todate As Date, ByVal interval As HistQuotesInterval) As HistQuotesResponse
If managedID Is Nothing Then Throw New ArgumentNullException("managedID", "The passed ID is null.")
Return Me.Download(managedID.ID, fromDate, todate, interval)
End Function
''' <summary>
''' Downloads historic quotes data.
''' </summary>
''' <param name="unmanagedID">The unmanaged ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Function Download(ByVal unmanagedID As String, ByVal fromDate As Date, ByVal todate As Date, ByVal interval As HistQuotesInterval) As HistQuotesResponse
If unmanagedID.Trim = String.Empty Then Throw New ArgumentNullException("unmanagedID", "The passed ID is empty.")
Return Me.ToResponse(MyBase.Download(Me.DownloadURL(New String() {unmanagedID}, fromDate, todate, interval)), New String() {unmanagedID})
End Function
''' <summary>
''' Downloads historic quotes data.
''' </summary>
''' <param name="managedIDs">The managed ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Function Download(ByVal managedIDs As IEnumerable(Of IID), ByVal fromDate As Date, ByVal todate As Date, ByVal interval As HistQuotesInterval) As HistQuotesResponse
If managedIDs Is Nothing Then Throw New ArgumentNullException("managedIDs", "The passed list is null.")
Return Me.Download(mFinanceHelper.IIDsToStrings(managedIDs), fromDate, todate, interval)
End Function
''' <summary>
''' Downloads historic quotes data.
''' </summary>
''' <param name="unmanagedIDs">The unmanaged ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads Function Download(ByVal unmanagedIDs As IEnumerable(Of String), ByVal fromDate As Date, ByVal todate As Date, ByVal interval As HistQuotesInterval) As HistQuotesResponse
If unmanagedIDs Is Nothing Then Throw New ArgumentNullException("unmanagedID", "The passed ID is empty.")
Me.CheckDates(fromDate, todate)
Dim url As String = Me.DownloadURL(unmanagedIDs, fromDate, todate, interval)
Return Me.ToResponse(MyBase.Download(url), mHelper.EnumToArray(unmanagedIDs))
End Function
''' <summary>
''' Starts an asynchronous download of historic quotes data.
''' </summary>
''' <param name="managedID">The managed ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <param name="userArgs">Individual user argument</param>
''' <remarks></remarks>
Public Overloads Sub DownloadAsync(ByVal managedID As IID, ByVal fromDate As Date, ByVal toDate As Date, ByVal interval As HistQuotesInterval, Optional ByVal userArgs As Object = Nothing)
If managedID Is Nothing Then Throw New ArgumentNullException("managedID", "The passed ID is null.")
Me.DownloadAsync(managedID.ID, fromDate, toDate, interval, userArgs)
End Sub
''' <summary>
''' Starts an asynchronous download of historic quotes data.
''' </summary>
''' <param name="unmanagedID">The unmanaged ID</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <param name="userArgs">Individual user argument</param>
''' <remarks></remarks>
Public Overloads Sub DownloadAsync(ByVal unmanagedID As String, ByVal fromDate As Date, ByVal toDate As Date, ByVal interval As HistQuotesInterval, Optional ByVal userArgs As Object = Nothing)
If unmanagedID = String.Empty Then Throw New ArgumentNullException("unmanagedID", "The passed ID is empty.")
Me.DownloadAsync(New String() {unmanagedID}, fromDate, toDate, interval, userArgs)
End Sub
''' <summary>
''' Starts an asynchronous download of historic quotes data.
''' </summary>
''' <param name="managedIDs">The managed list of IDs</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <param name="userArgs">Individual user argument</param>
''' <remarks></remarks>
Public Overloads Sub DownloadAsync(ByVal managedIDs As IEnumerable(Of IID), ByVal fromDate As Date, ByVal toDate As Date, ByVal interval As HistQuotesInterval, Optional ByVal userArgs As Object = Nothing)
If managedIDs Is Nothing Then Throw New ArgumentNullException("managedIDs", "The passed list is null.")
Me.DownloadAsync(mFinanceHelper.IIDsToStrings(managedIDs), fromDate, toDate, interval, userArgs)
End Sub
''' <summary>
''' Starts an asynchronous download of historic quotes data.
''' </summary>
''' <param name="unmanagedIDs">The unmanaged list of IDs</param>
''' <param name="fromDate">The startdate of the reviewed period</param>
''' <param name="todate">The enddate of the reviewed period</param>
''' <param name="interval">The trading period interval</param>
''' <param name="userArgs">Individual user argument</param>
''' <remarks></remarks>
Public Overloads Sub DownloadAsync(ByVal unmanagedIDs As IEnumerable(Of String), ByVal fromDate As Date, ByVal toDate As Date, ByVal interval As HistQuotesInterval, Optional ByVal userArgs As Object = Nothing)
If unmanagedIDs Is Nothing Then Throw New ArgumentNullException("unmanagedIDs", "The passed list is null.")
Me.CheckDates(fromDate, toDate)
Dim args As New AsyncDownloadArgs(userArgs, mFinanceHelper.CleanIDfromAT(unmanagedIDs), fromDate, toDate, interval)
MyBase.DownloadAsync(Me.DownloadURL(args.IDs, fromDate, toDate, interval), args)
End Sub
''' <summary>
''' Default constructor
''' </summary>
''' <remarks></remarks>
Public Sub New()
End Sub
Private Sub DownloadAsync_Completed(ByVal sender As Base.Download, ByVal ba As Base.StringDownloadCompletedEventArgs) Handles MyBase.AsyncStringDownloadCompleted
If ba IsNot Nothing AndAlso ba.UserArgs IsNot Nothing AndAlso TypeOf ba.UserArgs Is AsyncDownloadArgs Then
Dim dlArgs As AsyncDownloadArgs = DirectCast(ba.UserArgs, AsyncDownloadArgs)
Dim args As New HistQuotesDownloadCompletedEventArgs(dlArgs.UserArgs, Me.ToResponse(ba.Response, dlArgs.IDs), dlArgs.IDs, dlArgs.FromDate, dlArgs.ToDate, dlArgs.Interval)
RaiseEvent AsyncDownloadCompleted(Me, args)
End If
End Sub
Private Function DownloadURL(ByVal ids As IEnumerable(Of String), ByVal fromDate As Date, ByVal toDate As Date, ByVal interval As HistQuotesInterval) As String
Dim idArr() As String = mHelper.EnumToArray(ids)
If idArr.Length = 0 Then
Throw New ArgumentNullException("unmanagedIDs", "The passed list is empty")
Else
If idArr.Length = 1 Then
If idArr(0).Trim = String.Empty Then
Throw New ArgumentNullException("id", "The passed ID is empty.")
Else
Dim url As New Text.StringBuilder
url.Append("http://ichart.yahoo.com/table.csv?s=")
url.Append(Uri.EscapeDataString(mHelper.CleanYqlParam(idArr(0).ToUpper.Replace("@", ""))))
url.Append("&a=")
url.Append(fromDate.Month - 1)
url.Append("&b=")
url.Append(fromDate.Day)
url.Append("&c=")
url.Append(fromDate.Year)
url.Append("&d=")
url.Append(toDate.Month - 1)
url.Append("&e=")
url.Append(toDate.Day)
url.Append("&f=")
url.Append(toDate.Year)
url.Append("&g=")
url.Append(mFinanceHelper.GetHistQuotesInterval(interval))
url.Append("&ignore=.csv")
Return url.ToString
End If
Else
Dim url As New Text.StringBuilder
url.Append("url in (")
For i As Integer = 0 To idArr.Length - 1
url.Append("'"c)
url.Append(Me.DownloadURL(New String() {mHelper.CleanYqlParam(idArr(i).ToUpper.Replace("@", ""))}, fromDate, toDate, interval))
url.Append("'"c)
If i < idArr.Length - 1 Then url.Append(","c)
Next
url.Append(")")
Return mHelper.YqlUrl("*", "csv", url.ToString, Nothing, True)
End If
End If
End Function
Private Function ToResponse(ByVal resp As Base.StringResponse, ByVal ids() As String) As HistQuotesResponse
Dim quotes As New List(Of HistQuotesDataChain)
Dim chain As New HistQuotesDataChain
If resp.Connection.State = Base.ConnectionState.Success Then
If resp.Result.StartsWith("{""query"":") Then
Dim reg As New Regex("{""col0"":"".*?"",""col1"":"".*?"",""col2"":"".*?"",""col3"":"".*?"",""col4"":"".*?"",""col5"":"".*?"",""col6"":"".*?""}")
Dim matches As MatchCollection = reg.Matches(resp.Result)
If matches.Count > 0 Then
For Each m As Match In matches
If m.Success Then
Dim columns() As String = m.Value.Replace("{", "").Replace("}", "").Split(New Char() {","c})
If columns.Length = 7 Then
If columns(0) = """col0"":""Date""" Then
If chain.Count > 0 Then
Dim id As String = String.Empty
If quotes.Count <= ids.Length - 1 Then id = ids(quotes.Count)
chain.SetID(id)
quotes.Add(chain)
chain = New HistQuotesDataChain
End If
Else
Dim hq As New HistQuoteData
For Each col As String In columns
Dim values() As String = col.Replace("""", "").Split(":"c)
If values.Length = 2 Then
Select Case values(0)
Case "col0"
Date.TryParse(values(1), mFinanceHelper.DefaultYqlCulture, Globalization.DateTimeStyles.AdjustToUniversal, hq.TradingDate)
Case "col1"
Double.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.Open)
Case "col2"
Double.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.High)
Case "col3"
Double.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.Low)
Case "col4"
Double.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.Close)
Case "col5"
Long.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.Volume)
Case "col6"
Double.TryParse(values(1), Globalization.NumberStyles.Any, mFinanceHelper.DefaultYqlCulture, hq.CloseAdjusted)
End Select
End If
Next col
chain.Add(hq)
End If
End If
End If
Next m
If chain.Count > 0 Then
Dim id As String = String.Empty
If quotes.Count <= ids.Length - 1 Then id = ids(quotes.Count)
chain.SetID(id)
quotes.Add(chain)
End If
chain = Nothing
End If
Else
quotes.Add(New HistQuotesDataChain(ids(0), mCsvParser.ToHistQuotesData(resp.Result, ","c, mFinanceHelper.DefaultYqlCulture)))
End If
End If
Return New HistQuotesResponse(resp.Connection, quotes.ToArray)
End Function
Private Sub CheckDates(ByVal fromDate As Date, ByVal toDate As Date)
If fromDate >= toDate Then Throw New ArgumentNullException("date", "The start date is later than the end date.")
End Sub
Private Class AsyncDownloadArgs
Inherits Base.DownloadEventArgs
Public IDs() As String
Public FromDate As Date
Public ToDate As Date
Public Interval As HistQuotesInterval
Public Sub New(ByVal userArgs As Object, ByVal i() As String, ByVal fDate As Date, ByVal tDate As Date, ByVal inter As HistQuotesInterval)
MyBase.New(userArgs)
Me.IDs = i
Me.FromDate = fDate
Me.ToDate = tDate
Me.Interval = inter
End Sub
End Class
End Class
''' <summary>
''' Provides information and response of an asynchronous historic quote download.
''' </summary>
''' <remarks></remarks>
Public Class HistQuotesDownloadCompletedEventArgs
Inherits Base.DownloadCompletedEventArgs
Private mIDs() As String
Private mFromDate, mToDate As Date
Private mInterval As HistQuotesInterval
''' <summary>
''' Gets the ID of the stock, index, exchange rate, etc.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property IDs() As String()
Get
Return mIDs
End Get
End Property
''' <summary>
''' Gets the startdate of the reviewed period.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property FromDate() As Date
Get
Return mFromDate
End Get
End Property
''' <summary>
''' Gets the enddate of the reviewed period.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property ToDate() As Date
Get
Return mToDate
End Get
End Property
''' <summary>
''' Gets the trading period interval.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Interval() As HistQuotesInterval
Get
Return mInterval
End Get
End Property
''' <summary>
''' Gets the response with historic quote data.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads ReadOnly Property Response() As HistQuotesResponse
Get
Return DirectCast(MyBase.Response, HistQuotesResponse)
End Get
End Property
Friend Sub New(ByVal userArgs As Object, ByVal resp As HistQuotesResponse, ByVal id() As String, ByVal fDate As Date, ByVal tDate As Date, ByVal inter As HistQuotesInterval)
MyBase.New(userArgs, resp)
mIDs = id
mFromDate = fDate
mToDate = tDate
mInterval = inter
End Sub
End Class
''' <summary>
''' Provides connection information and downloaded historic quote data.
''' </summary>
''' <remarks></remarks>
Public Class HistQuotesResponse
Inherits Base.Response
''' <summary>
''' Gets the received historic quote data.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Overloads ReadOnly Property Result() As HistQuotesDataChain()
Get
Return TryCast(MyBase.Result, HistQuotesDataChain())
End Get
End Property
Friend Sub New(ByVal info As Base.ConnectionInfo, ByVal result() As HistQuotesDataChain)
MyBase.New(info, result)
End Sub
End Class
End Namespace