Skip to content

Commit

Permalink
refactoring and new function stubs`
Browse files Browse the repository at this point in the history
Removed the distance functions class from the distance method. Added a few new stubs to basicdistanceapproach.
  • Loading branch information
pranavwalia committed Mar 31, 2022
1 parent 1868180 commit 75d4960
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 17 deletions.
5 changes: 5 additions & 0 deletions Brokerage/AbstractBrokerage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'''
This module will serve as an abstract class defining the methods on a brokerage fee structure class
'''
class AbstractBrokerage():
pass
5 changes: 5 additions & 0 deletions Brokerage/InteractiveBrokers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'''
This class will simulate the fee structure associated with interactive brokers
'''
class InteractiveBrokers():
pass
57 changes: 40 additions & 17 deletions PairsTrading/DistanceApproach/BasicDistanceApproach.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
import pandas as pd
from pandas.api.types import is_numeric_dtype
from math import sqrt
from DistanceFunctions import DistanceFunctions



'''
This class stores distance functions that can be passed to the calculate pairs function of the DistanceApproach Class.
'''
class DistanceFunctions():
def __init(self) -> None:
pass
'''
Simple Euclidean Distance
'''
def euclideanDistance(a,b):
return (b-a)**2

'''
This class implements the distance approach to a pairs trading signal in 3 steps:
- Orders and ranks pairs according to some distance metric
- Generates a signal according to a threshold
This class implements the basic distance approach to a pairs trading signal in 3 steps:
- normalizes price data
- Orders proposed pairs according to a distance metric
- Generates a signal according to a deviation threshold
- Outputs a backtest according to a brokerage fee template
'''
class BasicDistanceApproach():

def __init__(self) -> None:
self.pairs = None
self.pairsData = None
self.tradeData = None
self.NotEnoughColumnsException = 'Dataframe is missing columns. Check that you have both securities and date columns'
self.dateTimeException = 'Left-Most Column is not of type datetime64'
self.nonNumericalException = 'Detected non-numerical data-types to the right of date column'
self.signals = None



Expand Down Expand Up @@ -57,7 +53,7 @@ def setPairsData(self, data: pd.DataFrame) -> bool:
- If there are non-numerical data types
Returns true if we can successfully set the pairs data
'''
def setTradeData(self, data: pd.DataFrame) -> bool:
def setSignalData(self, data: pd.DataFrame) -> bool:
if self.isDataWellFormed(data):
self.tradeData = data
return True
Expand All @@ -80,9 +76,36 @@ def isDataWellFormed(data: pd.DataFrame) -> bool:

'''
Generates Pairs:
Returns a dataframe with all the pair names and their distance values
- Build list of all possible pairs
- Sort list according to distance function
- Sets the top n best pairs as the pairs field in the class
Args:
- distanceFunc: a function that measures the distance (see DistanceFunctions.py)
- top: the number of pairs to select from the n best candidates
The pairs field is a list of data frames structured as follows:
Date | Asset_Price1 | Asset_Price2 | Asset_Price1_Normalized | Asset_Price2_Normalized | Normalized_Spread
'''
def generatePairs(self, distanceFunc: DistanceFunctions.__call__, top: int):
pass

'''
Retrieves the stored pairs in the object. Raises an exception if the pairs have not yet been generated.
'''
def getPairs(self):
if self.pairs != None:
return self.pairs
else:
raise Exception('Error: Pairs have not yet been generated.')

'''
Adds a signal column to each data frame within the pairs list (self.pairs).
A signal is in the form of an integer:
1 -> Buy the spread
-1 -> Sell the spread
0 -> Close the position
'''
def generatePairs(self,distanceFunc):
def addTradeSignals():
pass


Expand Down
14 changes: 14 additions & 0 deletions PairsTrading/DistanceApproach/DistanceFunctions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import pandas as pd

'''
This class stores distance functions that can be passed to the calculate pairs function of the DistanceApproach Class.
'''
class DistanceFunctions():
def __init__(self) -> None:
pass
'''
The sum of the squared distances between two securities
'''
def sumSquaredDistance(self, priceSeriesA: pd.Series, priceSeriesB: pd.Series) -> float:
squaredDifferenceSum = ((priceSeriesB-priceSeriesA)**2)
return sum(squaredDifferenceSum)
26 changes: 26 additions & 0 deletions PairsTrading/DistanceApproach/TestDistanceFunctions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from datetime import date, datetime
import unittest
from DistanceFunctions import DistanceFunctions
import pandas as pd
'''
Tests the distance functions
'''
class TestDistanceFunctions(unittest.TestCase):
'''
Tests the sum of squared difference function
'''
def testSumSquaredDifference(self):
d = DistanceFunctions()
exampleDate1 = pd.to_datetime(datetime(2019,1,1))
exampleDate2 = pd.to_datetime(datetime(2019,1,2))
exampleDate3 = pd.to_datetime(datetime(2019,1,3))
exampleDate4 = pd.to_datetime(datetime(2019,1,4))
priceDF = pd.DataFrame({'Date' : [exampleDate1, exampleDate2, exampleDate3, exampleDate4], 'Price1' : [1, 2, 1, 3],'Price2' : [1, 3, 4, 1]})

sumSquares = d.sumSquaredDistance(priceDF["Price1"],priceDF["Price2"])
self.assertEqual(sumSquares,14)


if __name__ == '__main__':
unittest.main()

0 comments on commit 75d4960

Please sign in to comment.